]> granicus.if.org Git - clang/commitdiff
Fix the issue of mangling of local anonymous unions (Itanium C++ ABI):
authorEvgeny Astigeevich <evgeny.astigeevich@arm.com>
Fri, 12 Dec 2014 16:17:46 +0000 (16:17 +0000)
committerEvgeny Astigeevich <evgeny.astigeevich@arm.com>
Fri, 12 Dec 2014 16:17:46 +0000 (16:17 +0000)
A discriminator is used for the first occurrence of a name.
inline int f1 () {
  static union {
    int a;
    long int b;
  };

  static union {
    int c;
    double d;
  };

  return a+c;
}
The name of the second union is mangled as _ZZ2f1vE1c_0 instead of _ZZ2f1vE1c.

Differential Revision: http://reviews.llvm.org/D6295

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

include/clang/AST/Decl.h
lib/AST/Decl.cpp
lib/AST/ItaniumCXXABI.cpp
lib/AST/ItaniumMangle.cpp
test/CodeGenCXX/mangle-local-anonymous-unions.cpp [new file with mode: 0644]

index b946636ebdf0ea2f1d8676c51239d62d5a649d4b..cdba3bda80f439f74fad69620945aadf0b421254 100644 (file)
@@ -3274,6 +3274,10 @@ public:
   /// intra-object-overflow bugs.
   bool mayInsertExtraPadding(bool EmitRemark = false) const;
 
+  /// Finds the first data member which has a name.
+  /// nullptr is returned if no named data member exists.
+  const FieldDecl *findFirstNamedDataMember() const;  
+
 private:
   /// \brief Deserialize just the fields.
   void LoadFieldsFromExternalStorage() const;
index 3e398ae91788e9be86f62eb878ea6938e5fbce26..1c0c6f766729270a66d6dca2db48d1cfb6a67f71 100644 (file)
@@ -3670,6 +3670,22 @@ bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const {
   return ReasonToReject < 0;
 }
 
+const FieldDecl *RecordDecl::findFirstNamedDataMember() const {
+  for (const auto *I : fields()) {
+    if (I->getIdentifier())
+      return I;
+
+    if (const RecordType *RT = I->getType()->getAs<RecordType>())
+      if (const FieldDecl *NamedDataMember =
+          RT->getDecl()->findFirstNamedDataMember())
+        return NamedDataMember;
+  }
+
+  // We didn't find a named data member.
+  return nullptr;
+}
+
+
 //===----------------------------------------------------------------------===//
 // BlockDecl Implementation
 //===----------------------------------------------------------------------===//
index 384c2ac696a3027c1795e2e0b05b7f8628edb4b2..378121c8e5b9b89d1d2847a4c9e84d64237f4bb7 100644 (file)
@@ -29,12 +29,33 @@ using namespace clang;
 
 namespace {
 
+/// According to Itanium C++ ABI 5.1.2:
+/// the name of an anonymous union is considered to be
+/// the name of the first named data member found by a pre-order,
+/// depth-first, declaration-order walk of the data members of
+/// the anonymous union.
+/// If there is no such data member (i.e., if all of the data members
+/// in the union are unnamed), then there is no way for a program to
+/// refer to the anonymous union, and there is therefore no need to mangle its name.
+///
+/// Returns the name of anonymous union VarDecl or nullptr if it is not found.
+static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) {
+  const RecordType *RT = VD.getType()->getAs<RecordType>();
+  assert(RT && "type of VarDecl is expected to be RecordType.");
+  assert(RT->getDecl()->isUnion() && "RecordType is expected to be a union.");
+  if (const FieldDecl *FD = RT->getDecl()->findFirstNamedDataMember()) {
+    return FD->getIdentifier();
+  }
+
+  return nullptr;
+}
+
 /// \brief Keeps track of the mangled names of lambda expressions and block
 /// literals within a particular context.
 class ItaniumNumberingContext : public MangleNumberingContext {
   llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
-  llvm::DenseMap<IdentifierInfo *, unsigned> VarManglingNumbers;
-  llvm::DenseMap<IdentifierInfo *, unsigned> TagManglingNumbers;
+  llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers;
+  llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers;
 
 public:
   unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
@@ -60,7 +81,12 @@ public:
 
   /// Variable decls are numbered by identifier.
   unsigned getManglingNumber(const VarDecl *VD, unsigned) override {
-    return ++VarManglingNumbers[VD->getIdentifier()];
+    const IdentifierInfo *Identifier = VD->getIdentifier();
+    if (!Identifier) {
+      // VarDecl without an identifier represents an anonymous union declaration.
+      Identifier = findAnonymousUnionVarDeclName(*VD);
+    }
+    return ++VarManglingNumbers[Identifier];
   }
 
   unsigned getManglingNumber(const TagDecl *TD, unsigned) override {
index 31250aaa20ff945af906e24316b75f139758b0cf..156ad646fa6d9d05ae49ac88d8ac9b27361be89b 100644 (file)
@@ -117,7 +117,7 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
   typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy;
   llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
   llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
-  
+
 public:
   explicit ItaniumMangleContextImpl(ASTContext &Context,
                                     DiagnosticsEngine &Diags)
@@ -1050,24 +1050,6 @@ void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier,
   mangleUnqualifiedName(nullptr, name, knownArity);
 }
 
-static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) {
-  assert(RD->isAnonymousStructOrUnion() &&
-         "Expected anonymous struct or union!");
-  
-  for (const auto *I : RD->fields()) {
-    if (I->getIdentifier())
-      return I;
-    
-    if (const RecordType *RT = I->getType()->getAs<RecordType>())
-      if (const FieldDecl *NamedDataMember = 
-          FindFirstNamedDataMember(RT->getDecl()))
-        return NamedDataMember;
-  }
-
-  // We didn't find a named data member.
-  return nullptr;
-}
-
 void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
                                            DeclarationName Name,
                                            unsigned KnownArity) {
@@ -1104,9 +1086,9 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
 
     if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
       // We must have an anonymous union or struct declaration.
-      const RecordDecl *RD = 
+      const RecordDecl *RD =
         cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl());
-      
+
       // Itanium C++ ABI 5.1.2:
       //
       //   For the purposes of mangling, the name of an anonymous union is
@@ -1116,14 +1098,16 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
       //   the data members in the union are unnamed), then there is no way for
       //   a program to refer to the anonymous union, and there is therefore no
       //   need to mangle its name.
-      const FieldDecl *FD = FindFirstNamedDataMember(RD);
+      assert(RD->isAnonymousStructOrUnion()
+             && "Expected anonymous struct or union!");
+      const FieldDecl *FD = RD->findFirstNamedDataMember();
 
       // It's actually possible for various reasons for us to get here
       // with an empty anonymous struct / union.  Fortunately, it
       // doesn't really matter what name we generate.
       if (!FD) break;
       assert(FD->getIdentifier() && "Data member name isn't an identifier!");
-      
+
       mangleSourceName(FD->getIdentifier());
       break;
     }
@@ -3758,7 +3742,7 @@ void ItaniumMangleContextImpl::mangleCXXName(const NamedDecl *D,
                                  "Mangling declaration");
 
   CXXNameMangler Mangler(*this, Out, D);
-  return Mangler.mangle(D);
+  Mangler.mangle(D);
 }
 
 void ItaniumMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D,
@@ -3947,3 +3931,4 @@ ItaniumMangleContext *
 ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
   return new ItaniumMangleContextImpl(Context, Diags);
 }
+
diff --git a/test/CodeGenCXX/mangle-local-anonymous-unions.cpp b/test/CodeGenCXX/mangle-local-anonymous-unions.cpp
new file mode 100644 (file)
index 0000000..9187c1a
--- /dev/null
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple %itanium_abi_triple -o - | FileCheck %s
+
+// CHECK-DAG: @_ZZ2f0vE1a
+// CHECK-DAG: @_ZZ2f0vE1c
+// CHECK-DAG: @_ZZ2f0vE1e_0
+inline int f0() {
+  static union {
+    int a;
+    long int b;
+  };
+
+  static union {
+    int c;
+    double d;
+  };
+
+  if (0) {
+    static union {
+      int e;
+      int f;
+    };
+  }
+  static union {
+    int e;
+    int f;
+  };
+
+  return a+c;
+}
+
+inline void nop() {
+  static union {
+    union {
+    };
+  };
+}
+
+int f1 (int a, int c) {
+  nop();
+  return a+c+f0();
+}
+