Hi pcc, rnk, cdavis5x, timurrrr, whunt,

Main and extern "C" functions are very special.  main in particular has
a unique mangling regardless of how it is phrased:
(int main(void), int main(int, char * []), int main(int, char **)) all
are mangled the same when in contexts that aren't "bare-function"

extern "C" functions don't get their parameter or return types mangled.

Furthermore, declaration mangling for extern "C" functions in template
arguments works out completely differently.

To get this much right, the logic behind working out which declarations
needed "C++" mangling had to be reworked.

Note, this *still* doesn't catch all of the corner cases...

http://llvm-reviews.chandlerc.com/D1627

Files:
  lib/AST/MicrosoftMangle.cpp
  test/CodeGenCXX/mangle-ms-extern-local.cpp
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -29,6 +29,40 @@
 
 namespace {
 
+/// \brief Retrieve the declaration context that should be used when mangling 
+/// the given declaration.
+static const DeclContext *getEffectiveDeclContext(const Decl *D) {
+  // The ABI assumes that lambda closure types that occur within
+  // default arguments live in the context of the function. However, due to
+  // the way in which Clang parses and creates function declarations, this is
+  // not the case: the lambda closure type ends up living in the context
+  // where the function itself resides, because the function declaration itself
+  // had not yet been created. Fix the context here.
+  if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+    if (RD->isLambda())
+      if (ParmVarDecl *ContextParam =
+              dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
+        return ContextParam->getDeclContext();
+  }
+
+  // Perform the same check for block literals.
+  if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+    if (ParmVarDecl *ContextParam =
+            dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl()))
+      return ContextParam->getDeclContext();
+  }
+
+  const DeclContext *DC = D->getDeclContext();
+  if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC))
+    return getEffectiveDeclContext(CD);
+
+  return DC;
+}
+
+static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
+  return getEffectiveDeclContext(cast<Decl>(DC));
+}
+
 static const FunctionDecl *getStructor(const FunctionDecl *fn) {
   if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
     return ftd->getTemplatedDecl();
@@ -81,10 +115,11 @@
 
   raw_ostream &getStream() const { return Out; }
 
-  void mangle(const NamedDecl *D, StringRef Prefix = "\01?");
+  void mangle(const NamedDecl *D, StringRef Prefix = "\01?",
+              bool IsForTemplateArg = false);
   void mangleName(const NamedDecl *ND);
   void mangleDeclaration(const NamedDecl *ND);
-  void mangleFunctionEncoding(const FunctionDecl *FD);
+  void mangleFunctionEncoding(const FunctionDecl *FD, bool IsForTemplateArg);
   void mangleVariableEncoding(const VarDecl *VD);
   void mangleNumber(int64_t Number);
   void mangleNumber(const llvm::APSInt &Value);
@@ -100,7 +135,7 @@
   }
   void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name);
   void mangleSourceName(const IdentifierInfo *II);
-  void manglePostfix(const DeclContext *DC, bool NoFunction=false);
+  void manglePostfix(const DeclContext *DC, bool NoFunction = false);
   void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
   void mangleCXXDtorType(CXXDtorType T);
   void mangleQualifiers(Qualifiers Quals, bool IsMember);
@@ -135,15 +170,15 @@
 
   void mangleTemplateArgs(const TemplateDecl *TD,
                           const TemplateArgumentList &TemplateArgs);
-  void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA);
+  void mangleTemplateArg(const TemplateArgument &TA);
 };
 
 /// MicrosoftMangleContext - Overrides the default MangleContext for the
 /// Microsoft Visual C++ ABI.
 class MicrosoftMangleContext : public MangleContext {
 public:
-  MicrosoftMangleContext(ASTContext &Context,
-                   DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { }
+  MicrosoftMangleContext(ASTContext &Context, DiagnosticsEngine &Diags)
+      : MangleContext(Context, Diags) {}
   virtual bool shouldMangleDeclName(const NamedDecl *D);
   virtual void mangleName(const NamedDecl *D, raw_ostream &Out);
   virtual void mangleThunk(const CXXMethodDecl *MD,
@@ -174,17 +209,6 @@
 
 }
 
-static bool isInCLinkageSpecification(const Decl *D) {
-  D = D->getCanonicalDecl();
-  for (const DeclContext *DC = D->getDeclContext();
-       !DC->isTranslationUnit(); DC = DC->getParent()) {
-    if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
-      return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
-  }
-
-  return false;
-}
-
 bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) {
   // In C, functions with no attributes never need to be mangled. Fastpath them.
   if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
@@ -195,34 +219,53 @@
   if (D->hasAttr<AsmLabelAttr>())
     return true;
 
-  // Clang's "overloadable" attribute extension to C/C++ implies name mangling
-  // (always) as does passing a C++ member function and a function
-  // whose name is not a simple identifier.
   const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
-  if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
-             !FD->getDeclName().isIdentifier()))
-    return true;
+  if (FD) {
+    LanguageLinkage L = FD->getLanguageLinkage();
+    // Overloadable functions need mangling.
+    if (FD->hasAttr<OverloadableAttr>())
+      return true;
+
+    // "main" is not mangled.
+    if (FD->isMain())
+      return false;
+
+    // C++ functions and those whose names are not a simple identifier need
+    // mangling.
+    if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage)
+      return true;
+
+    // C functions are not mangled.
+    if (L == CLanguageLinkage)
+      return false;
+  }
 
   // Otherwise, no mangling is done outside C++ mode.
   if (!getASTContext().getLangOpts().CPlusPlus)
     return false;
 
-  // Variables at global scope with internal linkage are not mangled.
-  if (!FD) {
-    const DeclContext *DC = D->getDeclContext();
-    if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage)
+  const VarDecl *VD = dyn_cast<VarDecl>(D);
+  if (VD) {
+    // C variables are not mangled.
+    if (VD->isExternC())
       return false;
-  }
 
-  // C functions and "main" are not mangled.
-  if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
-    return false;
+    // Variables at global scope with internal linkage are not mangled
+    const DeclContext *DC = getEffectiveDeclContext(D);
+    // Check for extern variable declared locally.
+    if (DC->isFunctionOrMethod() && D->hasLinkage())
+      while (!DC->isNamespace() && !DC->isTranslationUnit())
+        DC = getEffectiveParentContext(DC);
+    if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage &&
+        !isa<VarTemplateSpecializationDecl>(D))
+      return false;
+  }
 
   return true;
 }
 
-void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
-                                     StringRef Prefix) {
+void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix,
+                                     bool IsForTemplateArg) {
   // MSVC doesn't mangle C++ names the same way it mangles extern "C" names.
   // Therefore it's really important that we don't decorate the
   // name with leading underscores or leading/trailing at signs. So, by
@@ -237,11 +280,17 @@
     return;
   }
 
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+    if (FD->isMain()) {
+      Out << "$1main";
+      return;
+    }
+
   // <mangled-name> ::= ? <name> <type-encoding>
   Out << Prefix;
   mangleName(D);
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
-    mangleFunctionEncoding(FD);
+    mangleFunctionEncoding(FD, IsForTemplateArg);
   else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
     mangleVariableEncoding(VD);
   else {
@@ -255,18 +304,15 @@
   }
 }
 
-void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
+void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD,
+                                                     bool IsForTemplateArg) {
   // <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 :).
   TypeSourceInfo *TSI = FD->getTypeSourceInfo();
@@ -282,10 +328,14 @@
       InStructor = true;
   }
 
-  // First, the function class.
-  mangleFunctionClass(FD);
-
-  mangleFunctionType(FT, FD, InStructor, InInstMethod);
+  // extern "C" functions can hold entities that must be mangled.
+  // As it stands, these functions still need to get expressed in the full
+  // external name.  They have their class and type omitted, replaced with '9'.
+  if (IsForTemplateArg || Context.shouldMangleDeclName(FD)) {
+    mangleFunctionClass(FD);
+    mangleFunctionType(FT, FD, InStructor, InInstMethod);
+  } else
+    Out << '9';
 }
 
 void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
@@ -347,7 +397,7 @@
   const DeclContext *DC = ND->getDeclContext();
 
   // Always start with the unqualified name.
-  mangleUnqualifiedName(ND);    
+  mangleUnqualifiedName(ND);
 
   // If this is an extern variable declared locally, the relevant DeclContext
   // is that of the containing namespace, or the translation unit.
@@ -895,20 +945,17 @@
     << E->getStmtClassName() << E->getSourceRange();
 }
 
-void
-MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD,
-                                     const TemplateArgumentList &TemplateArgs) {
+void MicrosoftCXXNameMangler::mangleTemplateArgs(
+    const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) {
   // <template-args> ::= {<type> | <integer-literal>}+ @
   unsigned NumTemplateArgs = TemplateArgs.size();
-  for (unsigned i = 0; i < NumTemplateArgs; ++i) {
-    const TemplateArgument &TA = TemplateArgs[i];
-    mangleTemplateArg(TD, TA);
-  }
+  for (unsigned i = 0; i < NumTemplateArgs; ++i)
+    mangleTemplateArg(TemplateArgs[i]);
+
   Out << '@';
 }
 
-void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
-                                                const TemplateArgument &TA) {
+void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateArgument &TA) {
   switch (TA.getKind()) {
   case TemplateArgument::Null:
     llvm_unreachable("Can't mangle null template arguments!");
@@ -921,7 +968,8 @@
   }
   case TemplateArgument::Declaration: {
     const NamedDecl *ND = cast<NamedDecl>(TA.getAsDecl());
-    mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?");
+    mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?",
+           /*IsForTemplateArg=*/true);
     break;
   }
   case TemplateArgument::Integral:
@@ -938,7 +986,7 @@
     // Unlike Itanium, there is no character code to indicate an argument pack.
     for (TemplateArgument::pack_iterator I = TA.pack_begin(), E = TA.pack_end();
          I != E; ++I)
-      mangleTemplateArg(TD, *I);
+      mangleTemplateArg(*I);
     break;
   case TemplateArgument::Template:
     mangleType(cast<TagDecl>(
Index: test/CodeGenCXX/mangle-ms-extern-local.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/mangle-ms-extern-local.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+// CHECK: @"\01?a@test1@@3U?$x@$1?fun1@test1@@YAXXZ@1@A"
+// CHECK: @"\01?a@test2@@3U?$x@$1main@1@A"
+// CHECK: @"\01?g@?1??fun0@@9@4HA"
+
+extern "C" inline int *fun0() {
+  static int g;
+  return &g;
+}
+// CHECK: @"\01?h@@YAPAHXZ"
+int *h() { return fun0(); }
+
+// CHECK: define linkonce_odr i32* @fun0()
+
+namespace test1 {
+template <void (*)()> struct x {};
+
+extern "C" inline void fun1() {}
+
+x<fun1> a;
+}
+
+// CHECK: define i32 @main(i32 %argc, i8** %argv)
+int main(int argc, char *argv[]) {}
+
+namespace test2 {
+template <int (*)(int, char * [])> struct x {};
+
+x<main> a;
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to