From: Eli Friedman Date: Mon, 1 Jul 2013 20:22:57 +0000 (+0000) Subject: Fix mangling for block literals. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=07369dde9d72213bf8a48288cd8b29999af9a40c;p=clang Fix mangling for block literals. Blocks, like lambdas, can be written in contexts which are required to be treated as the same under ODR. Unlike lambdas, it isn't possible to actually take the address of a block, so the mangling of the block itself doesn't matter. However, objects like static variables inside a block do need to be mangled in a consistent way. There are basically three components here. One, block literals need a consistent numbering. Two, objects/types inside a block literal need to be mangled using it. Three, objects/types inside a block literal need to have their linkage computed correctly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@185372 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 3f810f9a03..7c2cea25cc 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -19,7 +19,7 @@ #include "clang/AST/CanonicalType.h" #include "clang/AST/CommentCommandTraits.h" #include "clang/AST/Decl.h" -#include "clang/AST/LambdaMangleContext.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/RawCommentList.h" @@ -338,9 +338,11 @@ class ASTContext : public RefCountedBase { typedef llvm::TinyPtrVector CXXMethodVector; llvm::DenseMap OverriddenMethods; - /// \brief Mapping from each declaration context to its corresponding lambda - /// mangling context. - llvm::DenseMap LambdaMangleContexts; + /// \brief Mapping from each declaration context to its corresponding + /// mangling numbering context (used for constructs like lambdas which + /// need to be consistently numbered for the mangler). + llvm::DenseMap + MangleNumberingContexts; llvm::DenseMap UnnamedMangleContexts; llvm::DenseMap UnnamedMangleNumbers; @@ -2087,9 +2089,10 @@ public: 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); - + /// \brief Retrieve the context for computing mangling numbers in the given + /// DeclContext. + MangleNumberingContext &getManglingNumberContext(DeclContext *DC); + /// \brief Used by ParmVarDecl to store on the side the /// index of the parameter when it exceeds the size of the normal bitfield. void setParameterIndex(const ParmVarDecl *D, unsigned index); diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 8342f79f4e..e90f454db3 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -3115,13 +3115,17 @@ private: Capture *Captures; unsigned NumCaptures; + unsigned ManglingNumber; + Decl *ManglingContextDecl; + protected: BlockDecl(DeclContext *DC, SourceLocation CaretLoc) : Decl(Block, DC, CaretLoc), DeclContext(Block), IsVariadic(false), CapturesCXXThis(false), BlockMissingReturnType(true), IsConversionFromLambda(false), ParamInfo(0), NumParams(0), Body(0), - SignatureAsWritten(0), Captures(0), NumCaptures(0) {} + SignatureAsWritten(0), Captures(0), NumCaptures(0), + ManglingNumber(0), ManglingContextDecl(0) {} public: static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); @@ -3191,6 +3195,18 @@ public: const Capture *end, bool capturesCXXThis); + unsigned getBlockManglingNumber() const { + return ManglingNumber; + } + Decl *getBlockManglingContextDecl() const { + return ManglingContextDecl; + } + + void setBlockMangling(unsigned Number, Decl *Ctx) { + ManglingNumber = Number; + ManglingContextDecl = Ctx; + } + virtual SourceRange getSourceRange() const LLVM_READONLY; // Implement isa/cast/dyncast/etc. diff --git a/include/clang/AST/LambdaMangleContext.h b/include/clang/AST/MangleNumberingContext.h similarity index 50% rename from include/clang/AST/LambdaMangleContext.h rename to include/clang/AST/MangleNumberingContext.h index bbaee26494..35c2abd9d8 100644 --- a/include/clang/AST/LambdaMangleContext.h +++ b/include/clang/AST/MangleNumberingContext.h @@ -1,4 +1,4 @@ -//===--- LambdaMangleContext.h - Context for mangling lambdas ---*- C++ -*-===// +//=== MangleNumberingContext.h - Context for mangling numbers ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,13 @@ // //===----------------------------------------------------------------------===// // -// This file defines the LambdaMangleContext interface, which keeps track of -// the Itanium C++ ABI mangling numbers for lambda expressions. +// This file defines the LambdaBlockMangleContext interface, which keeps track +// of the Itanium C++ ABI mangling numbers for lambda expressions and block +// literals. // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_LAMBDAMANGLECONTEXT_H -#define LLVM_CLANG_LAMBDAMANGLECONTEXT_H +#ifndef LLVM_CLANG_MANGLENUMBERINGCONTEXT_H +#define LLVM_CLANG_MANGLENUMBERINGCONTEXT_H #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" @@ -20,18 +21,24 @@ namespace clang { +class BlockDecl; class CXXMethodDecl; -class FunctionProtoType; +class Type; -/// \brief Keeps track of the mangled names of lambda expressions within a -/// particular context. -class LambdaMangleContext : public RefCountedBase { - llvm::DenseMap ManglingNumbers; +/// \brief Keeps track of the mangled names of lambda expressions and block +/// literals within a particular context. +class MangleNumberingContext + : public RefCountedBase { + llvm::DenseMap ManglingNumbers; public: /// \brief Retrieve the mangling number of a new lambda expression with the - /// given call operator within this lambda context. + /// given call operator within this context. unsigned getManglingNumber(CXXMethodDecl *CallOperator); + + /// \brief Retrieve the mangling number of a new block literal within this + /// context. + unsigned getManglingNumber(BlockDecl *BD); }; } // end namespace clang diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index f9846361e5..1b076a44ca 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -20,7 +20,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExternalASTSource.h" -#include "clang/AST/LambdaMangleContext.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/NSAPI.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TypeLoc.h" @@ -662,17 +662,17 @@ public: /// is indeed an unevaluated context. SmallVector Lambdas; - /// \brief The declaration that provides context for the lambda expression - /// if the normal declaration context does not suffice, e.g., in a - /// default function argument. - Decl *LambdaContextDecl; + /// \brief The declaration that provides context for lambda expressions + /// and block literals if the normal declaration context does not + /// suffice, e.g., in a default function argument. + Decl *ManglingContextDecl; /// \brief The context information used to mangle lambda expressions - /// within this context. + /// and block literals within this context. /// /// This mangling information is allocated lazily, since most contexts - /// do not have lambda expressions. - IntrusiveRefCntPtr LambdaMangle; + /// do not have lambda expressions or block literals. + IntrusiveRefCntPtr MangleNumbering; /// \brief If we are processing a decltype type, a set of call expressions /// for which we have deferred checking the completeness of the return type. @@ -685,18 +685,19 @@ public: ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, bool ParentNeedsCleanups, - Decl *LambdaContextDecl, + Decl *ManglingContextDecl, bool IsDecltype) : Context(Context), ParentNeedsCleanups(ParentNeedsCleanups), IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects), - LambdaContextDecl(LambdaContextDecl), LambdaMangle() { } - - /// \brief Retrieve the mangling context for lambdas. - LambdaMangleContext &getLambdaMangleContext() { - assert(LambdaContextDecl && "Need to have a lambda context declaration"); - if (!LambdaMangle) - LambdaMangle = new LambdaMangleContext; - return *LambdaMangle; + ManglingContextDecl(ManglingContextDecl), MangleNumbering() { } + + /// \brief Retrieve the mangling numbering context, used to consistently + /// number constructs like lambdas for mangling. + MangleNumberingContext &getMangleNumberingContext() { + assert(ManglingContextDecl && "Need to have a context declaration"); + if (!MangleNumbering) + MangleNumbering = new MangleNumberingContext; + return *MangleNumbering; } bool isUnevaluated() const { @@ -707,6 +708,18 @@ public: /// A stack of expression evaluation contexts. SmallVector ExprEvalContexts; + /// \brief Compute the mangling number context for a lambda expression or + /// block literal. + /// + /// \param DC - The DeclContext containing the lambda expression or + /// block literal. + /// \param[out] ManglingContextDecl - Returns the ManglingContextDecl + /// associated with the context, if relevant. + MangleNumberingContext *getCurrentMangleNumberContext( + DeclContext *DC, + Decl *&ManglingContextDecl); + + /// SpecialMemberOverloadResult - The overloading result for a special member /// function. /// diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 8374316ac6..7f02f59c68 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -8007,13 +8007,10 @@ int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const { return I != UnnamedMangleNumbers.end() ? I->second : -1; } -unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) { - CXXRecordDecl *Lambda = CallOperator->getParent(); - return LambdaMangleContexts[Lambda->getDeclContext()] - .getManglingNumber(CallOperator); +MangleNumberingContext &ASTContext::getManglingNumberContext(DeclContext *DC) { + return MangleNumberingContexts[DC]; } - void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { ParamIndices[D] = index; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 5267789643..0ad15fc683 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -287,13 +287,12 @@ getLVForTemplateParameterList(const TemplateParameterList *params, static LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation); -static const FunctionDecl *getOutermostFunctionContext(const Decl *D) { - const FunctionDecl *Ret = NULL; +static const Decl *getOutermostFuncOrBlockContext(const Decl *D) { + const Decl *Ret = NULL; const DeclContext *DC = D->getDeclContext(); while (DC->getDeclKind() != Decl::TranslationUnit) { - const FunctionDecl *F = dyn_cast(DC); - if (F) - Ret = F; + if (isa(DC) || isa(DC)) + Ret = cast(DC); DC = DC->getParent(); } return Ret; @@ -996,6 +995,22 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { return None; } +static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, + LVComputationKind computation) { + // This lambda has its linkage/visibility determined by its owner. + if (ContextDecl) { + if (isa(ContextDecl)) + DC = ContextDecl->getDeclContext()->getRedeclContext(); + else + return getLVForDecl(cast(ContextDecl), computation); + } + + if (const NamedDecl *ND = dyn_cast(DC)) + return getLVForDecl(ND, computation); + + return LinkageInfo::external(); +} + static LinkageInfo getLVForLocalDecl(const NamedDecl *D, LVComputationKind computation) { if (const FunctionDecl *Function = dyn_cast(D)) { @@ -1052,14 +1067,25 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, if (!Context.getLangOpts().CPlusPlus) return LinkageInfo::none(); - const FunctionDecl *FD = getOutermostFunctionContext(D); - if (!FD) + const Decl *OuterD = getOutermostFuncOrBlockContext(D); + if (!OuterD) return LinkageInfo::none(); - if (!FD->isInlined() && FD->getTemplateSpecializationKind() == TSK_Undeclared) - return LinkageInfo::none(); + LinkageInfo LV; + if (const BlockDecl *BD = dyn_cast(OuterD)) { + if (!BD->getBlockManglingNumber()) + return LinkageInfo::none(); + + LV = getLVForClosure(BD->getDeclContext()->getRedeclContext(), + BD->getBlockManglingContextDecl(), computation); + } else { + const FunctionDecl *FD = cast(OuterD); + if (!FD->isInlined() && + FD->getTemplateSpecializationKind() == TSK_Undeclared) + return LinkageInfo::none(); - LinkageInfo LV = getLVForDecl(FD, computation); + LV = getLVForDecl(FD, computation); + } if (!isExternallyVisible(LV.getLinkage())) return LinkageInfo::none(); return LinkageInfo(VisibleNoLinkage, LV.getVisibility(), @@ -1095,20 +1121,10 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, // This lambda has no mangling number, so it's internal. return LinkageInfo::internal(); } - - // This lambda has its linkage/visibility determined by its owner. - const DeclContext *DC = D->getDeclContext()->getRedeclContext(); - if (Decl *ContextDecl = Record->getLambdaContextDecl()) { - if (isa(ContextDecl)) - DC = ContextDecl->getDeclContext()->getRedeclContext(); - else - return getLVForDecl(cast(ContextDecl), computation); - } - if (const NamedDecl *ND = dyn_cast(DC)) - return getLVForDecl(ND, computation); - - return LinkageInfo::external(); + // This lambda has its linkage/visibility determined by its owner. + return getLVForClosure(D->getDeclContext()->getRedeclContext(), + Record->getLambdaContextDecl(), computation); } break; diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index cf1e5126d3..bbdf0f93d1 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1416,15 +1416,22 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { return; if (const BlockDecl *Block = dyn_cast(DC)) { - // The symbol we're adding a prefix for isn't externally - // visible; make up something sane. - // FIXME: This isn't always true! - SmallString<16> BlockPrefix; - BlockPrefix += "__block_prefix_internal"; - unsigned Number = Context.getBlockId(Block, false); + // Reflect the lambda mangling rules, except that we don't have an + // actual function declaration. + if (NoFunction) + return; + + 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) - BlockPrefix += llvm::utostr_32(Number - 2); - Out << BlockPrefix.size() << BlockPrefix; + Out << Number - 2; + Out << '_'; return; } else if (isa(DC)) { // Skip CapturedDecl context. diff --git a/lib/AST/LambdaMangleContext.cpp b/lib/AST/MangleNumberingContext.cpp similarity index 71% rename from lib/AST/LambdaMangleContext.cpp rename to lib/AST/MangleNumberingContext.cpp index 10b01a6999..a4c8a27da5 100644 --- a/lib/AST/LambdaMangleContext.cpp +++ b/lib/AST/MangleNumberingContext.cpp @@ -1,4 +1,4 @@ -//===--- LambdaMangleContext.cpp - Context for mangling lambdas -*- C++ -*-===// +//===--- MangleNumberingContext.cpp - Context for mangling numbers --------===// // // The LLVM Compiler Infrastructure // @@ -12,13 +12,14 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/LambdaMangleContext.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" using namespace clang; -unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) { +unsigned +MangleNumberingContext::getManglingNumber(CXXMethodDecl *CallOperator) { const FunctionProtoType *Proto = CallOperator->getType()->getAs(); ASTContext &Context = CallOperator->getASTContext(); @@ -28,3 +29,10 @@ unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) { Key = Context.getCanonicalType(Key); return ++ManglingNumbers[Key->castAs()]; } + +unsigned +MangleNumberingContext::getManglingNumber(BlockDecl *BD) { + // FIXME: Compute a BlockPointerType? Not obvious how. + const Type *Ty = 0; + return ++ManglingNumbers[Ty]; +} diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 519f03aba1..62cd7442ec 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -130,9 +130,27 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) { if (D.isExternallyVisible()) { const Decl *D = CurCodeDecl; while (true) { - if (isa(D)) { - // FIXME: Handle this case properly! (Should be similar to the - // way we handle lambdas in computeLVForDecl in Decl.cpp.) + if (const BlockDecl *BD = dyn_cast(D)) { + if (!BD->getBlockManglingNumber()) + break; + + // This block has the linkage/visibility of its contained variables + // determined by its owner. + const DeclContext *DC = D->getDeclContext()->getRedeclContext(); + if (Decl *ContextDecl = BD->getBlockManglingContextDecl()) { + if (isa(ContextDecl)) { + DC = ContextDecl->getDeclContext()->getRedeclContext(); + } else { + D = ContextDecl; + continue; + } + } + + if (const NamedDecl *ND = dyn_cast(DC)) { + D = ND; + continue; + } + break; } else if (isa(D)) { D = cast(cast(D)->getParent()); @@ -140,13 +158,26 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) { break; } } - // FIXME: Do we really only care about FunctionDecls here? + llvm::GlobalValue::LinkageTypes ParentLinkage; if (isa(D)) { - llvm::GlobalValue::LinkageTypes ParentLinkage = - CGM.getFunctionLinkage(cast(D)); - if (llvm::GlobalValue::isWeakForLinker(ParentLinkage)) - Linkage = ParentLinkage; + ParentLinkage = CGM.getFunctionLinkage(cast(D)); + } else if (isa(D)) { + // FIXME: I'm pretty sure this is wrong... + ParentLinkage = CGM.GetLLVMLinkageVarDefinition(cast(D), + /*constant*/false); + } else { + assert(isa(D) && "Expect function, variable, or field"); + // FIXME: Is this right? + ParentLinkage = llvm::GlobalValue::LinkOnceODRLinkage; } + + if (llvm::GlobalValue::isWeakForLinker(ParentLinkage)) + Linkage = ParentLinkage; + + // FIXME: We need to force the emission/use of a guard variable for + // some variables even if we can constant-evaluate them because + // we can't guarantee every translation unit will constant-evaluate them. + // Also, we might need to fix up the linkage. } return EmitStaticVarDecl(D, Linkage); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 3298d5a089..cfb9e78368 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1797,7 +1797,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // Set the llvm linkage type as appropriate. llvm::GlobalValue::LinkageTypes Linkage = - GetLLVMLinkageVarDefinition(D, GV); + GetLLVMLinkageVarDefinition(D, GV->isConstant()); GV->setLinkage(Linkage); if (Linkage == llvm::GlobalVariable::CommonLinkage) // common vars aren't constant even if declared const. @@ -1828,8 +1828,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { } llvm::GlobalValue::LinkageTypes -CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, - llvm::GlobalVariable *GV) { +CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) { GVALinkage Linkage = getContext().GetGVALinkageForVariable(D); if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; @@ -1844,7 +1843,7 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, // http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx return llvm::GlobalVariable::WeakODRLinkage; } else if (D->hasAttr()) { - if (GV->isConstant()) + if (isConstant) return llvm::GlobalVariable::WeakODRLinkage; else return llvm::GlobalVariable::WeakAnyLinkage; diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 6e5985d9bf..a5fca36a93 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -942,8 +942,7 @@ public: /// GetLLVMLinkageVarDefinition - Returns LLVM linkage for a global /// variable. llvm::GlobalValue::LinkageTypes - GetLLVMLinkageVarDefinition(const VarDecl *D, - llvm::GlobalVariable *GV); + GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant); /// Emit all the global annotations. void EmitGlobalAnnotations(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 15235634df..2f5961d479 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9810,6 +9810,17 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, /// ActOnBlockStart - This callback is invoked when a block literal is started. void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc); + + { + Decl *ManglingContextDecl; + if (MangleNumberingContext *MCtx = + getCurrentMangleNumberContext(Block->getDeclContext(), + ManglingContextDecl)) { + unsigned ManglingNumber = MCtx->getManglingNumber(Block); + Block->setBlockMangling(ManglingNumber, ManglingContextDecl); + } + } + PushBlockScope(CurScope, Block); CurContext->addDecl(Block); if (CurScope) @@ -9929,11 +9940,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, // Finally we can process decl attributes. ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); - // Put the parameter variables in scope. We can bail out immediately - // if we don't have any. - if (Params.empty()) - return; - + // Put the parameter variables in scope. for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(), E = CurBlock->TheDecl->param_end(); AI != E; ++AI) { (*AI)->setOwningFunction(CurBlock->TheDecl); @@ -10641,8 +10648,8 @@ void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, bool IsDecltype) { - Decl *LambdaContextDecl = ExprEvalContexts.back().LambdaContextDecl; - PushExpressionEvaluationContext(NewContext, LambdaContextDecl, IsDecltype); + Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl; + PushExpressionEvaluationContext(NewContext, ClosureContextDecl, IsDecltype); } void Sema::PopExpressionEvaluationContext() { diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 32cc176119..bc99d58d14 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -52,6 +52,72 @@ static bool isInInlineFunction(const DeclContext *DC) { return false; } +MangleNumberingContext * +Sema::getCurrentMangleNumberContext(DeclContext *DC, + Decl *&ManglingContextDecl) { + // Compute the context for allocating mangling numbers in the current + // expression, if the ABI requires them. + ManglingContextDecl = ExprEvalContexts.back().ManglingContextDecl; + + enum ContextKind { + Normal, + DefaultArgument, + DataMember, + StaticDataMember + } Kind = Normal; + + // Default arguments of member function parameters that appear in a class + // definition, as well as the initializers of data members, receive special + // treatment. Identify them. + if (ManglingContextDecl) { + if (ParmVarDecl *Param = dyn_cast(ManglingContextDecl)) { + if (const DeclContext *LexicalDC + = Param->getDeclContext()->getLexicalParent()) + if (LexicalDC->isRecord()) + Kind = DefaultArgument; + } else if (VarDecl *Var = dyn_cast(ManglingContextDecl)) { + if (Var->getDeclContext()->isRecord()) + Kind = StaticDataMember; + } else if (isa(ManglingContextDecl)) { + Kind = DataMember; + } + } + + // Itanium ABI [5.1.7]: + // In the following contexts [...] the one-definition rule requires closure + // types in different translation units to "correspond": + bool IsInNonspecializedTemplate = + !ActiveTemplateInstantiations.empty() || CurContext->isDependentContext(); + switch (Kind) { + case Normal: + // -- the bodies of non-exported nonspecialized template functions + // -- the bodies of inline functions + if ((IsInNonspecializedTemplate && + !(ManglingContextDecl && isa(ManglingContextDecl))) || + isInInlineFunction(CurContext)) { + ManglingContextDecl = 0; + return &Context.getManglingNumberContext(DC); + } + + ManglingContextDecl = 0; + return 0; + + case StaticDataMember: + // -- the initializers of nonspecialized static members of template classes + if (!IsInNonspecializedTemplate) { + ManglingContextDecl = 0; + return 0; + } + // Fall through to get the current context. + + case DataMember: + // -- the in-class initializers of class members + case DefaultArgument: + // -- default arguments appearing in class definitions + return &ExprEvalContexts.back().getMangleNumberingContext(); + } +} + CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, @@ -98,75 +164,14 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, (*P)->setOwningFunction(Method); } - // Allocate a mangling number for this lambda expression, if the ABI - // requires one. - Decl *ContextDecl = ExprEvalContexts.back().LambdaContextDecl; - - enum ContextKind { - Normal, - DefaultArgument, - DataMember, - StaticDataMember - } Kind = Normal; - - // Default arguments of member function parameters that appear in a class - // definition, as well as the initializers of data members, receive special - // treatment. Identify them. - if (ContextDecl) { - if (ParmVarDecl *Param = dyn_cast(ContextDecl)) { - if (const DeclContext *LexicalDC - = Param->getDeclContext()->getLexicalParent()) - if (LexicalDC->isRecord()) - Kind = DefaultArgument; - } else if (VarDecl *Var = dyn_cast(ContextDecl)) { - if (Var->getDeclContext()->isRecord()) - Kind = StaticDataMember; - } else if (isa(ContextDecl)) { - Kind = DataMember; - } - } - - // Itanium ABI [5.1.7]: - // In the following contexts [...] the one-definition rule requires closure - // types in different translation units to "correspond": - bool IsInNonspecializedTemplate = - !ActiveTemplateInstantiations.empty() || CurContext->isDependentContext(); - unsigned ManglingNumber; - switch (Kind) { - case Normal: - // -- the bodies of non-exported nonspecialized template functions - // -- the bodies of inline functions - if ((IsInNonspecializedTemplate && - !(ContextDecl && isa(ContextDecl))) || - isInInlineFunction(CurContext)) - ManglingNumber = Context.getLambdaManglingNumber(Method); - else - ManglingNumber = 0; - - // There is no special context for this lambda. - ContextDecl = 0; - break; - - case StaticDataMember: - // -- the initializers of nonspecialized static members of template classes - if (!IsInNonspecializedTemplate) { - ManglingNumber = 0; - ContextDecl = 0; - break; - } - // Fall through to assign a mangling number. - - case DataMember: - // -- the in-class initializers of class members - case DefaultArgument: - // -- default arguments appearing in class definitions - ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext() - .getManglingNumber(Method); - break; + Decl *ManglingContextDecl; + if (MangleNumberingContext *MCtx = + getCurrentMangleNumberContext(Class->getDeclContext(), + ManglingContextDecl)) { + unsigned ManglingNumber = MCtx->getManglingNumber(Method); + Class->setLambdaMangling(ManglingNumber, ManglingContextDecl); } - Class->setLambdaMangling(ManglingNumber, ContextDecl); - return Method; } diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm index cb2bf75f22..39f59a3fec 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks-irgen.mm @@ -14,7 +14,7 @@ namespace PR12746 { } // CHECK: define internal zeroext i1 @___ZN7PR127462f1EPi_block_invoke - // CHECK: call zeroext i1 @"_ZNK23__block_prefix_internal3$_0clEv" + // CHECK: call zeroext i1 @"_ZNK7PR127462f1Ub_3$_0clEv" bool f2(int *x) { auto outer = [&]() -> bool { diff --git a/test/CodeGenObjCXX/mangle-blocks.mm b/test/CodeGenObjCXX/mangle-blocks.mm index 20cc7b4854..6493135050 100644 --- a/test/CodeGenObjCXX/mangle-blocks.mm +++ b/test/CodeGenObjCXX/mangle-blocks.mm @@ -1,13 +1,14 @@ // RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck %s -// CHECK: @_ZGVN23__block_prefix_internal5valueE = internal global i64 0 -// CHECK: @_ZN24__block_prefix_internal35namebE = internal global i8* +// 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 int f(); void foo() { // CHECK: define internal i32 @___Z3foov_block_invoke - // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVN23__block_prefix_internal5valueE + // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVN3fooUb_5valueE (void)^(int x) { static int value = f(); return x + value; @@ -25,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: @_ZN24__block_prefix_internal04nameE + // CHECK: @"_ZN11-[A method]Ub0_4nameE" static const char *name = "hello"; return name[x]; }; @@ -43,7 +44,7 @@ namespace N { // CHECK: define internal signext i8 @___Z3fooi_block_invoke void bar() { (void)^(int x) { - // CHECK: @_ZN24__block_prefix_internal14nameE + // CHECK: @_ZN1N3barUb2_4nameE static const char *name = "hello"; return name[x]; }; @@ -55,8 +56,33 @@ class C { }; C::C() { (void)^(int x) { - // CHECK: @_ZN24__block_prefix_internal35namebE + // CHECK: @_ZN1CC1Ub3_5namebE static const char *nameb = "hello"; return nameb[x]; }; } + +int f(); +namespace externally_visible_statics { + inline void inlinefunc() { + ^{ + static int i = f(); + }(); + } + struct S { + int x = ^{ + static int j = f(); + return j; + }(); + void foo(int y = ^{ static int k = f(); return k; }()) {} + }; + void g() { + inlinefunc(); + S s; +#if 0 + // FIXME: We know how to mangle k, but crash trying to mangle the + // block itself. + s.foo(); +#endif + } +}