More fixes for block mangling.

Make sure we properly treat names defined inside a block as local
names.  There are basically three fixes here.  One, correctly
treat blocks as a context where we need to use local-name mangling using
the new isLocalContainerContext helper. Two, make
CXXNameMangler::manglePrefix handle local names in a consistent way.
Three, extend CXXNameMangler::mangleLocalName so it can mangle a block
correctly.

llvm-svn: 185450
This commit is contained in:
Eli Friedman 2013-07-02 17:52:28 +00:00
parent 43bbdd29de
commit 95f501284a
5 changed files with 90 additions and 57 deletions

View File

@ -57,17 +57,25 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) {
return ContextParam->getDeclContext();
}
return D->getDeclContext();
const DeclContext *DC = D->getDeclContext();
if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC))
return getEffectiveDeclContext(CD);
return DC;
}
static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
return getEffectiveDeclContext(cast<Decl>(DC));
}
static bool isLocalContainerContext(const DeclContext *DC) {
return isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC) || isa<BlockDecl>(DC);
}
static const CXXRecordDecl *GetLocalClassDecl(const Decl *D) {
const DeclContext *DC = getEffectiveDeclContext(D);
while (!DC->isNamespace() && !DC->isTranslationUnit()) {
if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC) || isa<BlockDecl>(DC))
if (isLocalContainerContext(DC))
return dyn_cast<CXXRecordDecl>(D);
D = cast<Decl>(DC);
DC = getEffectiveDeclContext(D);
@ -306,7 +314,9 @@ private:
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleUnscopedTemplateName(TemplateName);
void mangleSourceName(const IdentifierInfo *II);
void mangleLocalName(const NamedDecl *ND);
void mangleLocalName(const Decl *D);
void mangleBlockForPrefix(const BlockDecl *Block);
void mangleUnqualifiedBlock(const BlockDecl *Block);
void mangleLambda(const CXXRecordDecl *Lambda);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
bool NoFunction=false);
@ -551,8 +561,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
// is that of the containing namespace, or the translation unit.
// FIXME: This is a hack; extern variables declared locally should have
// a proper semantic declaration context!
if ((isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) &&
ND->hasLinkage() && !isLambda(ND))
if (isLocalContainerContext(DC) && ND->hasLinkage() && !isLambda(ND))
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = getEffectiveParentContext(DC);
else if (GetLocalClassDecl(ND)) {
@ -575,7 +584,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
return;
}
if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) {
if (isLocalContainerContext(DC)) {
mangleLocalName(ND);
return;
}
@ -1264,21 +1273,22 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
Out << 'E';
}
void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
void CXXNameMangler::mangleLocalName(const Decl *D) {
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
// := Z <function encoding> E s [<discriminator>]
// <local-name> := Z <function encoding> E d [ <parameter number> ]
// _ <entity name>
// <discriminator> := _ <non-negative number>
const CXXRecordDecl *RD = GetLocalClassDecl(ND);
const DeclContext *DC = getEffectiveDeclContext(RD ? RD : ND);
assert(isa<NamedDecl>(D) || isa<BlockDecl>(D));
const CXXRecordDecl *RD = GetLocalClassDecl(D);
const DeclContext *DC = getEffectiveDeclContext(RD ? RD : D);
Out << 'Z';
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC))
mangleObjCMethodName(MD);
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC))
manglePrefix(BD); // FIXME: This isn't right.
mangleBlockForPrefix(BD);
else
mangleFunctionEncoding(cast<FunctionDecl>(DC));
@ -1307,10 +1317,16 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
}
// Mangle the name relative to the closest enclosing function.
if (ND == RD) // equality ok because RD derived from ND above
mangleUnqualifiedName(ND);
else
// equality ok because RD derived from ND above
if (D == RD) {
mangleUnqualifiedName(RD);
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
manglePrefix(getEffectiveDeclContext(BD), true /*NoFunction*/);
mangleUnqualifiedBlock(BD);
} else {
const NamedDecl *ND = cast<NamedDecl>(D);
mangleNestedName(ND, getEffectiveDeclContext(ND), true /*NoFunction*/);
}
if (!SkipDiscriminator) {
unsigned disc;
@ -1325,7 +1341,48 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
return;
}
mangleUnqualifiedName(ND);
if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
mangleUnqualifiedBlock(BD);
else
mangleUnqualifiedName(cast<NamedDecl>(D));
}
void CXXNameMangler::mangleBlockForPrefix(const BlockDecl *Block) {
if (GetLocalClassDecl(Block)) {
mangleLocalName(Block);
return;
}
const DeclContext *DC = getEffectiveDeclContext(Block);
if (isLocalContainerContext(DC)) {
mangleLocalName(Block);
return;
}
manglePrefix(getEffectiveDeclContext(Block));
mangleUnqualifiedBlock(Block);
}
void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
if (Decl *Context = Block->getBlockManglingContextDecl()) {
if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
Context->getDeclContext()->isRecord()) {
if (const IdentifierInfo *Name
= cast<NamedDecl>(Context)->getIdentifier()) {
mangleSourceName(Name);
Out << 'M';
}
}
}
// If we have a block mangling number, use it.
unsigned Number = Block->getBlockManglingNumber();
// Otherwise, just make up a number. It doesn't matter what it is because
// the symbol in question isn't externally visible.
if (!Number)
Number = Context.getBlockId(Block, false);
Out << "Ub";
if (Number > 1)
Out << Number - 2;
Out << '_';
}
void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
@ -1411,30 +1468,11 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (DC->isTranslationUnit())
return;
if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) {
// Reflect the lambda mangling rules, except that we don't have an
// actual function declaration.
if (NoFunction)
return;
if (NoFunction && isLocalContainerContext(DC))
return;
assert(!isLocalContainerContext(DC));
manglePrefix(getEffectiveParentContext(DC), NoFunction);
// If we have a block mangling number, use it.
unsigned Number = Block->getBlockManglingNumber();
// Otherwise, just make up a number. It doesn't matter what it is because
// the symbol in question isn't externally visible.
if (!Number)
Number = Context.getBlockId(Block, false);
Out << "Ub";
if (Number > 1)
Out << Number - 2;
Out << '_';
return;
} else if (isa<CapturedDecl>(DC)) {
// Skip CapturedDecl context.
manglePrefix(getEffectiveParentContext(DC), NoFunction);
return;
}
const NamedDecl *ND = cast<NamedDecl>(DC);
if (mangleSubstitution(ND))
return;
@ -1444,12 +1482,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgs(*TemplateArgs);
}
else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND)))
return;
else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
mangleObjCMethodName(Method);
else {
} else {
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
mangleUnqualifiedName(ND);
}

View File

@ -14,7 +14,7 @@ namespace PR12746 {
}
// CHECK: define internal zeroext i1 @___ZN7PR127462f1EPi_block_invoke
// CHECK: call zeroext i1 @"_ZZ7PR127462f1Ub_ENK3$_0clEv"
// CHECK: call zeroext i1 @"_ZZZN7PR127462f1EPiEUb_ENK3$_0clEv"
bool f2(int *x) {
auto outer = [&]() -> bool {

View File

@ -165,7 +165,7 @@ void template_capture_lambda() {
}
void test_capture_lambda() {
// CHECK-6: define {{.*}} void @_ZZ23template_capture_lambdaIiEvvENKS_IiEUlvE_clEv
// CHECK-6: define {{.*}} void @_ZZ23template_capture_lambdaIiEvvENKUlvE_clEv
// CHECK-6-NOT: }
// CHECK-6: store i32*
// CHECK-6: store i32*
@ -175,7 +175,7 @@ void test_capture_lambda() {
}
inline int test_captured_linkage() {
// CHECK-7: @_ZN21test_captured_linkage1iE = linkonce_odr global i32 0
// CHECK-7: @_ZZ21test_captured_linkagevE1i = linkonce_odr global i32 0
int j;
#pragma clang __debug captured
{

View File

@ -160,7 +160,7 @@ void func_template(T = []{ return T(); }());
// CHECK: define void @_Z17use_func_templatev()
void use_func_template() {
// CHECK: call i32 @"_ZZ13func_templateIiEvT_ENKS_IiE3$_3clEv"
// CHECK: call i32 @"_ZZ13func_templateIiEvT_ENK3$_3clEv"
func_template<int>();
}
@ -205,8 +205,8 @@ namespace PR12808 {
void f() {
b<int>(1);
}
// CHECK: define linkonce_odr void @_ZZN7PR128081bIiEEviENKS0_IiEUlvE_clEv
// CHECK: define linkonce_odr i32 @_ZZZN7PR128081bIiEEviENKS0_IiEUlvE_clEvENKUlvE_clEv
// CHECK: define linkonce_odr void @_ZZN7PR128081bIiEEviENKUlvE_clEv
// CHECK: define linkonce_odr i32 @_ZZZN7PR128081bIiEEviENKUlvE_clEvENKUlvE_clEv
}
// CHECK: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_

View File

@ -1,14 +1,14 @@
// RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck %s
// CHECK: @_ZGVN3fooUb_5valueE = internal global i64 0
// CHECK: @_ZN26externally_visible_statics1SUb_1jE = linkonce_odr global i32 0
// CHECK: @_ZN26externally_visible_statics10inlinefuncUb_1iE = linkonce_odr global i32 0
// CHECK: @_ZGVZZ3foovEUb_E5value = internal global i64 0
// CHECK: @_ZZ26externally_visible_statics1S1xMUb_E1j = linkonce_odr global i32 0
// CHECK: @_ZZZN26externally_visible_statics10inlinefuncEvEUb_E1i = linkonce_odr global i32 0
int f();
void foo() {
// CHECK: define internal i32 @___Z3foov_block_invoke
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVN3fooUb_5valueE
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZZ3foovEUb_E5value
(void)^(int x) {
static int value = f();
return x + value;
@ -26,7 +26,7 @@ int i = ^(int x) { return x;}(i);
- (void)method {
// CHECK: define internal signext i8 @"__11-[A method]_block_invoke"
(void)^(int x) {
// CHECK: @"_ZN11-[A method]Ub0_4nameE"
// CHECK: @"_ZZZ11-[A method]EUb0_E4name"
static const char *name = "hello";
return name[x];
};
@ -44,7 +44,7 @@ namespace N {
// CHECK: define internal signext i8 @___Z3fooi_block_invoke
void bar() {
(void)^(int x) {
// CHECK: @_ZN1N3barUb2_4nameE
// CHECK: @_ZZZN1N3barEvEUb2_E4name
static const char *name = "hello";
return name[x];
};
@ -56,7 +56,7 @@ class C {
};
C::C() {
(void)^(int x) {
// CHECK: @_ZN1CC1Ub3_5namebE
// CHECK: @_ZZZN1CC1EvEUb3_E5nameb
static const char *nameb = "hello";
return nameb[x];
};