]> granicus.if.org Git - clang/commitdiff
[ms-cxxabi] Use sugared types in the mangler instead of canonical types
authorReid Kleckner <reid@kleckner.net>
Mon, 24 Jun 2013 19:21:52 +0000 (19:21 +0000)
committerReid Kleckner <reid@kleckner.net>
Mon, 24 Jun 2013 19:21:52 +0000 (19:21 +0000)
At this point, it's clear that the MSVC mangler uses the type-as-written
instead of the canonical type, so this should bring us closer to MSVC.
The main thrust of this change is to fix the way we mangle decayed array
parameters of function pointer parameters.  With a DecayedType sugar
node, this code can now be much simpler.

Fixes PR16096.

This also fixes a separate issue that Richard spotted in review.
Because separate declarations of the same entity can be spelled and
mangled differently, MSVC always mangles the earliest declaration in an
attempt to avoid link errors.  Clang now does the same.

Reviewers: rsmith

Differential Revision: http://llvm-reviews.chandlerc.com/D844

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184777 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/MicrosoftMangle.cpp
test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp

index 5e488e042e717f20ea5a473ec29f661f08deb855..e2b42e7e30c41b4927ae5674625bdf8e80de7891 100644 (file)
@@ -125,7 +125,7 @@ private:
   void mangleFunctionType(const FunctionType *T, const FunctionDecl *D,
                           bool IsStructor, bool IsInstMethod);
   void mangleDecayedArrayType(const ArrayType *T, bool IsGlobal);
-  void mangleArrayType(const ArrayType *T, Qualifiers Quals);
+  void mangleArrayType(const ArrayType *T);
   void mangleFunctionClass(const FunctionDecl *FD);
   void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
   void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
@@ -257,13 +257,20 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
 void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
   // <type-encoding> ::= <function-class> <function-type>
 
+  // Since MSVC operates on the type as written and not the canonical type, it
+  // actually matters which decl we have here.  MSVC appears to choose the
+  // first, since it is most likely to be the declaration in a header file.
+  FD = FD->getFirstDeclaration();
+
   // Don't mangle in the type if this isn't a decl we should typically mangle.
   if (!Context.shouldMangleDeclName(FD))
     return;
   
   // We should never ever see a FunctionNoProtoType at this point.
   // We don't even know how to mangle their types anyway :).
-  const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>();
+  TypeSourceInfo *TSI = FD->getTypeSourceInfo();
+  QualType T = TSI ? TSI->getType() : FD->getType();
+  const FunctionProtoType *FT = T->castAs<FunctionProtoType>();
 
   bool InStructor = false, InInstMethod = false;
   const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
@@ -980,17 +987,24 @@ void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) {
 
 void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
                                                  SourceRange Range) {
+  // MSVC will backreference two canonically equivalent types that have slightly
+  // different manglings when mangled alone.
   void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr();
   ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
 
   if (Found == TypeBackReferences.end()) {
     size_t OutSizeBefore = Out.GetNumBytesInBuffer();
 
-    if (const ArrayType *AT = getASTContext().getAsArrayType(T)) {
-      mangleDecayedArrayType(AT, false);
-    } else if (const FunctionType *FT = T->getAs<FunctionType>()) {
-      Out << "P6";
-      mangleFunctionType(FT, 0, false, false);
+    if (const DecayedType *DT = T->getAs<DecayedType>()) {
+      QualType OT = DT->getOriginalType();
+      if (const ArrayType *AT = getASTContext().getAsArrayType(OT)) {
+        mangleDecayedArrayType(AT, false);
+      } else if (const FunctionType *FT = OT->getAs<FunctionType>()) {
+        Out << "P6";
+        mangleFunctionType(FT, 0, false, false);
+      } else {
+        llvm_unreachable("unexpected decayed type");
+      }
     } else {
       mangleType(T, Range, QMM_Drop);
     }
@@ -1010,16 +1024,18 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
 
 void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
                                          QualifierMangleMode QMM) {
-  // Only operate on the canonical type!
-  T = getASTContext().getCanonicalType(T);
+  // Don't use the canonical types.  MSVC includes things like 'const' on
+  // pointer arguments to function pointers that canonicalization strips away.
+  T = T.getDesugaredType(getASTContext());
   Qualifiers Quals = T.getLocalQualifiers();
-
-  if (const ArrayType *AT = dyn_cast<ArrayType>(T)) {
+  if (const ArrayType *AT = getASTContext().getAsArrayType(T)) {
+    // If there were any Quals, getAsArrayType() pushed them onto the array
+    // element type.
     if (QMM == QMM_Mangle)
       Out << 'A';
     else if (QMM == QMM_Escape || QMM == QMM_Result)
       Out << "$$B";
-    mangleArrayType(AT, Quals);
+    mangleArrayType(AT);
     return;
   }
 
@@ -1180,6 +1196,9 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
   //                     <return-type> <argument-list> <throw-spec>
   const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
 
+  SourceRange Range;
+  if (D) Range = D->getSourceRange();
+
   // If this is a C++ instance method, mangle the CVR qualifiers for the
   // this pointer.
   if (IsInstMethod)
@@ -1201,7 +1220,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
     }
     Out << '@';
   } else {
-    mangleType(Proto->getResultType(), SourceRange(), QMM_Result);
+    mangleType(Proto->getResultType(), Range, QMM_Result);
   }
 
   // <argument-list> ::= X # void
@@ -1210,23 +1229,11 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
   if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
     Out << 'X';
   } else {
-    if (D) {
-      // If we got a decl, use the type-as-written to make sure arrays
-      // get mangled right.  Note that we can't rely on the TSI
-      // existing if (for example) the parameter was synthesized.
-      for (FunctionDecl::param_const_iterator Parm = D->param_begin(),
-             ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) {
-        TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo();
-        QualType Type = TSI ? TSI->getType() : (*Parm)->getType();
-        mangleArgumentType(Type, (*Parm)->getSourceRange());
-      }
-    } else {
-      // Happens for function pointer type arguments for example.
-      for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
-           ArgEnd = Proto->arg_type_end();
-           Arg != ArgEnd; ++Arg)
-        mangleArgumentType(*Arg, SourceRange());
-    }
+    // Happens for function pointer type arguments for example.
+    for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+         ArgEnd = Proto->arg_type_end();
+         Arg != ArgEnd; ++Arg)
+      mangleArgumentType(*Arg, Range);
     // <builtin-type>      ::= Z  # ellipsis
     if (Proto->isVariadic())
       Out << 'Z';
@@ -1431,8 +1438,7 @@ void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T,
                                          SourceRange) {
   llvm_unreachable("Should have been special cased");
 }
-void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T,
-                                              Qualifiers Quals) {
+void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
   QualType ElementTy(T, 0);
   SmallVector<llvm::APInt, 3> Dimensions;
   for (;;) {
@@ -1471,8 +1477,7 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T,
   mangleNumber(Dimensions.size());
   for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim)
     mangleNumber(Dimensions[Dim].getLimitedValue());
-  mangleType(getASTContext().getQualifiedType(ElementTy.getTypePtr(), Quals),
-             SourceRange(), QMM_Escape);
+  mangleType(ElementTy, SourceRange(), QMM_Escape);
 }
 
 // <type>                   ::= <pointer-to-member-type>
index ed7027d975ddc63e5e7b1ff4606915c747468257..672a48641ca0874017fa9212e9af2f286bde3638 100644 (file)
@@ -162,3 +162,45 @@ void foo_volatile(volatile Vector) {}
 void foo(Vector*, const Vector, const double) {}
 // CHECK: "\01?foo@@YAXPAY02NQBNN@Z"
 // X64: "\01?foo@@YAXPEAY02NQEBNN@Z"
+
+typedef void (*ConstFunPtr)(int *const d);
+void foo_fnptrconst(ConstFunPtr f) {  }
+// CHECK: "\01?foo_fnptrconst@@YAXP6AXQAH@Z@Z"
+// X64:   "\01?foo_fnptrconst@@YAXP6AXQEAH@Z@Z"
+
+typedef void (*ArrayFunPtr)(int d[1]);
+void foo_fnptrarray(ArrayFunPtr f) {  }
+// CHECK: "\01?foo_fnptrarray@@YAXP6AXQAH@Z@Z"
+// X64:   "\01?foo_fnptrarray@@YAXP6AXQEAH@Z@Z"
+
+void foo_fnptrbackref1(ArrayFunPtr f1, ArrayFunPtr f2) {  }
+// CHECK: "\01?foo_fnptrbackref1@@YAXP6AXQAH@Z1@Z"
+// X64:   "\01?foo_fnptrbackref1@@YAXP6AXQEAH@Z1@Z"
+
+void foo_fnptrbackref2(ArrayFunPtr f1, ConstFunPtr f2) {  }
+// CHECK: "\01?foo_fnptrbackref2@@YAXP6AXQAH@Z1@Z"
+// X64:   "\01?foo_fnptrbackref2@@YAXP6AXQEAH@Z1@Z"
+
+typedef void (*NormalFunPtr)(int *d);
+void foo_fnptrbackref3(ArrayFunPtr f1, NormalFunPtr f2) {  }
+// CHECK: "\01?foo_fnptrbackref3@@YAXP6AXQAH@Z1@Z"
+// X64:   "\01?foo_fnptrbackref3@@YAXP6AXQEAH@Z1@Z"
+
+void foo_fnptrbackref4(NormalFunPtr f1, ArrayFunPtr f2) {  }
+// CHECK: "\01?foo_fnptrbackref4@@YAXP6AXPAH@Z1@Z"
+// X64:   "\01?foo_fnptrbackref4@@YAXP6AXPEAH@Z1@Z"
+
+ArrayFunPtr ret_fnptrarray() { return 0; }
+// CHECK: "\01?ret_fnptrarray@@YAP6AXQAH@ZXZ"
+// X64:   "\01?ret_fnptrarray@@YAP6AXQEAH@ZXZ"
+
+// Test that we mangle the forward decl when we have a redeclaration with a
+// slightly different type.
+void mangle_fwd(char * const x);
+void mangle_fwd(char * x) {}
+// CHECK: "\01?mangle_fwd@@YAXQAD@Z"
+// X64:   "\01?mangle_fwd@@YAXQEAD@Z"
+
+void mangle_no_fwd(char * x) {}
+// CHECK: "\01?mangle_no_fwd@@YAXPAD@Z"
+// X64:   "\01?mangle_no_fwd@@YAXPEAD@Z"