]> granicus.if.org Git - clang/commitdiff
More local mangling fixes.
authorEli Friedman <eli.friedman@gmail.com>
Wed, 10 Jul 2013 00:30:46 +0000 (00:30 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Wed, 10 Jul 2013 00:30:46 +0000 (00:30 +0000)
Compute mangling numbers for externally visible local variables and tags.
Change the mangler to consistently use discriminators where necessary.
Tweak the scheme we use to number decls which are not externally visible
to avoid unnecessary discriminators in common cases now that we request
them more consistently.

Fixes <rdar://problem/14204721>.

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

include/clang/AST/ASTContext.h
include/clang/AST/MangleNumberingContext.h
include/clang/Sema/Sema.h
lib/AST/ASTContext.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/MangleNumberingContext.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaLambda.cpp
test/CodeGenCXX/linkage.cpp
test/CodeGenCXX/mangle-local-class-names.cpp
test/CodeGenCXX/mangle.cpp

index 7c2cea25cceba7fc056dcdf3f0b2a53f6515c2fd..f0b0e41bd0f305202755eb15f48ce1505a95042c 100644 (file)
@@ -344,8 +344,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
   llvm::DenseMap<const DeclContext *, MangleNumberingContext>
       MangleNumberingContexts;
 
-  llvm::DenseMap<const DeclContext *, unsigned> UnnamedMangleContexts;
-  llvm::DenseMap<const TagDecl *, unsigned> UnnamedMangleNumbers;
+  /// \brief Side-table of mangling numbers for declarations which rarely
+  /// need them (like static local vars).
+  llvm::DenseMap<const NamedDecl *, unsigned> MangleNumbers;
 
   /// \brief Mapping that stores parameterIndex values for ParmVarDecls when
   /// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
@@ -2086,12 +2087,12 @@ public:
   /// it is not used.
   bool DeclMustBeEmitted(const Decl *D);
 
-  void addUnnamedTag(const TagDecl *Tag);
-  int getUnnamedTagManglingNumber(const TagDecl *Tag) const;
+  void setManglingNumber(const NamedDecl *ND, unsigned Number);
+  unsigned getManglingNumber(const NamedDecl *ND) const;
 
   /// \brief Retrieve the context for computing mangling numbers in the given
   /// DeclContext.
-  MangleNumberingContext &getManglingNumberContext(DeclContext *DC);
+  MangleNumberingContext &getManglingNumberContext(const DeclContext *DC);
 
   /// \brief Used by ParmVarDecl to store on the side the
   /// index of the parameter when it exceeds the size of the normal bitfield.
index 35c2abd9d8469a10c7d558ebb4523693aeb1dc0b..4f81e0c554856bd9db3889fe97d7992e201a52c6 100644 (file)
@@ -23,22 +23,35 @@ namespace clang {
 
 class BlockDecl;
 class CXXMethodDecl;
+class IdentifierInfo;
+class TagDecl;
 class Type;
+class VarDecl;
 
 /// \brief Keeps track of the mangled names of lambda expressions and block
 /// literals within a particular context.
 class MangleNumberingContext 
     : public RefCountedBase<MangleNumberingContext> {
   llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
-  
+  llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers;
+  llvm::DenseMap<IdentifierInfo*, unsigned> TagManglingNumbers;
+
 public:
   /// \brief Retrieve the mangling number of a new lambda expression with the
   /// given call operator within this context.
-  unsigned getManglingNumber(CXXMethodDecl *CallOperator);
+  unsigned getManglingNumber(const CXXMethodDecl *CallOperator);
 
   /// \brief Retrieve the mangling number of a new block literal within this
   /// context.
-  unsigned getManglingNumber(BlockDecl *BD);
+  unsigned getManglingNumber(const BlockDecl *BD);
+
+  /// \brief Retrieve the mangling number of a static local variable within
+  /// this context.
+  unsigned getManglingNumber(const VarDecl *VD);
+
+  /// \brief Retrieve the mangling number of a static local variable within
+  /// this context.
+  unsigned getManglingNumber(const TagDecl *TD);
 };
   
 } // end namespace clang
index 1d780def42d61781d1783608b95c51d2a73ee477..6345989f16089d949c69bc2a9750ff588ccafc11 100644 (file)
@@ -716,7 +716,7 @@ public:
   /// \param[out] ManglingContextDecl - Returns the ManglingContextDecl
   /// associated with the context, if relevant.
   MangleNumberingContext *getCurrentMangleNumberContext(
-    DeclContext *DC,
+    const DeclContext *DC,
     Decl *&ManglingContextDecl);
 
 
index 7f02f59c6833df94f4be0b625335a37f28994083..933e5e057ee93c03c60fe19c2e0e0fb58b027d7d 100644 (file)
@@ -7990,24 +7990,19 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
     + llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
 }
 
-void ASTContext::addUnnamedTag(const TagDecl *Tag) {
-  // FIXME: This mangling should be applied to function local classes too
-  if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() ||
-      !isa<CXXRecordDecl>(Tag->getParent()))
-    return;
-
-  std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P =
-    UnnamedMangleContexts.insert(std::make_pair(Tag->getParent(), 0));
-  UnnamedMangleNumbers.insert(std::make_pair(Tag, P.first->second++));
+void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) {
+  if (Number > 1)
+    MangleNumbers[ND] = Number;
 }
 
-int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const {
-  llvm::DenseMap<const TagDecl *, unsigned>::const_iterator I =
-    UnnamedMangleNumbers.find(Tag);
-  return I != UnnamedMangleNumbers.end() ? I->second : -1;
+unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const {
+  llvm::DenseMap<const NamedDecl *, unsigned>::const_iterator I =
+    MangleNumbers.find(ND);
+  return I != MangleNumbers.end() ? I->second : 1;
 }
 
-MangleNumberingContext &ASTContext::getManglingNumberContext(DeclContext *DC) {
+MangleNumberingContext &
+ASTContext::getManglingNumberContext(const DeclContext *DC) {
   return MangleNumberingContexts[DC];
 }
 
index 79219825aae7a2346b37bc77802678164433bb0a..2dc44eb35559613182241949de4b709749212b47 100644 (file)
@@ -99,7 +99,8 @@ static const unsigned UnknownArity = ~0U;
 
 class ItaniumMangleContext : public MangleContext {
   llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
-  unsigned Discriminator;
+  typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy;
+  llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
   llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
   
 public:
@@ -114,11 +115,6 @@ public:
     return Result.first->second;
   }
 
-  void startNewFunction() {
-    MangleContext::startNewFunction();
-    mangleInitDiscriminator();
-  }
-
   /// @name Mangler Entry Points
   /// @{
 
@@ -153,21 +149,33 @@ public:
   void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &);
   void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &);
 
-  void mangleInitDiscriminator() {
-    Discriminator = 0;
-  }
-
   bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
-    // Lambda closure types with external linkage (indicated by a 
-    // non-zero lambda mangling number) have their own numbering scheme, so
-    // they do not need a discriminator.
+    // Lambda closure types are already numbered.
     if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND))
-      if (RD->isLambda() && RD->getLambdaManglingNumber() > 0)
+      if (RD->isLambda())
         return false;
-        
+
+    // Anonymous tags are already numbered.
+    if (const TagDecl *Tag = dyn_cast<TagDecl>(ND)) {
+      if (Tag->getName().empty() && !Tag->getTypedefNameForAnonDecl())
+        return false;
+    }
+
+    // Use the canonical number for externally visible decls.
+    if (ND->isExternallyVisible()) {
+      unsigned discriminator = getASTContext().getManglingNumber(ND);
+      if (discriminator == 1)
+        return false;
+      disc = discriminator - 2;
+      return true;
+    }
+
+    // Make up a reasonable number for internal decls.
     unsigned &discriminator = Uniquifier[ND];
-    if (!discriminator)
-      discriminator = ++Discriminator;
+    if (!discriminator) {
+      const DeclContext *DC = getEffectiveDeclContext(ND);
+      discriminator = ++Discriminator[std::make_pair(DC, ND->getIdentifier())];
+    }
     if (discriminator == 1)
       return false;
     disc = discriminator-2;
@@ -1141,11 +1149,11 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
       }
     }
 
-    int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD);
-    if (UnnamedMangle != -1) {
+    if (TD->isExternallyVisible()) {
+      unsigned UnnamedMangle = getASTContext().getManglingNumber(TD);
       Out << "Ut";
-      if (UnnamedMangle != 0)
-        Out << llvm::utostr(UnnamedMangle - 1);
+      if (UnnamedMangle > 1)
+        Out << llvm::utostr(UnnamedMangle - 2);
       Out << '_';
       break;
     }
@@ -1300,7 +1308,6 @@ void CXXNameMangler::mangleLocalName(const Decl *D) {
     // <entity name> will of course contain a <closure-type-name>: Its 
     // numbering will be local to the particular argument in which it appears
     // -- other default arguments do not affect its encoding.
-    bool SkipDiscriminator = false;
     const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD);
     if (CXXRD->isLambda()) {
       if (const ParmVarDecl *Parm
@@ -1312,7 +1319,6 @@ void CXXNameMangler::mangleLocalName(const Decl *D) {
           if (Num > 1)
             mangleNumber(Num - 2);
           Out << '_';
-          SkipDiscriminator = true;
         }
       }
     }
@@ -1328,24 +1334,21 @@ void CXXNameMangler::mangleLocalName(const Decl *D) {
       const NamedDecl *ND = cast<NamedDecl>(D);
       mangleNestedName(ND, getEffectiveDeclContext(ND), true /*NoFunction*/);
     }
-
-    if (!SkipDiscriminator) {
-      unsigned disc;
-      if (Context.getNextDiscriminator(RD, disc)) {
-        if (disc < 10)
-          Out << '_' << disc;
-        else
-          Out << "__" << disc << '_';
-      }
+  } else {
+    if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
+      mangleUnqualifiedBlock(BD);
+    else
+      mangleUnqualifiedName(cast<NamedDecl>(D));
+  }
+  if (const NamedDecl *ND = dyn_cast<NamedDecl>(RD ? RD : D)) {
+    unsigned disc;
+    if (Context.getNextDiscriminator(ND, disc)) {
+      if (disc < 10)
+        Out << '_' << disc;
+      else
+        Out << "__" << disc << '_';
     }
-    
-    return;
   }
-
-  if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
-    mangleUnqualifiedBlock(BD);
-  else
-    mangleUnqualifiedName(cast<NamedDecl>(D));
 }
 
 void CXXNameMangler::mangleBlockForPrefix(const BlockDecl *Block) {
index a4c8a27da5c55c0f03c1d5b4f18f13b96ad84e55..4e9006ec24a89a5ca7c39e320de7e948ad663580 100644 (file)
@@ -19,7 +19,7 @@
 using namespace clang;
 
 unsigned
-MangleNumberingContext::getManglingNumber(CXXMethodDecl *CallOperator) {
+MangleNumberingContext::getManglingNumber(const CXXMethodDecl *CallOperator) {
   const FunctionProtoType *Proto
     = CallOperator->getType()->getAs<FunctionProtoType>();
   ASTContext &Context = CallOperator->getASTContext();
@@ -31,8 +31,18 @@ MangleNumberingContext::getManglingNumber(CXXMethodDecl *CallOperator) {
 }
 
 unsigned
-MangleNumberingContext::getManglingNumber(BlockDecl *BD) {
+MangleNumberingContext::getManglingNumber(const BlockDecl *BD) {
   // FIXME: Compute a BlockPointerType?  Not obvious how.
   const Type *Ty = 0;
   return ++ManglingNumbers[Ty];
 }
+
+unsigned
+MangleNumberingContext::getManglingNumber(const VarDecl *VD) {
+  return ++VarManglingNumbers[VD->getIdentifier()];
+}
+
+unsigned
+MangleNumberingContext::getManglingNumber(const TagDecl *TD) {
+  return ++TagManglingNumbers[TD->getIdentifier()];
+}
index 3f85de5d2c12c8d077268682e2c4bb0a98a04d86..5e535da19a1464e01a4f68ee42bd4bad90a62983 100644 (file)
@@ -3043,6 +3043,27 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
   return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg());
 }
 
+static void HandleTagNumbering(Sema &S, const TagDecl *Tag) {
+  if (isa<CXXRecordDecl>(Tag->getParent())) {
+    // If this tag is the direct child of a class, number it if
+    // it is anonymous.
+    if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl())
+      return;
+    MangleNumberingContext &MCtx =
+        S.Context.getManglingNumberContext(Tag->getParent());
+    S.Context.setManglingNumber(Tag, MCtx.getManglingNumber(Tag));
+    return;
+  }
+
+  // If this tag isn't a direct child of a class, number it if it is local.
+  Decl *ManglingContextDecl;
+  if (MangleNumberingContext *MCtx =
+          S.getCurrentMangleNumberContext(Tag->getDeclContext(),
+                                          ManglingContextDecl)) {
+    S.Context.setManglingNumber(Tag, MCtx->getManglingNumber(Tag));
+  }
+}
+
 /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
 /// no declarator (e.g. "struct foo;") is parsed. It also accepts template
 /// parameters to cope with template friend declarations.
@@ -3072,7 +3093,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
   }
 
   if (Tag) {
-    getASTContext().addUnnamedTag(Tag);
+    HandleTagNumbering(*this, Tag);
     Tag->setFreeStanding();
     if (Tag->isInvalidDecl())
       return Tag;
@@ -5120,6 +5141,15 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
       isIncompleteDeclExternC(*this, NewVD))
     RegisterLocallyScopedExternCDecl(NewVD, S);
 
+  if (NewVD->isStaticLocal()) {
+    Decl *ManglingContextDecl;
+    if (MangleNumberingContext *MCtx =
+            getCurrentMangleNumberContext(NewVD->getDeclContext(),
+                                          ManglingContextDecl)) {
+      Context.setManglingNumber(NewVD, MCtx->getManglingNumber(NewVD));
+    }
+  }
+
   return NewVD;
 }
 
@@ -8374,9 +8404,10 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
     if (Decl *D = Group[i])
       Decls.push_back(D);
 
-  if (DeclSpec::isDeclRep(DS.getTypeSpecType()))
+  if (DeclSpec::isDeclRep(DS.getTypeSpecType())) {
     if (const TagDecl *Tag = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl()))
-      getASTContext().addUnnamedTag(Tag);
+      HandleTagNumbering(*this, Tag);
+  }
 
   return BuildDeclaratorGroup(Decls, DS.containsPlaceholderType());
 }
index 1e6ef9baf70e07cab58eef7d4ea27aae874f2d80..8351ff27869d221621f6214a6ec5436151891225 100644 (file)
@@ -53,7 +53,7 @@ static bool isInInlineFunction(const DeclContext *DC) {
 }
 
 MangleNumberingContext *
-Sema::getCurrentMangleNumberContext(DeclContext *DC,
+Sema::getCurrentMangleNumberContext(const DeclContext *DC,
                                     Decl *&ManglingContextDecl) {
   // Compute the context for allocating mangling numbers in the current
   // expression, if the ABI requires them.
index 4aba1b32822df3a0844433ce85528017c0912b4f..cc4e0909c2134280ba5cd11ad7fc4170905cb40e 100644 (file)
@@ -12,7 +12,7 @@ namespace test1 {
 }
 
 namespace test2 {
-  // CHECK-DAG: define internal void @_ZN5test21fIZNS_L1gEvE1S_0EEvT_(
+  // CHECK-DAG: define internal void @_ZN5test21fIZNS_L1gEvE1SEEvT_(
   template <typename T> void f(T) {}
   static inline void *g() {
     struct S {
@@ -46,7 +46,7 @@ namespace test4 {
 }
 
 namespace test5 {
-  // CHECK-DAG: define linkonce_odr void @_ZN5test51fIZNS_1gILi1EEEPvvE1S_1EEvT_(
+  // CHECK-DAG: define linkonce_odr void @_ZN5test51fIZNS_1gILi1EEEPvvE1SEEvT_(
   template <typename T> void f(T) {}
   template <int N> inline void *g() {
     struct S {
@@ -58,7 +58,7 @@ namespace test5 {
 }
 
 namespace test6 {
-  // CHECK-DAG: define linkonce_odr void @_ZN5test61fIZZNS_1gEvEN1S1hE_2vE1T_3EEvv(
+  // CHECK-DAG: define linkonce_odr void @_ZN5test61fIZZNS_1gEvEN1S1hEvE1TEEvv(
   template <typename T> void f() {}
 
   inline void *g() {
@@ -76,7 +76,7 @@ namespace test6 {
 }
 
 namespace test7 {
-  // CHECK-DAG: define internal void @_ZN5test71fIZZNS_1gEvEN1S1hEvE1T_4EEvv(
+  // CHECK-DAG: define internal void @_ZN5test71fIZZNS_1gEvEN1S1hEvE1TEEvv(
   template <typename T> void f() {}
 
   void *g() {
@@ -105,7 +105,7 @@ namespace test8 {
 }
 
 namespace test9 {
-  // CHECK-DAG: define linkonce_odr void @_ZN5test91fIPZNS_1gEvE1S_5EEvT_(
+  // CHECK-DAG: define linkonce_odr void @_ZN5test91fIPZNS_1gEvE1SEEvT_(
   template <typename T> void f(T) {}
   inline void *g() {
     struct S {
@@ -116,7 +116,7 @@ namespace test9 {
 }
 
 namespace test10 {
-  // CHECK-DAG: define linkonce_odr void @_ZN6test101fIPFZNS_1gEvE1S_6vEEEvT_(
+  // CHECK-DAG: define linkonce_odr void @_ZN6test101fIPFZNS_1gEvE1SvEEEvT_(
   template <typename T> void f(T) {}
   inline void *g() {
     struct S {
@@ -128,7 +128,7 @@ namespace test10 {
 }
 
 namespace test11 {
-  // CHECK-DAG: define internal void @_ZN6test111fIPFZNS_1gEvE1S_7PNS_12_GLOBAL__N_11IEEEEvT_(
+  // CHECK-DAG: define internal void @_ZN6test111fIPFZNS_1gEvE1SPNS_12_GLOBAL__N_11IEEEEvT_(
   namespace {
     struct I {
     };
@@ -172,7 +172,7 @@ namespace test13 {
 }
 
 namespace test14 {
-  // CHECK-DAG: define linkonce_odr void @_ZN6test143fooIZNS_1fEvE1S_8E3barILPS1_0EEEvv(
+  // CHECK-DAG: define linkonce_odr void @_ZN6test143fooIZNS_1fEvE1SE3barILPS1_0EEEvv(
   template <typename T> struct foo {
     template <T *P> static void bar() {}
     static void *g() { return (void *)bar<nullptr>; }
@@ -186,7 +186,7 @@ namespace test14 {
 }
 
 namespace test15 {
-  // CHECK-DAG: define linkonce_odr void @_ZN6test153zedIZNS_3fooIiEEPvvE3bar_9EEvv(
+  // CHECK-DAG: define linkonce_odr void @_ZN6test153zedIZNS_3fooIiEEPvvE3barEEvv(
   template <class T> void zed() {}
   template <class T> void *foo() {
     class bar {
@@ -197,7 +197,7 @@ namespace test15 {
 }
 
 namespace test16 {
-  // CHECK-DAG: define linkonce_odr void @_ZN6test163zedIZNS_3fooIiE3barEvE1S__10_EEvv(
+  // CHECK-DAG: define linkonce_odr void @_ZN6test163zedIZNS_3fooIiE3barEvE1SEEvv(
   template <class T> void zed() {}
   template <class T> struct foo {
     static void *bar();
index c3ea31a54cac8b1feaba6f4e161ec7318ada1335..186d76a225a95530980bec540af9501fd4f7e6f2 100644 (file)
@@ -55,6 +55,26 @@ void GORF (float IVAR1)
    }
 }
 
+// CHECK: @_ZZ12OmittingCodefEN4SSSSC1E_0RKf
+inline void OmittingCode(float x) {
+  if (0) {
+    struct SSSS {
+      float bv;
+      SSSS(const float& from): bv(from) { }
+    };
+
+    SSSS VAR1(x);
+  }
+
+  struct SSSS {
+    float bv;
+    SSSS(const float& from): bv(from) { }
+  };
+
+  SSSS VAR2(x);
+}
+void CallOmittingCode() { OmittingCode(1); }
+
 // CHECK: @_ZZ25LocalTemplateFunctionTestdEN5Local3fooIdEET_S1_
 int LocalTemplateFunctionTest(double d) {
   struct Local {
@@ -64,3 +84,14 @@ int LocalTemplateFunctionTest(double d) {
   };
   return Local().foo(d);
 }
+
+// CHECK: @_ZZ15LocalAnonStructvENUt0_1gEv
+inline void LocalAnonStruct() {
+  if (0) {
+    struct { void f() {} } x;
+    x.f();
+  }
+  struct { void g() {} } y;
+  y.g();
+}
+void CallLocalAnonStruct() { LocalAnonStruct(); }
index 5f31e5480d2affa2d17579d72c198bbf9e4f90be..4b601229d341f7b3564c2dd98d7708b0eb9933a4 100644 (file)
@@ -888,7 +888,7 @@ namespace test38 {
 }
 
 namespace test39 {
-  // CHECK: define internal void @"_ZN6test394funcINS_3$_0Ut_EEEvT_"
+  // CHECK: define internal void @"_ZN6test394funcINS_3$_03$_1EEEvT_"
   typedef struct {
     struct {} a;
   } *foo;
@@ -897,3 +897,16 @@ namespace test39 {
     func(x->a);
   }
 }
+
+namespace test40 {
+  // CHECK: i32* @_ZZN6test401fEvE1a_0
+  void h(int&);
+  inline void f() {
+    if (0) {
+      static int a;
+    }
+    static int a;
+    h(a);
+  };
+  void g() { f(); }
+}