Move the computation of the lambda mangling information (mangling

number + context) to the point where we initially start defining the
lambda, so that the linkage won't change when that information is made
available. Fixes the assertion in <rdar://problem/11182962>.

Plus, actually mangle the context of lambdas properly.

llvm-svn: 154029
This commit is contained in:
Douglas Gregor 2012-04-04 17:40:10 +00:00
parent f18c03e49e
commit b61e809b42
8 changed files with 130 additions and 111 deletions

View File

@ -621,7 +621,7 @@ class CXXRecordDecl : public RecordDecl {
"queried lambda property of non-lambda class");
return static_cast<LambdaDefinitionData &>(*DefinitionData);
}
/// \brief The template or declaration that this declaration
/// describes or was instantiated from, respectively.
///
@ -1503,6 +1503,13 @@ public:
return getLambdaData().ContextDecl;
}
/// \brief Set the mangling number and context declaration for a lambda
/// class.
void setLambdaMangling(unsigned ManglingNumber, Decl *ContextDecl) {
getLambdaData().ManglingNumber = ManglingNumber;
getLambdaData().ContextDecl = ContextDecl;
}
/// \brief Determine whether this lambda expression was known to be dependent
/// at the time it was created, even if its context does not appear to be
/// dependent.

View File

@ -1231,9 +1231,7 @@ private:
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace,
unsigned ManglingNumber,
Decl *ContextDecl);
SourceLocation ClosingBrace);
/// \brief Construct an empty lambda expression.
LambdaExpr(EmptyShell Empty, unsigned NumCaptures, bool HasArrayIndexVars)
@ -1271,9 +1269,7 @@ public:
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace,
unsigned ManglingNumber,
Decl *ContextDecl);
SourceLocation ClosingBrace);
/// \brief Construct a new lambda expression that will be deserialized from
/// an external source.

View File

@ -3700,7 +3700,10 @@ public:
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
SourceLocation EndLoc,
llvm::ArrayRef<ParmVarDecl *> Params);
llvm::ArrayRef<ParmVarDecl *> Params,
llvm::Optional<unsigned> ManglingNumber
= llvm::Optional<unsigned>(),
Decl *ContextDecl = 0);
/// \brief Introduce the scope for a lambda expression.
sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator,
@ -3733,9 +3736,6 @@ public:
/// was successfully completed.
ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope,
llvm::Optional<unsigned> ManglingNumber
= llvm::Optional<unsigned>(),
Decl *ContextDecl = 0,
bool IsInstantiation = false);
/// \brief Define the "body" of the conversion from a lambda object to a

View File

@ -796,9 +796,7 @@ LambdaExpr::LambdaExpr(QualType T,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace,
unsigned ManglingNumber,
Decl *ContextDecl)
SourceLocation ClosingBrace)
: Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
T->isDependentType(), T->isDependentType(), T->isDependentType(),
/*ContainsUnexpandedParameterPack=*/false),
@ -819,8 +817,6 @@ LambdaExpr::LambdaExpr(QualType T,
ASTContext &Context = Class->getASTContext();
Data.NumCaptures = NumCaptures;
Data.NumExplicitCaptures = 0;
Data.ManglingNumber = ManglingNumber;
Data.ContextDecl = ContextDecl;
Data.Captures = (Capture *)Context.Allocate(sizeof(Capture) * NumCaptures);
Capture *ToCapture = Data.Captures;
for (unsigned I = 0, N = Captures.size(); I != N; ++I) {
@ -848,9 +844,6 @@ LambdaExpr::LambdaExpr(QualType T,
sizeof(unsigned) * Captures.size());
getArrayIndexStarts()[Captures.size()] = ArrayIndexVars.size();
}
if (ManglingNumber)
Class->ClearLinkageCache();
}
LambdaExpr *LambdaExpr::Create(ASTContext &Context,
@ -863,9 +856,7 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
ArrayRef<Expr *> CaptureInits,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace,
unsigned ManglingNumber,
Decl *ContextDecl) {
SourceLocation ClosingBrace) {
// Determine the type of the expression (i.e., the type of the
// function object we're creating).
QualType T = Context.getTypeDeclType(Class);
@ -878,7 +869,7 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault,
Captures, ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars, ArrayIndexStarts,
ClosingBrace, ManglingNumber, ContextDecl);
ClosingBrace);
}
LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures,

View File

@ -535,6 +535,14 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
return 0;
}
static bool isLambda(const NamedDecl *ND) {
const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(ND);
if (!Record)
return false;
return Record->isLambda();
}
void CXXNameMangler::mangleName(const NamedDecl *ND) {
// <name> ::= <nested-name>
// ::= <unscoped-name>
@ -545,7 +553,9 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
// If this is an extern variable declared locally, the relevant DeclContext
// is that of the containing namespace, or the translation unit.
if (isa<FunctionDecl>(DC) && ND->hasLinkage())
// FIXME: This is a hack; extern variables declared locally should have
// a proper semantic declaration context!
if (isa<FunctionDecl>(DC) && ND->hasLinkage() && !isLambda(ND))
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = getEffectiveParentContext(DC);
else if (GetLocalClassDecl(ND)) {

View File

@ -36,11 +36,27 @@ CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
return Class;
}
/// \brief Determine whether the given context is or is enclosed in an inline
/// function.
static bool isInInlineFunction(const DeclContext *DC) {
while (!DC->isFileContext()) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
if (FD->isInlined())
return true;
DC = DC->getLexicalParent();
}
return false;
}
CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
SourceLocation EndLoc,
llvm::ArrayRef<ParmVarDecl *> Params) {
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
SourceLocation EndLoc,
llvm::ArrayRef<ParmVarDecl *> Params,
llvm::Optional<unsigned> ManglingNumber,
Decl *ContextDecl) {
// C++11 [expr.prim.lambda]p5:
// The closure type for a lambda-expression has a public inline function
// call operator (13.5.4) whose parameters and return type are described by
@ -83,6 +99,63 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
(*P)->setOwningFunction(Method);
}
// If we don't already have a mangling number for this lambda expression,
// allocate one now.
if (!ManglingNumber) {
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<ParmVarDecl>(ContextDecl)) {
if (const DeclContext *LexicalDC
= Param->getDeclContext()->getLexicalParent())
if (LexicalDC->isRecord())
Kind = DefaultArgument;
} else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) {
if (Var->getDeclContext()->isRecord())
Kind = StaticDataMember;
} else if (isa<FieldDecl>(ContextDecl)) {
Kind = DataMember;
}
}
switch (Kind) {
case Normal:
if (CurContext->isDependentContext() || isInInlineFunction(CurContext))
ManglingNumber = Context.getLambdaManglingNumber(Method);
else
ManglingNumber = 0;
// There is no special context for this lambda.
ContextDecl = 0;
break;
case StaticDataMember:
if (!CurContext->isDependentContext()) {
ManglingNumber = 0;
ContextDecl = 0;
break;
}
// Fall through to assign a mangling number.
case DataMember:
case DefaultArgument:
ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
.getManglingNumber(Method);
break;
}
}
Class->setLambdaMangling(*ManglingNumber, ContextDecl);
return Method;
}
@ -491,25 +564,9 @@ static void addBlockPointerConversion(Sema &S,
Conversion->setImplicit(true);
Class->addDecl(Conversion);
}
/// \brief Determine whether the given context is or is enclosed in an inline
/// function.
static bool isInInlineFunction(const DeclContext *DC) {
while (!DC->isFileContext()) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
if (FD->isInlined())
return true;
DC = DC->getLexicalParent();
}
return false;
}
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope,
llvm::Optional<unsigned> ManglingNumber,
Decl *ContextDecl,
bool IsInstantiation) {
// Collect information from the lambda scope.
llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
@ -655,69 +712,12 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
if (LambdaExprNeedsCleanups)
ExprNeedsCleanups = true;
// If we don't already have a mangling number for this lambda expression,
// allocate one now.
if (!ManglingNumber) {
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<ParmVarDecl>(ContextDecl)) {
if (const DeclContext *LexicalDC
= Param->getDeclContext()->getLexicalParent())
if (LexicalDC->isRecord())
Kind = DefaultArgument;
} else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) {
if (Var->getDeclContext()->isRecord())
Kind = StaticDataMember;
} else if (isa<FieldDecl>(ContextDecl)) {
Kind = DataMember;
}
}
switch (Kind) {
case Normal:
if (CurContext->isDependentContext() || isInInlineFunction(CurContext))
ManglingNumber = Context.getLambdaManglingNumber(CallOperator);
else
ManglingNumber = 0;
// There is no special context for this lambda.
ContextDecl = 0;
break;
case StaticDataMember:
if (!CurContext->isDependentContext()) {
ManglingNumber = 0;
ContextDecl = 0;
break;
}
// Fall through to assign a mangling number.
case DataMember:
case DefaultArgument:
ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
.getManglingNumber(CallOperator);
break;
}
}
LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
CaptureDefault, Captures,
ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars,
ArrayIndexStarts, Body->getLocEnd(),
*ManglingNumber, ContextDecl);
ArrayIndexStarts, Body->getLocEnd());
// C++11 [expr.prim.lambda]p2:
// A lambda-expression shall not appear in an unevaluated operand

View File

@ -7815,7 +7815,8 @@ ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// Create the local class that will describe the lambda.
CXXRecordDecl *Class
= getSema().createLambdaClosureType(E->getIntroducerRange());
= getSema().createLambdaClosureType(E->getIntroducerRange(),
/*KnownDependent=*/false);
getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
// Transform the type of the lambda parameters and start the definition of
@ -7836,11 +7837,15 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
Invalid = true;
// Build the call operator.
// Note: Once a lambda mangling number and context declaration have been
// assigned, they never change.
unsigned ManglingNumber = E->getLambdaClass()->getLambdaManglingNumber();
Decl *ContextDecl = E->getLambdaClass()->getLambdaContextDecl();
CXXMethodDecl *CallOperator
= getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
MethodTy,
E->getCallOperator()->getLocEnd(),
Params);
Params, ManglingNumber, ContextDecl);
getDerived().transformAttrs(E->getCallOperator(), CallOperator);
// FIXME: Instantiation-specific.
@ -7953,14 +7958,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
return ExprError();
}
// Note: Once a lambda mangling number and context declaration have been
// assigned, they never change.
unsigned ManglingNumber = E->getLambdaClass()->getLambdaManglingNumber();
Decl *ContextDecl = E->getLambdaClass()->getLambdaContextDecl();
return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(),
/*CurScope=*/0, ManglingNumber,
ContextDecl,
/*IsInstantiation=*/true);
/*CurScope=*/0, /*IsInstantiation=*/true);
}
template<typename Derived>

View File

@ -150,6 +150,8 @@ void use_func_template() {
func_template<int>();
}
// CHECK: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_
struct Members {
int x = [] { return 1; }() + [] { return 2; }();
int y = [] { return 3; }();
@ -165,6 +167,20 @@ void test_Members() {
// CHECK: ret void
}
template<typename P> void f(P) { }
struct TestNestedInstantiation {
void operator()() const {
[]() -> void {
return f([]{});
}();
}
};
void test_NestedInstantiation() {
TestNestedInstantiation()();
}
// Check the linkage of the lambdas used in test_Members.
// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE_clEv
// CHECK: ret i32 1