Skip to content

Commit

Permalink
MSABI: Basic mangling for access to member subobjects in a class
Browse files Browse the repository at this point in the history
non-type template parameter.

The mangling information used here comes from private communication with
Jon Caves at Microsoft.
  • Loading branch information
zygoloid committed Dec 10, 2020
1 parent 9d6177c commit 7127fd1
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 36 deletions.
116 changes: 92 additions & 24 deletions clang/lib/AST/MicrosoftMangle.cpp
Expand Up @@ -394,7 +394,7 @@ class MicrosoftCXXNameMangler {
void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA,
const NamedDecl *Parm);
void mangleTemplateArgValue(QualType T, const APValue &V,
bool WithScalarType = true);
bool WithScalarType = false);

void mangleObjCProtocol(const ObjCProtocolDecl *PD);
void mangleObjCLifetime(const QualType T, Qualifiers Quals,
Expand Down Expand Up @@ -1473,11 +1473,34 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
// ::= <integer-literal>
// ::= <member-data-pointer>
// ::= <member-function-pointer>
// ::= $E? <name> <type-encoding>
// ::= $1? <name> <type-encoding>
// ::= $2 <type> <value> # class NTTP
// ::= $0A@
// ::= $ <constant-value>
// ::= <template-args>
//
// <constant-value> ::= 0 <number> # integer
// ::= 1 <mangled-name> # address of D
// ::= 2 <type> <typed-constant-value>* @ # struct
// ::= 3 <type> <constant-value>* @ # array
// ::= 4 ??? # string
// ::= 5 <constant-value> @ # address of subobject
// ::= 6 <constant-value> <unqualified-name> @ # a.b
// ::= 7 <type> [<unqualified-name> <constant-value>] @
// # union, with or without an active member
// # pointer to member, symbolically
// ::= 8 <class> <unqualified-name> @
// ::= A <type> <non-negative integer> # float
// ::= B <type> <non-negative integer> # double
// ::= E <mangled-name> # reference to D
// # pointer to member, by component value
// ::= F <number> <number>
// ::= G <number> <number> <number>
// ::= H <mangled-name> <number>
// ::= I <mangled-name> <number> <number>
// ::= J <mangled-name> <number> <number> <number>
//
// <typed-constant-value> ::= [<type>] <constant-value>
//
// The <type> appears to be included in a <typed-constant-value> only in the
// '0', '1', '8', 'A', 'B', and 'E' cases.

switch (TA.getKind()) {
case TemplateArgument::Null:
Expand Down Expand Up @@ -1622,22 +1645,66 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
if (WithScalarType)
mangleType(T, SourceRange(), QMM_Escape);

APValue::LValueBase Base = V.getLValueBase();
if (Base.isNull())
Out << "0A@";
else if (auto *VD = Base.dyn_cast<const ValueDecl*>())
mangle(VD, T->isReferenceType() ? "E?" : "1?");
else
// We don't know how to mangle past-the-end pointers yet.
if (V.isLValueOnePastTheEnd())
break;

// FIXME: MSVC doesn't support template arguments referring to subobjects
// yet (it either mangles such template arguments as null pointers or
// small integers or crashes). It's probably the intent to mangle the
// declaration followed by an offset, but that's not what actually happens.
// For now just bail.
if (!V.hasLValuePath() || !V.getLValuePath().empty() ||
V.isLValueOnePastTheEnd())
break;
APValue::LValueBase Base = V.getLValueBase();
if (!V.hasLValuePath() || V.getLValuePath().empty()) {
// Taking the address of a complete object has a special-case mangling.
if (Base.isNull()) {
// MSVC emits 0A@ for null pointers. Generalize this for arbitrary
// integers cast to pointers.
// FIXME: This mangles 0 cast to a pointer the same as a null pointer,
// even in cases where the two are different values.
Out << "0";
mangleNumber(V.getLValueOffset().getQuantity());
} else if (!V.hasLValuePath()) {
// FIXME: This can only happen as an extension. Invent a mangling.
break;
} else if (auto *VD = Base.dyn_cast<const ValueDecl*>()) {
Out << (T->isReferenceType() ? "E" : "1");
mangle(VD);
} else {
break;
}
} else {
unsigned NumAts = 0;
if (T->isPointerType()) {
Out << "5";
++NumAts;
}

QualType T = Base.getType();
for (APValue::LValuePathEntry E : V.getLValuePath()) {
// We don't know how to mangle array subscripting yet.
if (T->isArrayType())
goto mangling_unknown;

const Decl *D = E.getAsBaseOrMember().getPointer();
auto *FD = dyn_cast<FieldDecl>(D);
// We don't know how to mangle derived-to-base conversions yet.
if (!FD)
goto mangling_unknown;

Out << "6";
++NumAts;
T = FD->getType();
}

auto *VD = Base.dyn_cast<const ValueDecl*>();
if (!VD)
break;
Out << "E";
mangle(VD);

for (APValue::LValuePathEntry E : V.getLValuePath()) {
const Decl *D = E.getAsBaseOrMember().getPointer();
mangleUnqualifiedName(cast<FieldDecl>(D));
}
for (unsigned I = 0; I != NumAts; ++I)
Out << '@';
}

return;
}
Expand Down Expand Up @@ -1675,7 +1742,8 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
for (const FieldDecl *FD : RD->fields())
if (!FD->isUnnamedBitfield())
mangleTemplateArgValue(FD->getType(),
V.getStructField(FD->getFieldIndex()));
V.getStructField(FD->getFieldIndex()),
/*WithScalarType*/ true);
Out << '@';
return;
}
Expand All @@ -1685,8 +1753,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
mangleType(T, SourceRange(), QMM_Escape);
if (const FieldDecl *FD = V.getUnionField()) {
mangleUnqualifiedName(FD);
mangleTemplateArgValue(FD->getType(), V.getUnionValue(),
/*WithType*/false);
mangleTemplateArgValue(FD->getType(), V.getUnionValue());
}
Out << '@';
return;
Expand Down Expand Up @@ -1718,7 +1785,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
const APValue &ElemV = I < V.getArrayInitializedElts()
? V.getArrayInitializedElt(I)
: V.getArrayFiller();
mangleTemplateArgValue(ElemT, ElemV, /*WithType*/false);
mangleTemplateArgValue(ElemT, ElemV);
Out << '@';
}
Out << '@';
Expand All @@ -1735,7 +1802,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
mangleType(ElemT, SourceRange(), QMM_Escape);
for (unsigned I = 0, N = V.getVectorLength(); I != N; ++I) {
const APValue &ElemV = V.getVectorElt(I);
mangleTemplateArgValue(ElemT, ElemV, /*WithType*/false);
mangleTemplateArgValue(ElemT, ElemV);
Out << '@';
}
Out << "@@";
Expand All @@ -1747,6 +1814,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
break;
}

mangling_unknown:
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error, "cannot mangle this template argument yet");
Expand Down
29 changes: 17 additions & 12 deletions clang/test/CodeGenCXX/mangle-class-nttp.cpp
Expand Up @@ -23,25 +23,28 @@ template void f<B{nullptr, 1}>();
// CHECK: define weak_odr void @_Z1fIXtl1BEEEvv(
// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H0A@@@@YAXXZ"
template void f<B{nullptr}>();
#ifndef _WIN32
// FIXME: MSVC crashes on the first of these and mangles the second the same as
// the nullptr version. Check the output is correct once we have a reference to
// compare against.
// These are extensions, but they seem like the obvious manglings.
// CHECK: define weak_odr void @_Z1fIXtl1BLPKi32EEEEvv(
// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0CA@H0A@@@@YAXXZ"
template void f<B{fold((int*)32)}>();
#ifndef _WIN32
// FIXME: On MS ABI, we mangle this the same as nullptr, despite considering a
// null pointer and zero bitcast to a pointer to be distinct pointer values.
// CHECK: define weak_odr void @_Z1fIXtl1BrcPKiLi0EEEEvv(
template void f<B{fold(reinterpret_cast<int*>(0))}>();
#endif

// Pointers to subobjects.
struct Nested { union { int k; int arr[2]; }; } nested[2];
struct Derived : A, Nested { int z; } extern derived;
// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z7derivedE16EEEEvv
// MSABI: define {{.*}} void @"??$f@$2UB@@PEBH56E?derived@@3UDerived@@Az@@@H0A@@@@YAXXZ"
template void f<B{&derived.z}>();
// FIXME: We don't know the MS ABI mangling for array subscripting and
// past-the-end pointers yet.
#ifndef _WIN32
// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE_EEEEvv
// FIXME: MSVC generates the garbage mangling ??$f@$2UB@@PEAH0A@H0A@@@@YAXXZ
// for this.
template void f<B{&nested[0].k}>();
// FIXME: MSVC crashes on these.
// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE16_0pEEEEvv
template void f<B{&nested[1].arr[2]}>();
// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z7derivedE8pEEEEvv
Expand All @@ -53,24 +56,28 @@ template void f<B{fold(&derived.b + 3)}>();
// References to subobjects.
struct BR { const int &r; };
template<BR> void f() {}
// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z7derivedE16EEEEvv
// MSABI: define {{.*}} void @"??$f@$2UBR@@AEBH6E?derived@@3UDerived@@Az@@@@@YAXXZ"
template void f<BR{derived.z}>();
// FIXME: We don't know the MS ABI mangling for array subscripting yet.
#ifndef _WIN32
// FIXME: MSVC produces garbage manglings for these.
// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE_EEEEvv
template void f<BR{nested[0].k}>();
// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE12_0EEEEvv
template void f<BR{nested[1].arr[1]}>();
// CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z7derivedE4EEEEvv
template void f<BR{derived.b}>();
// FIXME: Crashes MSVC.
// CHECK: define weak_odr void @_Z1fIXtl2BRdecvPKiplcvPcadL_Z7derivedELl16EEEEvv
template void f<BR{fold(*(&derived.b + 3))}>();
#endif

// Qualification conversions.
struct C { const int *p; };
template<C> void f() {}
// CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE16EEEEvv
// MSABI: define {{.*}} void @"??$f@$2UC@@PEBH56E?derived@@3UDerived@@Az@@@@@@YAXXZ"
template void f<C{&derived.z}>();
#ifndef _WIN32
// FIXME: MSVC produces a garbage mangling for this.
// CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv
template void f<C{&derived.b}>();
#endif
Expand Down Expand Up @@ -118,8 +125,6 @@ template<E> void f() {}

// Union members.
// CHECK: define weak_odr void @_Z1fIXL1EEEEvv(
// FIXME: MSVC rejects this; check this is the mangling MSVC uses when they
// start accepting.
// MSABI: define {{.*}} @"??$f@$7TE@@@@@YAXXZ"
template void f<E{}>();
// CHECK: define weak_odr void @_Z1fIXtl1EEEEvv(
Expand Down

0 comments on commit 7127fd1

Please sign in to comment.