diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 4 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 29 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 6 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 39 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 9 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 165 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 33 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 6 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 1 | ||||
-rw-r--r-- | test/CodeGenCXX/mangle-lambdas.cpp | 57 |
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 + int inner(int i = []{ return 1; }()); + // CHECK: call i32 @_ZZ11inline_funciENKUlvE2_clEv + // CHECK-NEXT: call i32 @_Z5inneri + inner(); + + // CHECK-NEXT: ret void } void call_inline_func() { inline_func(17); } + +struct S { + void f(int = []{return 1;}() + + []{return 2;}(), + int = []{return 3;}()); + void g(int, int); +}; + +void S::g(int i = []{return 1;}(), + int j = []{return 2; }()) {} + +// CHECK: define void @_Z6test_S1S +void test_S(S s) { + // CHECK: call i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv + // CHECK-NEXT: call i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv + // CHECK-NEXT: add nsw i32 + // CHECK-NEXT: call i32 @_ZZN1S1fEiiEd_NKUlvE_clEv + // CHECK-NEXT: call void @_ZN1S1fEii + s.f(); + + // NOTE: These manglings don't actually matter that much, because + // the lambdas in the default arguments of g() won't be seen by + // multiple translation units. We check them mainly to ensure that they don't + // get the special mangling for lambdas in in-class default arguments. + // CHECK: call i32 @_ZNK1SUlvE_clEv + // CHECK-NEXT: call i32 @_ZNK1SUlvE0_clEv + // CHECK- |