From: David Blaikie Date: Wed, 14 Nov 2012 01:52:05 +0000 (+0000) Subject: Provide the correct mangling and linkage for certain unnamed nested classes. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=66cff7257698d5528632917d38f9a3037bb1506d;p=clang Provide the correct mangling and linkage for certain unnamed nested classes. This corrects the mangling and linkage of classes (& their member functions) in cases like this: struct foo { struct { void func() { ... } } x; }; we were accidentally giving this nested unnamed struct 'no' linkage where it should've had the linkage of the outer class. The mangling was incorrecty too, mangling as TU-wide unnamed type mangling of $_X rather than class-scoped mangling of UtX_. This also fixes -Wunused-member-function which would incorrectly diagnose 'func' as unused due to it having no linkage & thus appearing to be TU-local when in fact it might be correctly used in another TU. Similar mangling should be applied to function local classes in similar cases but I've deferred that for a subsequent patch. Review/discussion by Richard Smith, John McCall, & especially Eli Friedman. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167906 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index d559feed17..25135133d4 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -343,7 +343,10 @@ class ASTContext : public RefCountedBase { /// \brief Mapping from each declaration context to its corresponding lambda /// mangling context. llvm::DenseMap LambdaMangleContexts; - + + llvm::DenseMap UnnamedMangleContexts; + llvm::DenseMap UnnamedMangleNumbers; + /// \brief Mapping that stores parameterIndex values for ParmVarDecls when /// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex. typedef llvm::DenseMap ParameterIndexTable; @@ -1989,6 +1992,9 @@ public: /// it is not used. bool DeclMustBeEmitted(const Decl *D); + void addUnnamedTag(const TagDecl *Tag); + int getUnnamedTagManglingNumber(const TagDecl *Tag) const; + /// \brief Retrieve the lambda mangling number for a lambda expression. unsigned getLambdaManglingNumber(CXXMethodDecl *CallOperator); diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 0728e87376..c1cf30e45f 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -377,16 +377,16 @@ private: static bool isExprRep(TST T) { return (T == TST_typeofExpr || T == TST_decltype); } + + DeclSpec(const DeclSpec &) LLVM_DELETED_FUNCTION; + void operator=(const DeclSpec &) LLVM_DELETED_FUNCTION; +public: static bool isDeclRep(TST T) { return (T == TST_enum || T == TST_struct || T == TST_interface || T == TST_union || T == TST_class); } - DeclSpec(const DeclSpec &) LLVM_DELETED_FUNCTION; - void operator=(const DeclSpec &) LLVM_DELETED_FUNCTION; -public: - DeclSpec(AttributeFactory &attrFactory) : StorageClassSpec(SCS_unspecified), SCS_thread_specified(false), diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 577dd0adaf..80ce66a017 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -7508,6 +7508,23 @@ 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(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage) + return; + + std::pair::iterator, bool> P = + UnnamedMangleContexts.insert(std::make_pair(Tag->getParent(), 0)); + UnnamedMangleNumbers.insert(std::make_pair(Tag, P.first->second++)); +} + +int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const { + llvm::DenseMap::const_iterator I = + UnnamedMangleNumbers.find(Tag); + return I != UnnamedMangleNumbers.end() ? I->second : -1; +} + unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) { CXXRecordDecl *Lambda = CallOperator->getParent(); return LambdaMangleContexts[Lambda->getDeclContext()] diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 74abbaa492..9569841a56 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -480,8 +480,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) { if (!(isa(D) || isa(D) || isa(D) || - (isa(D) && - (D->getDeclName() || cast(D)->getTypedefNameForAnonDecl())))) + isa(D))) return LinkageInfo::none(); LinkageInfo LV; @@ -2561,8 +2560,7 @@ void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { void TagDecl::startDefinition() { IsBeingDefined = true; - if (isa(this)) { - CXXRecordDecl *D = cast(this); + if (CXXRecordDecl *D = dyn_cast(this)) { struct CXXRecordDecl::DefinitionData *Data = new (getASTContext()) struct CXXRecordDecl::DefinitionData(D); for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 851944a42b..fc61d88bd9 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1117,6 +1117,18 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, break; } } + + int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD); + if (UnnamedMangle != -1) { + Out << "Ut"; + if (UnnamedMangle != 0) + Out << llvm::utostr(UnnamedMangle - 1); + Out << '_'; + break; + } + + //assert(cast(RD)->isAnonymousStructOrUnion() && "Don't mangle unnamed things as " + // "anonymous things"); // Get a unique id for the anonymous struct. uint64_t AnonStructId = Context.getAnonymousStructId(TD); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 04f66e5882..72516fda80 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2655,6 +2655,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } if (Tag) { + getASTContext().addUnnamedTag(Tag); Tag->setFreeStanding(); if (Tag->isInvalidDecl()) return Tag; @@ -7355,6 +7356,10 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, if (Decl *D = Group[i]) Decls.push_back(D); + if (DeclSpec::isDeclRep(DS.getTypeSpecType())) + if (const TagDecl *Tag = dyn_cast_or_null(DS.getRepAsDecl())) + getASTContext().addUnnamedTag(Tag); + return BuildDeclaratorGroup(Decls.data(), Decls.size(), DS.getTypeSpecType() == DeclSpec::TST_auto); } diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index ba1b3bf5ac..5dad030d5e 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -218,7 +218,7 @@ struct S7 { // PR5139 // CHECK: @_ZN2S7C1Ev // CHECK: @_ZN2S7C2Ev -// CHECK: @"_ZN2S73$_0C1Ev" +// CHECK: @_ZN2S7Ut_C1Ev S7::S7() {} // PR5063 @@ -852,3 +852,23 @@ namespace test36 { // CHECK: define weak_odr {{.*}} @_ZN6test362f1IJifEEENS_1AIXsZfp_EEEDpT_ template A<2> f1(int, float); } + +namespace test37 { + struct foo { + struct { + } a; + typedef struct { } b; + typedef struct { } *c; + struct { + } d; + }; + template void func(T) { } + void test() { + // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt_EEEvT_ + func(foo().a); + // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt0_EEEvT_ + func(*foo::c()); + // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt1_EEEvT_ + func(foo().d); + } +} diff --git a/test/CodeGenCXX/template-anonymous-types.cpp b/test/CodeGenCXX/template-anonymous-types.cpp index 72fe090ceb..3df487a33f 100644 --- a/test/CodeGenCXX/template-anonymous-types.cpp +++ b/test/CodeGenCXX/template-anonymous-types.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -w -o - | FileCheck %s struct S { enum { FOO = 42 }; @@ -17,21 +17,21 @@ template int f(T t) { } void test() { - // Look for two instantiations, entirely internal to this TU, one for FOO's + // Look for two instantiations, one for FOO's // type and one for BAR's. - // CHECK: define internal i32 @"_Z1fIN1S3$_0EEiT_"(i32 %t) + // CHECK: define linkonce_odr i32 @_Z1fIN1SUt_EEiT_(i32 %t) (void)f(S::FOO); - // CHECK: define internal i32 @"_Z1fIN1S3$_1EEiT_"(i32 %t) + // CHECK: define linkonce_odr i32 @_Z1fIN1SUt0_EEiT_(i32 %t) (void)f(S::BAR); // Now check for the class template instantiations. Annoyingly, they are in // reverse order. // // BAR's instantiation of X: - // CHECK: define internal i32 @"_ZN1XIN1S3$_1EE1fEv"(%struct.X* %this) - // CHECK: define internal void @"_ZN1XIN1S3$_1EEC2ES1_"(%struct.X* %this, i32 %t) unnamed_addr + // CHECK: define linkonce_odr i32 @_ZN1XIN1SUt0_EE1fEv(%struct.X* %this) + // CHECK: define linkonce_odr void @_ZN1XIN1SUt0_EEC2ES1_(%struct.X* %this, i32 %t) unnamed_addr // // FOO's instantiation of X: - // CHECK: define internal i32 @"_ZN1XIN1S3$_0EE1fEv"(%struct.X.0* %this) - // CHECK: define internal void @"_ZN1XIN1S3$_0EEC2ES1_"(%struct.X.0* %this, i32 %t) unnamed_addr + // CHECK: define linkonce_odr i32 @_ZN1XIN1SUt_EE1fEv(%struct.X.0* %this) + // CHECK: define linkonce_odr void @_ZN1XIN1SUt_EEC2ES1_(%struct.X.0* %this, i32 %t) unnamed_addr } diff --git a/test/SemaCXX/warn-unused-filescoped.cpp b/test/SemaCXX/warn-unused-filescoped.cpp index ad896b5212..1e0802e42d 100644 --- a/test/SemaCXX/warn-unused-filescoped.cpp +++ b/test/SemaCXX/warn-unused-filescoped.cpp @@ -101,3 +101,20 @@ namespace test5 { static const double d = 0.0; int y = sizeof(d); } + +namespace unused_nested { + class outer { + void func1(); + struct { + void func2() { + } + } x; + }; +} + +namespace unused { + struct { + void func() { // expected-warning {{unused member function}} + } + } x; // expected-warning {{unused variable}} +}