aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-02-21 00:37:24 +0000
committerDouglas Gregor <dgregor@apple.com>2012-02-21 00:37:24 +0000
commitccc1b5eebc6ca8a904c58c0468b9a71483b7c7cf (patch)
treee2665ec87aa0c270a52f40e66b19a6ca5b2f05f0
parentef7844666b36226521e459d18f2834dacaa039e3 (diff)
Implement name mangling for lambda expressions that occur within the
default arguments of function parameters. This simple-sounding task is complicated greatly by two issues: (1) Default arguments aren't actually a real context, so we need to maintain extra state within lambda expressions to track when a lambda was actually in a default argument. (2) At the time that we parse a default argument, the FunctionDecl doesn't exist yet, so lambda closure types end up in the enclosing context. It's not clear that we ever want to change that, so instead we introduce the notion of the "effective" context of a declaration for the purposes of name mangling. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151011 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h4
-rw-r--r--include/clang/AST/DeclCXX.h29
-rw-r--r--include/clang/AST/ExprCXX.h6
-rw-r--r--include/clang/Sema/Sema.h39
-rw-r--r--lib/AST/ExprCXX.cpp9
-rw-r--r--lib/AST/ItaniumMangle.cpp165
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp6
-rw-r--r--lib/Parse/ParseDecl.cpp3
-rw-r--r--lib/Sema/Sema.cpp2
-rw-r--r--lib/Sema/SemaExpr.cpp6
-rw-r--r--lib/Sema/SemaLambda.cpp33
-rw-r--r--lib/Sema/TreeTransform.h6
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--lib/Serialization/ASTWriter.cpp1
-rw-r--r--test/CodeGenCXX/mangle-lambdas.cpp57
15 files changed, 285 insertions, 82 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 1082806834..10fc81ab22 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -327,12 +327,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// expression used to copy the lambda object.
llvm::DenseMap<const CXXConversionDecl *, Expr *> LambdaBlockPointerInits;
+ friend class CXXConversionDecl;
+
/// \brief Mapping from each declaration context to its corresponding lambda
/// mangling context.
llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
- friend class CXXConversionDecl;
-
/// \brief Mapping that stores parameterIndex values for ParmVarDecls
/// when that value exceeds the bitfield size of
/// ParmVarDeclBits.ParameterIndex.
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 15c37813de..453db168b4 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -561,7 +561,9 @@ class CXXRecordDecl : public RecordDecl {
typedef LambdaExpr::Capture Capture;
LambdaDefinitionData(CXXRecordDecl *D)
- : DefinitionData(D), NumCaptures(0), NumExplicitCaptures(0), Captures(0) {
+ : DefinitionData(D), NumCaptures(0), NumExplicitCaptures(0),
+ ContextDecl(0), Captures(0)
+ {
IsLambda = true;
}
@@ -575,9 +577,14 @@ class CXXRecordDecl : public RecordDecl {
/// mangling in the Itanium C++ ABI.
unsigned ManglingNumber;
- /// \brief The "extra" data associated with the lambda, including
- /// captures, capture initializers, the body of the lambda, and the
- /// array-index variables for array captures.
+ /// \brief The declaration that provides context for this lambda, if the
+ /// actual DeclContext does not suffice. This is used for lambdas that
+ /// occur within default arguments of function parameters within the class
+ /// or within a data member initializer.
+ Decl *ContextDecl;
+
+ /// \brief The list of captures, both explicit and implicit, for this
+ /// lambda.
Capture *Captures;
};
@@ -1457,6 +1464,20 @@ public:
return getLambdaData().ManglingNumber;
}
+ /// \brief Retrieve the declaration that provides additional context for a
+ /// lambda, when the normal declaration context is not specific enough.
+ ///
+ /// Certain contexts (default arguments of in-class function parameters and
+ /// the initializers of data members) have separate name mangling rules for
+ /// lambdas within the Itanium C++ ABI. For these cases, this routine provides
+ /// the declaration in which the lambda occurs, e.g., the function parameter
+ /// or the non-static data member. Otherwise, it returns NULL to imply that
+ /// the declaration context suffices.
+ Decl *getLambdaContextDecl() const {
+ assert(isLambda() && "Not a lambda closure type!");
+ return getLambdaData().ContextDecl;
+ }
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstCXXRecord && K <= lastCXXRecord;
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 0d3b86269f..395fdcd10f 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -1167,7 +1167,8 @@ private:
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace,
- unsigned ManglingNumber);
+ unsigned ManglingNumber,
+ Decl *ContextDecl);
/// \brief Construct an empty lambda expression.
LambdaExpr(EmptyShell Empty, unsigned NumCaptures, bool HasArrayIndexVars)
@@ -1206,7 +1207,8 @@ public:
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace,
- unsigned ManglingNumber);
+ unsigned ManglingNumber,
+ Decl *ContextDecl);
/// \brief Construct a new lambda expression that will be deserialized from
/// an external source.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 5df80891f3..29d3862b4b 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -572,11 +572,37 @@ public:
/// is indeed an unevaluated context.
llvm::SmallVector<LambdaExpr *, 2> 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 context information used to mangle lambda expressions
+ /// within this context.
+ ///
+ /// This mangling information is allocated lazily, since most contexts
+ /// do not have lambda expressions.
+ LambdaMangleContext *LambdaMangle;
+
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
unsigned NumCleanupObjects,
- bool ParentNeedsCleanups)
+ bool ParentNeedsCleanups,
+ Decl *LambdaContextDecl)
: Context(Context), ParentNeedsCleanups(ParentNeedsCleanups),
- NumCleanupObjects(NumCleanupObjects) { }
+ NumCleanupObjects(NumCleanupObjects),
+ LambdaContextDecl(LambdaContextDecl), LambdaMangle() { }
+
+ ~ExpressionEvaluationContextRecord() {
+ delete 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;
+ }
};
/// A stack of expression evaluation contexts.
@@ -2288,7 +2314,8 @@ public:
void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
Expr **Args, unsigned NumArgs);
- void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext);
+ void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
+ Decl *LambdaContextDecl = 0);
void PopExpressionEvaluationContext();
@@ -3558,6 +3585,7 @@ public:
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
@@ -6541,9 +6569,10 @@ class EnterExpressionEvaluationContext {
public:
EnterExpressionEvaluationContext(Sema &Actions,
- Sema::ExpressionEvaluationContext NewContext)
+ Sema::ExpressionEvaluationContext NewContext,
+ Decl *LambdaContextDecl = 0)
: Actions(Actions) {
- Actions.PushExpressionEvaluationContext(NewContext);
+ Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl);
}
~EnterExpressionEvaluationContext() {
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index cbc5950f83..98664b2a7c 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -765,7 +765,8 @@ LambdaExpr::LambdaExpr(QualType T,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace,
- unsigned ManglingNumber)
+ unsigned ManglingNumber,
+ Decl *ContextDecl)
: Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
T->isDependentType(), T->isDependentType(), T->isDependentType(),
/*ContainsUnexpandedParameterPack=*/false),
@@ -787,6 +788,7 @@ LambdaExpr::LambdaExpr(QualType T,
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) {
@@ -827,7 +829,8 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
ArrayRef<VarDecl *> ArrayIndexVars,
ArrayRef<unsigned> ArrayIndexStarts,
SourceLocation ClosingBrace,
- unsigned ManglingNumber) {
+ unsigned ManglingNumber,
+ Decl *ContextDecl) {
// Determine the type of the expression (i.e., the type of the
// function object we're creating).
QualType T = Context.getTypeDeclType(Class);
@@ -840,7 +843,7 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault,
Captures, ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars, ArrayIndexStarts,
- ClosingBrace, ManglingNumber);
+ ClosingBrace, ManglingNumber, ContextDecl);
}
LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures,
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index a0bb6c74c3..93ebcc50cf 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -40,14 +40,38 @@ using namespace clang;
namespace {
+/// \brief Retrieve the declaration context that should be used when mangling
+/// the given declaration.
+static const DeclContext *getEffectiveDeclContext(const Decl *D) {
+ // The ABI assumes that lambda closure types that occur within
+ // default arguments live in the context of the function. However, due to
+ // the way in which Clang parses and creates function declarations, this is
+ // not the case: the lambda closure type ends up living in the context
+ // where the function itself resides, because the function declaration itself
+ // had not yet been created. Fix the context here.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (RD->isLambda())
+ if (ParmVarDecl *ContextParam
+ = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
+ return ContextParam->getDeclContext();
+ }
+
+ return D->getDeclContext();
+}
+
+static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
+ return getEffectiveDeclContext(cast<Decl>(DC));
+}
+
static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
const DeclContext *DC = dyn_cast<DeclContext>(ND);
if (!DC)
- DC = ND->getDeclContext();
+ DC = getEffectiveDeclContext(ND);
while (!DC->isNamespace() && !DC->isTranslationUnit()) {
- if (isa<FunctionDecl>(DC->getParent()))
+ const DeclContext *Parent = getEffectiveDeclContext(cast<Decl>(DC));
+ if (isa<FunctionDecl>(Parent))
return dyn_cast<CXXRecordDecl>(DC);
- DC = DC->getParent();
+ DC = Parent;
}
return 0;
}
@@ -63,7 +87,7 @@ static const NamedDecl *getStructor(const NamedDecl *decl) {
const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl);
return (fn ? getStructor(fn) : decl);
}
-
+
static const unsigned UnknownArity = ~0U;
class ItaniumMangleContext : public MangleContext {
@@ -279,6 +303,7 @@ private:
void mangleUnscopedTemplateName(TemplateName);
void mangleSourceName(const IdentifierInfo *II);
void mangleLocalName(const NamedDecl *ND);
+ void mangleLambda(const CXXRecordDecl *Lambda);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
bool NoFunction=false);
void mangleNestedName(const TemplateDecl *TD,
@@ -339,8 +364,8 @@ private:
static bool isInCLinkageSpecification(const Decl *D) {
D = D->getCanonicalDecl();
- for (const DeclContext *DC = D->getDeclContext();
- !DC->isTranslationUnit(); DC = DC->getParent()) {
+ for (const DeclContext *DC = getEffectiveDeclContext(D);
+ !DC->isTranslationUnit(); DC = getEffectiveParentContext(DC)) {
if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
}
@@ -372,17 +397,17 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
// Variables at global scope with non-internal linkage are not mangled
if (!FD) {
- const DeclContext *DC = D->getDeclContext();
+ const DeclContext *DC = getEffectiveDeclContext(D);
// Check for extern variable declared locally.
if (DC->isFunctionOrMethod() && D->hasLinkage())
while (!DC->isNamespace() && !DC->isTranslationUnit())
- DC = DC->getParent();
+ DC = getEffectiveParentContext(DC);
if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage)
return false;
}
// Class members are always mangled.
- if (D->getDeclContext()->isRecord())
+ if (getEffectiveDeclContext(D)->isRecord())
return true;
// C functions and "main" are not mangled.
@@ -465,7 +490,7 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
while (isa<LinkageSpecDecl>(DC)) {
- DC = DC->getParent();
+ DC = getEffectiveParentContext(DC);
}
return DC;
@@ -473,7 +498,8 @@ static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
/// isStd - Return whether a given namespace is the 'std' namespace.
static bool isStd(const NamespaceDecl *NS) {
- if (!IgnoreLinkageSpecDecls(NS->getParent())->isTranslationUnit())
+ if (!IgnoreLinkageSpecDecls(getEffectiveParentContext(NS))
+ ->isTranslationUnit())
return false;
const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
@@ -515,20 +541,20 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
// ::= <unscoped-template-name> <template-args>
// ::= <local-name>
//
- const DeclContext *DC = ND->getDeclContext();
+ const DeclContext *DC = getEffectiveDeclContext(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())
while (!DC->isNamespace() && !DC->isTranslationUnit())
- DC = DC->getParent();
+ DC = getEffectiveParentContext(DC);
else if (GetLocalClassDecl(ND)) {
mangleLocalName(ND);
return;
}
while (isa<LinkageSpecDecl>(DC))
- DC = DC->getParent();
+ DC = getEffectiveParentContext(DC);
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
// Check if we have a template.
@@ -554,7 +580,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
void CXXNameMangler::mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
- const DeclContext *DC = IgnoreLinkageSpecDecls(TD->getDeclContext());
+ const DeclContext *DC = IgnoreLinkageSpecDecls(getEffectiveDeclContext(TD));
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD);
@@ -568,7 +594,7 @@ void CXXNameMangler::mangleName(const TemplateDecl *TD,
void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) {
// <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> # ::std::
- if (isStdNamespace(ND->getDeclContext()))
+ if (isStdNamespace(getEffectiveDeclContext(ND)))
Out << "St";
mangleUnqualifiedName(ND);
@@ -1028,7 +1054,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// This naming convention is the same as that followed by GCC,
// though it shouldn't actually matter.
if (ND && ND->getLinkage() == InternalLinkage &&
- ND->getDeclContext()->isFileContext())
+ getEffectiveDeclContext(ND)->isFileContext())
Out << 'L';
mangleSourceName(II);
@@ -1089,28 +1115,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'.
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
if (Record->isLambda()) {
- // FIXME: Figure out if we're in a function body, default argument,
- // or initializer for a class member.
-
- Out << "Ul";
- DeclarationName Name
- = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
- const FunctionProtoType *Proto
- = cast<CXXMethodDecl>(*Record->lookup(Name).first)->getType()->
- getAs<FunctionProtoType>();
- mangleBareFunctionType(Proto, /*MangleReturnType=*/false);
- Out << "E";
-
- // The number is omitted for the first closure type with a given
- // <lambda-sig> in a given context; it is n-2 for the nth closure type
- // (in lexical order) with that same <lambda-sig> and context.
- //
- // The AST keeps track of the number for us.
- if (unsigned Number = Record->getLambdaManglingNumber()) {
- if (Number > 1)
- mangleNumber(Number - 2);
- }
- Out << '_';
+ mangleLambda(Record);
break;
}
}
@@ -1243,8 +1248,10 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
// <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 DeclContext *DC = ND->getDeclContext();
+ const DeclContext *DC = getEffectiveDeclContext(ND);
if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) {
// Don't add objc method name mangling to locally declared function
mangleUnqualifiedName(ND);
@@ -1256,23 +1263,46 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
mangleObjCMethodName(MD);
} else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) {
- mangleFunctionEncoding(cast<FunctionDecl>(RD->getDeclContext()));
+ mangleFunctionEncoding(cast<FunctionDecl>(getEffectiveDeclContext(RD)));
Out << 'E';
+ // The parameter number is omitted for the last parameter, 0 for the
+ // second-to-last parameter, 1 for the third-to-last parameter, etc. The
+ // <entity name> will of course contain a <closure-type-name>: Its
+ // numbering will be local to the particular argument in which it appears
+ // -- other default arguments do not affect its encoding.
+ bool SkipDiscriminator = false;
+ if (RD->isLambda()) {
+ if (const ParmVarDecl *Parm
+ = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) {
+ if (const FunctionDecl *Func
+ = dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
+ Out << 'd';
+ unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex();
+ if (Num > 1)
+ mangleNumber(Num - 2);
+ Out << '_';
+ SkipDiscriminator = true;
+ }
+ }
+ }
+
// Mangle the name relative to the closest enclosing function.
if (ND == RD) // equality ok because RD derived from ND above
mangleUnqualifiedName(ND);
else
mangleNestedName(ND, DC, true /*NoFunction*/);
- unsigned disc;
- if (Context.getNextDiscriminator(RD, disc)) {
- if (disc < 10)
- Out << '_' << disc;
- else
- Out << "__" << disc << '_';
+ if (!SkipDiscriminator) {
+ unsigned disc;
+ if (Context.getNextDiscriminator(RD, disc)) {
+ if (disc < 10)
+ Out << '_' << disc;
+ else
+ Out << "__" << disc << '_';
+ }
}
-
+
return;
}
else
@@ -1282,6 +1312,31 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
mangleUnqualifiedName(ND);
}
+void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
+ // FIXME: Figure out if we're in a function body, default argument,
+ // or initializer for a class member.
+
+ Out << "Ul";
+ DeclarationName Name
+ = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ const FunctionProtoType *Proto
+ = cast<CXXMethodDecl>(*Lambda->lookup(Name).first)->getType()->
+ getAs<FunctionProtoType>();
+ mangleBareFunctionType(Proto, /*MangleReturnType=*/false);
+ Out << "E";
+
+ // The number is omitted for the first closure type with a given
+ // <lambda-sig> in a given context; it is n-2 for the nth closure type
+ // (in lexical order) with that same <lambda-sig> and context.
+ //
+ // The AST keeps track of the number for us.
+ if (unsigned Number = Lambda->getLambdaManglingNumber()) {
+ if (Number > 1)
+ mangleNumber(Number - 2);
+ }
+ Out << '_';
+}
+
void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
switch (qualifier->getKind()) {
case NestedNameSpecifier::Global:
@@ -1322,13 +1377,13 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
// ::= <substitution>
while (isa<LinkageSpecDecl>(DC))
- DC = DC->getParent();
+ DC = getEffectiveParentContext(DC);
if (DC->isTranslationUnit())
return;
if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) {
- manglePrefix(DC->getParent(), NoFunction);
+ manglePrefix(getEffectiveParentContext(DC), NoFunction);
SmallString<64> Name;
llvm::raw_svector_ostream NameStream(Name);
Context.mangleBlock(Block, NameStream);
@@ -1352,7 +1407,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC))
mangleObjCMethodName(Method);
else {
- manglePrefix(DC->getParent(), NoFunction);
+ manglePrefix(getEffectiveParentContext(DC), NoFunction);
mangleUnqualifiedName(cast<NamedDecl>(DC));
}
@@ -1399,7 +1454,7 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
return;
}
- manglePrefix(ND->getDeclContext());
+ manglePrefix(getEffectiveDeclContext(ND));
mangleUnqualifiedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
@@ -3159,7 +3214,7 @@ static bool isCharSpecialization(QualType T, const char *Name) {
if (!SD)
return false;
- if (!isStdNamespace(SD->getDeclContext()))
+ if (!isStdNamespace(getEffectiveDeclContext(SD)))
return false;
const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
@@ -3201,7 +3256,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
}
if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
- if (!isStdNamespace(TD->getDeclContext()))
+ if (!isStdNamespace(getEffectiveDeclContext(TD)))
return false;
// <substitution> ::= Sa # ::std::allocator
@@ -3219,7 +3274,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
if (const ClassTemplateSpecializationDecl *SD =
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
- if (!isStdNamespace(SD->getDeclContext()))
+ if (!isStdNamespace(getEffectiveDeclContext(SD)))
return false;
// <substitution> ::= Ss # ::std::basic_string<char,
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 51dc5c88f8..8ed058787e 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -297,7 +297,8 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
Scope::FunctionPrototypeScope|Scope::DeclScope);
for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
// Introduce the parameter into scope.
- Actions.ActOnDelayedCXXMethodParameter(getCurScope(), LM.DefaultArgs[I].Param);
+ Actions.ActOnDelayedCXXMethodParameter(getCurScope(),
+ LM.DefaultArgs[I].Param);
if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
// Save the current token position.
@@ -317,7 +318,8 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
// The argument isn't actually potentially evaluated unless it is
// used.
EnterExpressionEvaluationContext Eval(Actions,
- Sema::PotentiallyEvaluatedIfUsed);
+ Sema::PotentiallyEvaluatedIfUsed,
+ LM.DefaultArgs[I].Param);
ExprResult DefArgResult(ParseAssignmentExpression());
if (DefArgResult.isInvalid())
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 0b98274002..4193890021 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -4520,7 +4520,8 @@ void Parser::ParseParameterDeclarationClause(
// The argument isn't actually potentially evaluated unless it is
// used.
EnterExpressionEvaluationContext Eval(Actions,
- Sema::PotentiallyEvaluatedIfUsed);
+ Sema::PotentiallyEvaluatedIfUsed,
+ Param);
ExprResult DefArgResult(ParseAssignmentExpression());
if (DefArgResult.isInvalid()) {
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 716ffd131b..6a83518bc0 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -111,7 +111,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
&Context);
ExprEvalContexts.push_back(
- ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0, false));
+ ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0, false, 0));
FunctionScopes.push_back(new FunctionScopeInfo(Diags));
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3f1fabcaa3..1008a3ab43 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -9275,11 +9275,13 @@ ExprResult Sema::TranformToPotentiallyEvaluated(Expr *E) {
}
void
-Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
+Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
+ Decl *LambdaContextDecl) {
ExprEvalContexts.push_back(
ExpressionEvaluationContextRecord(NewContext,
ExprCleanupObjects.size(),
- ExprNeedsCleanups));
+ ExprNeedsCleanups,
+ LambdaContextDecl));
ExprNeedsCleanups = false;
if (!MaybeODRUseExprs.empty())
std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 6d54d403aa..047a28436f 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -485,6 +485,7 @@ static void addBlockPointerConversion(Sema &S,
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope,
llvm::Optional<unsigned> ManglingNumber,
+ Decl *ContextDecl,
bool IsInstantiation) {
// Leave the expression-evaluation context.
DiscardCleanupsInEvaluationContext();
@@ -638,8 +639,34 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
// If we don't already have a mangling number for this lambda expression,
// allocate one now.
if (!ManglingNumber) {
- // FIXME: Default arguments, data member initializers are special.
- ManglingNumber = Context.getLambdaManglingNumber(CallOperator);
+ ContextDecl = ExprEvalContexts.back().LambdaContextDecl;
+
+ // FIXME: Data member initializers.
+ enum ContextKind {
+ Normal,
+ DefaultArgument
+ } Kind = Normal;
+
+ // Default arguments of member function parameters that appear in a class
+ // definition receive special treatment. Identify them.
+ if (ParmVarDecl *Param = dyn_cast_or_null<ParmVarDecl>(ContextDecl)) {
+ if (const DeclContext *LexicalDC
+ = Param->getDeclContext()->getLexicalParent())
+ if (LexicalDC->isRecord())
+ Kind = DefaultArgument;
+ }
+
+ switch (Kind) {
+ case Normal:
+ ManglingNumber = Context.getLambdaManglingNumber(CallOperator);
+ ContextDecl = 0;
+ break;
+
+ case DefaultArgument:
+ ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
+ .getManglingNumber(CallOperator);
+ break;
+ }
}
LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
@@ -647,7 +674,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars,
ArrayIndexStarts, Body->getLocEnd(),
- *ManglingNumber);
+ *ManglingNumber, ContextDecl);
// C++11 [expr.prim.lambda]p2:
// A lambda-expression shall not appear in an unevaluated operand
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 7e095f7336..7e775f55e0 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -7768,10 +7768,14 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
/*IsInstantiation=*/true);
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);
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index b5e9c3d179..c2a93b99fa 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1110,6 +1110,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Lambda.NumCaptures = Record[Idx++];
Lambda.NumExplicitCaptures = Record[Idx++];
Lambda.ManglingNumber = Record[Idx++];
+ Lambda.ContextDecl = ReadDecl(Record, Idx);
Lambda.Captures
= (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures);
Capture *ToCapture = Lambda.Captures;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index add89ea8e2..5c3a1e93f6 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -4333,6 +4333,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Lambda.NumCaptures);
Record.push_back(Lambda.NumExplicitCaptures);
Record.push_back(Lambda.ManglingNumber);
+ AddDeclRef(Lambda.ContextDecl, Record);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
LambdaExpr::Capture &Capture = Lambda.Captures[I];
AddSourceLocation(Capture.getLocation(), Record);
diff --git a/test/CodeGenCXX/mangle-lambdas.cpp b/test/CodeGenCXX/mangle-lambdas.cpp
index b2376648c2..de8360d730 100644
--- a/test/CodeGenCXX/mangle-lambdas.cpp
+++ b/test/CodeGenCXX/mangle-lambdas.cpp
@@ -14,9 +14,64 @@ inline void inline_func(int n) {
// CHECK: call i32 @_ZZ11inline_funciENKUliE_clEi
int l = [=] (int x) -> int { return x + i; }(n);
- // CHECK: ret void