[clang] 7127fd1 - MSABI: Basic mangling for access to member subobjects in a class

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 9 18:09:13 PST 2020


Author: Richard Smith
Date: 2020-12-09T18:08:49-08:00
New Revision: 7127fd1786e607990ada5ade2bf473e6cad68d9d

URL: https://github.com/llvm/llvm-project/commit/7127fd1786e607990ada5ade2bf473e6cad68d9d
DIFF: https://github.com/llvm/llvm-project/commit/7127fd1786e607990ada5ade2bf473e6cad68d9d.diff

LOG: MSABI: Basic mangling for access to member subobjects in a class
non-type template parameter.

The mangling information used here comes from private communication with
Jon Caves at Microsoft.

Added: 
    

Modified: 
    clang/lib/AST/MicrosoftMangle.cpp
    clang/test/CodeGenCXX/mangle-class-nttp.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 1fba1392d0ed..286000faf2a4 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -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,
@@ -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:
@@ -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 
diff erent 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;
   }
@@ -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;
   }
@@ -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;
@@ -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 << '@';
@@ -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 << "@@";
@@ -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");

diff  --git a/clang/test/CodeGenCXX/mangle-class-nttp.cpp b/clang/test/CodeGenCXX/mangle-class-nttp.cpp
index 579afd0a01be..81107c481504 100644
--- a/clang/test/CodeGenCXX/mangle-class-nttp.cpp
+++ b/clang/test/CodeGenCXX/mangle-class-nttp.cpp
@@ -23,12 +23,13 @@ template void f<B{nullptr, 1}>();
 // CHECK: define weak_odr void @_Z1fIXtl1BEEEvv(
 // MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A at 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 at 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
@@ -36,12 +37,14 @@ template void f<B{fold(reinterpret_cast<int*>(0))}>();
 // 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 at 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
@@ -53,15 +56,17 @@ 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
@@ -69,8 +74,10 @@ template void f<BR{fold(*(&derived.b + 3))}>();
 // 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
@@ -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(


        


More information about the cfe-commits mailing list