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. llvm-svn: 167906
This commit is contained in:
parent
5f265fb124
commit
095deba533
|
@ -343,7 +343,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
/// \brief Mapping from each declaration context to its corresponding lambda
|
||||
/// mangling context.
|
||||
llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
|
||||
|
||||
|
||||
llvm::DenseMap<const DeclContext *, unsigned> UnnamedMangleContexts;
|
||||
llvm::DenseMap<const TagDecl *, unsigned> UnnamedMangleNumbers;
|
||||
|
||||
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when
|
||||
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
|
||||
typedef llvm::DenseMap<const VarDecl *, unsigned> 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);
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage)
|
||||
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++));
|
||||
}
|
||||
|
||||
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::getLambdaManglingNumber(CXXMethodDecl *CallOperator) {
|
||||
CXXRecordDecl *Lambda = CallOperator->getParent();
|
||||
return LambdaMangleContexts[Lambda->getDeclContext()]
|
||||
|
|
|
@ -480,8 +480,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) {
|
|||
if (!(isa<CXXMethodDecl>(D) ||
|
||||
isa<VarDecl>(D) ||
|
||||
isa<FieldDecl>(D) ||
|
||||
(isa<TagDecl>(D) &&
|
||||
(D->getDeclName() || cast<TagDecl>(D)->getTypedefNameForAnonDecl()))))
|
||||
isa<TagDecl>(D)))
|
||||
return LinkageInfo::none();
|
||||
|
||||
LinkageInfo LV;
|
||||
|
@ -2561,8 +2560,7 @@ void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
|
|||
void TagDecl::startDefinition() {
|
||||
IsBeingDefined = true;
|
||||
|
||||
if (isa<CXXRecordDecl>(this)) {
|
||||
CXXRecordDecl *D = cast<CXXRecordDecl>(this);
|
||||
if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(this)) {
|
||||
struct CXXRecordDecl::DefinitionData *Data =
|
||||
new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
|
||||
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
|
||||
|
|
|
@ -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<RecordDecl>(RD)->isAnonymousStructOrUnion() && "Don't mangle unnamed things as "
|
||||
// "anonymous things");
|
||||
|
||||
// Get a unique id for the anonymous struct.
|
||||
uint64_t AnonStructId = Context.getAnonymousStructId(TD);
|
||||
|
|
|
@ -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<TagDecl>(DS.getRepAsDecl()))
|
||||
getASTContext().addUnnamedTag(Tag);
|
||||
|
||||
return BuildDeclaratorGroup(Decls.data(), Decls.size(),
|
||||
DS.getTypeSpecType() == DeclSpec::TST_auto);
|
||||
}
|
||||
|
|
|
@ -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<typename T> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <typename T> 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
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue