Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -3274,6 +3274,10 @@ /// 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: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -3667,6 +3667,22 @@ 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()) + if (const FieldDecl *NamedDataMember = + RT->getDecl()->findFirstNamedDataMember()) + return NamedDataMember; + } + + // We didn't find a named data member. + return nullptr; +} + + //===----------------------------------------------------------------------===// // BlockDecl Implementation //===----------------------------------------------------------------------===// Index: lib/AST/ItaniumCXXABI.cpp =================================================================== --- lib/AST/ItaniumCXXABI.cpp +++ lib/AST/ItaniumCXXABI.cpp @@ -29,12 +29,33 @@ 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(); + 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 ManglingNumbers; - llvm::DenseMap VarManglingNumbers; - llvm::DenseMap TagManglingNumbers; + llvm::DenseMap VarManglingNumbers; + llvm::DenseMap TagManglingNumbers; public: unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override { @@ -60,7 +81,12 @@ /// 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: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -117,7 +117,7 @@ typedef std::pair DiscriminatorKeyTy; llvm::DenseMap Discriminator; llvm::DenseMap Uniquifier; - + public: explicit ItaniumMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags) @@ -1050,24 +1050,6 @@ 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()) - 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 @@ if (const VarDecl *VD = dyn_cast(ND)) { // We must have an anonymous union or struct declaration. - const RecordDecl *RD = + const RecordDecl *RD = cast(VD->getType()->getAs()->getDecl()); - + // Itanium C++ ABI 5.1.2: // // For the purposes of mangling, the name of an anonymous union is @@ -1116,14 +1098,16 @@ // 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; } @@ -3745,7 +3729,7 @@ "Mangling declaration"); CXXNameMangler Mangler(*this, Out, D); - return Mangler.mangle(D); + Mangler.mangle(D); } void ItaniumMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D, @@ -3934,3 +3918,4 @@ ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) { return new ItaniumMangleContextImpl(Context, Diags); } + Index: test/CodeGenCXX/mangle-local-anonymous-unions.cpp =================================================================== --- test/CodeGenCXX/mangle-local-anonymous-unions.cpp +++ test/CodeGenCXX/mangle-local-anonymous-unions.cpp @@ -0,0 +1,34 @@ +// 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; +} + +int f1 (int a, int c) { + return a+c+f0(); +} +