Author: hamzasood Date: Sat May 4 03:49:46 2019 New Revision: 359967 URL: http://llvm.org/viewvc/llvm-project?rev=359967&view=rev Log: [c++20] Implement P0428R2 - Familiar template syntax for generic lambdas
Differential Revision: https://reviews.llvm.org/D36527 Added: cfe/trunk/test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp cfe/trunk/test/PCH/cxx2a-template-lambdas.cpp cfe/trunk/test/Parser/cxx2a-template-lambdas.cpp cfe/trunk/test/SemaCXX/cxx2a-template-lambdas.cpp cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp Modified: cfe/trunk/include/clang/AST/DeclCXX.h cfe/trunk/include/clang/AST/DeclTemplate.h cfe/trunk/include/clang/AST/ExprCXX.h cfe/trunk/include/clang/AST/RecursiveASTVisitor.h cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td cfe/trunk/include/clang/Parse/Parser.h cfe/trunk/include/clang/Sema/ScopeInfo.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/DeclCXX.cpp cfe/trunk/lib/AST/DeclPrinter.cpp cfe/trunk/lib/AST/ExprCXX.cpp cfe/trunk/lib/AST/ItaniumMangle.cpp cfe/trunk/lib/AST/StmtPrinter.cpp cfe/trunk/lib/AST/TypePrinter.cpp cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Sema/Sema.cpp cfe/trunk/lib/Sema/SemaLambda.cpp cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p4.cpp cfe/trunk/test/Index/print-display-names.cpp cfe/trunk/test/PCH/cxx11-lambdas.mm cfe/trunk/test/PCH/cxx1y-lambdas.mm cfe/trunk/unittests/AST/StmtPrinterTest.cpp cfe/trunk/www/cxx_status.html Modified: cfe/trunk/include/clang/AST/DeclCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h (original) +++ cfe/trunk/include/clang/AST/DeclCXX.h Sat May 4 03:49:46 2019 @@ -1221,6 +1221,9 @@ public: /// lambda. TemplateParameterList *getGenericLambdaTemplateParameterList() const; + /// Retrieve the lambda template parameters that were specified explicitly. + ArrayRef<NamedDecl *> getLambdaExplicitTemplateParameters() const; + LambdaCaptureDefault getLambdaCaptureDefault() const { assert(isLambda()); return static_cast<LambdaCaptureDefault>(getLambdaData().CaptureDefault); Modified: cfe/trunk/include/clang/AST/DeclTemplate.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclTemplate.h (original) +++ cfe/trunk/include/clang/AST/DeclTemplate.h Sat May 4 03:49:46 2019 @@ -176,6 +176,11 @@ public: return SourceRange(TemplateLoc, RAngleLoc); } + void print(raw_ostream &Out, const ASTContext &Context, + bool OmitTemplateKW = false) const; + void print(raw_ostream &Out, const ASTContext &Context, + const PrintingPolicy &Policy, bool OmitTemplateKW = false) const; + public: // FIXME: workaround for MSVC 2013; remove when no longer needed using FixedSizeStorageOwner = TrailingObjects::FixedSizeStorageOwner; Modified: cfe/trunk/include/clang/AST/ExprCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ExprCXX.h (original) +++ cfe/trunk/include/clang/AST/ExprCXX.h Sat May 4 03:49:46 2019 @@ -1899,6 +1899,10 @@ public: /// parameter list associated with it, or else return null. TemplateParameterList *getTemplateParameterList() const; + /// Get the template parameters were explicitly specified (as opposed to being + /// invented by use of an auto parameter). + ArrayRef<NamedDecl *> getExplicitTemplateParameters() const; + /// Whether this is a generic lambda. bool isGenericLambda() const { return getTemplateParameterList(); } Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original) +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Sat May 4 03:49:46 2019 @@ -2423,6 +2423,10 @@ DEF_TRAVERSE_STMT(LambdaExpr, { TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>(); + for (Decl *D : S->getExplicitTemplateParameters()) { + // Visit explicit template parameters. + TRY_TO(TraverseDecl(D)); + } if (S->hasExplicitParameters()) { // Visit parameters. for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Sat May 4 03:49:46 2019 @@ -886,6 +886,16 @@ def warn_cxx14_compat_constexpr_on_lambd def ext_constexpr_on_lambda_cxx17 : ExtWarn< "'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>; + // C++2a template lambdas + def ext_lambda_template_parameter_list: ExtWarn< + "explicit template parameter list for lambdas is a C++2a extension">, + InGroup<CXX2a>; +def warn_cxx17_compat_lambda_template_parameter_list: Warning< + "explicit template parameter list for lambdas is incompatible with " + "C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore; + def err_lambda_template_parameter_list_empty : Error< + "lambda template parameter list cannot be empty">; + // Availability attribute def err_expected_version : Error< "expected a version of the form 'major[.minor[.subminor]]'">; Modified: cfe/trunk/include/clang/Parse/Parser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Parser.h (original) +++ cfe/trunk/include/clang/Parse/Parser.h Sat May 4 03:49:46 2019 @@ -250,7 +250,13 @@ class Parser : public CodeCompletionHand Depth += D; AddedLevels += D; } + void setAddedDepth(unsigned D) { + Depth = Depth - AddedLevels + D; + AddedLevels = D; + } + unsigned getDepth() const { return Depth; } + unsigned getOriginalDepth() const { return Depth - AddedLevels; } }; /// Factory object for creating ParsedAttr objects. Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/ScopeInfo.h (original) +++ cfe/trunk/include/clang/Sema/ScopeInfo.h Sat May 4 03:49:46 2019 @@ -816,16 +816,24 @@ public: /// each 'auto' parameter, during initial AST construction. unsigned AutoTemplateParameterDepth = 0; - /// Store the list of the auto parameters for a generic lambda. - /// If this is a generic lambda, store the list of the auto - /// parameters converted into TemplateTypeParmDecls into a vector - /// that can be used to construct the generic lambda's template - /// parameter list, during initial AST construction. - SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams; + /// The number of parameters in the template parameter list that were + /// explicitly specified by the user, as opposed to being invented by use + /// of an auto parameter. + unsigned NumExplicitTemplateParams = 0; + + /// Source range covering the explicit template parameter list (if it exists). + SourceRange ExplicitTemplateParamsRange; + + /// Store the list of the template parameters for a generic lambda. + /// If this is a generic lambda, this holds the explicit template parameters + /// followed by the auto parameters converted into TemplateTypeParmDecls. + /// It can be used to construct the generic lambda's template parameter list + /// during initial AST construction. + SmallVector<NamedDecl*, 4> TemplateParams; /// If this is a generic lambda, and the template parameter - /// list has been created (from the AutoTemplateParams) then - /// store a reference to it (cache it to avoid reconstructing it). + /// list has been created (from the TemplateParams) then store + /// a reference to it (cache it to avoid reconstructing it). TemplateParameterList *GLTemplateParameterList = nullptr; /// Contains all variable-referring-expressions (i.e. DeclRefExprs @@ -878,9 +886,9 @@ public: } /// Is this scope known to be for a generic lambda? (This will be false until - /// we parse the first 'auto'-typed parameter. + /// we parse a template parameter list or the first 'auto'-typed parameter). bool isGenericLambda() const { - return !AutoTemplateParams.empty() || GLTemplateParameterList; + return !TemplateParams.empty() || GLTemplateParameterList; } /// Add a variable that might potentially be captured by the Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Sat May 4 03:49:46 2019 @@ -5723,6 +5723,12 @@ public: /// given lambda. void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); + /// \brief This is called after parsing the explicit template parameter list + /// on a lambda (if it exists) in C++2a. + void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc, + ArrayRef<NamedDecl *> TParams, + SourceLocation RAngleLoc); + /// Introduce the lambda parameters into scope. void addLambdaParameters( ArrayRef<LambdaIntroducer::LambdaCapture> Captures, Modified: cfe/trunk/lib/AST/DeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp (original) +++ cfe/trunk/lib/AST/DeclCXX.cpp Sat May 4 03:49:46 2019 @@ -1421,13 +1421,30 @@ void CXXRecordDecl::getCaptureFields( TemplateParameterList * CXXRecordDecl::getGenericLambdaTemplateParameterList() const { - if (!isLambda()) return nullptr; + if (!isGenericLambda()) return nullptr; CXXMethodDecl *CallOp = getLambdaCallOperator(); if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate()) return Tmpl->getTemplateParameters(); return nullptr; } +ArrayRef<NamedDecl *> +CXXRecordDecl::getLambdaExplicitTemplateParameters() const { + TemplateParameterList *List = getGenericLambdaTemplateParameterList(); + if (!List) + return {}; + + assert(std::is_partitioned(List->begin(), List->end(), + [](const NamedDecl *D) { return !D->isImplicit(); }) + && "Explicit template params should be ordered before implicit ones"); + + const auto ExplicitEnd = std::lower_bound(List->begin(), List->end(), false, + [](const NamedDecl *D, bool) { + return !D->isImplicit(); + }); + return llvm::makeArrayRef(List->begin(), ExplicitEnd); +} + Decl *CXXRecordDecl::getLambdaContextDecl() const { assert(isLambda() && "Not a lambda closure type!"); ExternalASTSource *Source = getParentASTContext().getExternalSource(); Modified: cfe/trunk/lib/AST/DeclPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclPrinter.cpp (original) +++ cfe/trunk/lib/AST/DeclPrinter.cpp Sat May 4 03:49:46 2019 @@ -15,6 +15,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -105,7 +106,8 @@ namespace { void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D); void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D); - void printTemplateParameters(const TemplateParameterList *Params); + void printTemplateParameters(const TemplateParameterList *Params, + bool OmitTemplateKW = false); void printTemplateArguments(const TemplateArgumentList &Args, const TemplateParameterList *Params = nullptr); void prettyPrintAttributes(Decl *D); @@ -126,6 +128,18 @@ void Decl::print(raw_ostream &Out, const Printer.Visit(const_cast<Decl*>(this)); } +void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context, + bool OmitTemplateKW) const { + print(Out, Context, Context.getPrintingPolicy(), OmitTemplateKW); +} + +void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context, + const PrintingPolicy &Policy, + bool OmitTemplateKW) const { + DeclPrinter Printer(Out, Policy, Context); + Printer.printTemplateParameters(this, OmitTemplateKW); +} + static QualType GetBaseType(QualType T) { // FIXME: This should be on the Type class! QualType BaseType = T; @@ -1002,25 +1016,35 @@ void DeclPrinter::VisitLinkageSpecDecl(L Visit(*D->decls_begin()); } -void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params) { +void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params, + bool OmitTemplateKW) { assert(Params); - Out << "template <"; + if (!OmitTemplateKW) + Out << "template "; + Out << '<'; + + bool NeedComma = false; + for (const Decl *Param : *Params) { + if (Param->isImplicit()) + continue; - for (unsigned i = 0, e = Params->size(); i != e; ++i) { - if (i != 0) + if (NeedComma) Out << ", "; + else + NeedComma = true; - const Decl *Param = Params->getParam(i); if (auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { if (TTP->wasDeclaredWithTypename()) - Out << "typename "; + Out << "typename"; else - Out << "class "; + Out << "class"; if (TTP->isParameterPack()) - Out << "..."; + Out << " ..."; + else if (!TTP->getName().empty()) + Out << ' '; Out << *TTP; @@ -1045,7 +1069,9 @@ void DeclPrinter::printTemplateParameter } } - Out << "> "; + Out << '>'; + if (!OmitTemplateKW) + Out << ' '; } void DeclPrinter::printTemplateArguments(const TemplateArgumentList &Args, Modified: cfe/trunk/lib/AST/ExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprCXX.cpp (original) +++ cfe/trunk/lib/AST/ExprCXX.cpp Sat May 4 03:49:46 2019 @@ -1204,7 +1204,11 @@ CXXMethodDecl *LambdaExpr::getCallOperat TemplateParameterList *LambdaExpr::getTemplateParameterList() const { CXXRecordDecl *Record = getLambdaClass(); return Record->getGenericLambdaTemplateParameterList(); +} +ArrayRef<NamedDecl *> LambdaExpr::getExplicitTemplateParameters() const { + const CXXRecordDecl *Record = getLambdaClass(); + return Record->getLambdaExplicitTemplateParameters(); } CompoundStmt *LambdaExpr::getBody() const { Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Sat May 4 03:49:46 2019 @@ -486,6 +486,7 @@ private: const AbiTagList *AdditionalAbiTags); void mangleBlockForPrefix(const BlockDecl *Block); void mangleUnqualifiedBlock(const BlockDecl *Block); + void mangleTemplateParamDecl(const NamedDecl *Decl); void mangleLambda(const CXXRecordDecl *Lambda); void mangleNestedName(const NamedDecl *ND, const DeclContext *DC, const AbiTagList *AdditionalAbiTags, @@ -1372,7 +1373,8 @@ void CXXNameMangler::mangleUnqualifiedNa // <unnamed-type-name> ::= <closure-type-name> // // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ - // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'. + // <lambda-sig> ::= <template-param-decl>* <parameter-type>+ + // # Parameter types or 'v' for 'void'. if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) { if (Record->isLambda() && Record->getLambdaManglingNumber()) { assert(!AdditionalAbiTags && @@ -1678,6 +1680,24 @@ void CXXNameMangler::mangleUnqualifiedBl Out << '_'; } +// <template-param-decl> +// ::= Ty # template type parameter +// ::= Tn <type> # template non-type parameter +// ::= Tt <template-param-decl>* E # template template parameter +void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) { + if (isa<TemplateTypeParmDecl>(Decl)) { + Out << "Ty"; + } else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) { + Out << "Tn"; + mangleType(Tn->getType()); + } else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) { + Out << "Tt"; + for (auto *Param : *Tt->getTemplateParameters()) + mangleTemplateParamDecl(Param); + Out << "E"; + } +} + void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { // If the context of a closure type is an initializer for a class member // (static or nonstatic), it is encoded in a qualified name with a final @@ -1705,6 +1725,8 @@ void CXXNameMangler::mangleLambda(const } Out << "Ul"; + for (auto *D : Lambda->getLambdaExplicitTemplateParameters()) + mangleTemplateParamDecl(D); const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()-> getAs<FunctionProtoType>(); mangleBareFunctionType(Proto, /*MangleReturnType=*/false, Modified: cfe/trunk/lib/AST/StmtPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/lib/AST/StmtPrinter.cpp (original) +++ cfe/trunk/lib/AST/StmtPrinter.cpp Sat May 4 03:49:46 2019 @@ -1900,8 +1900,14 @@ void StmtPrinter::VisitLambdaExpr(Lambda } OS << ']'; + if (!Node->getExplicitTemplateParameters().empty()) { + Node->getTemplateParameterList()->print( + OS, Node->getLambdaClass()->getASTContext(), + /*OmitTemplateKW*/true); + } + if (Node->hasExplicitParameters()) { - OS << " ("; + OS << '('; CXXMethodDecl *Method = Node->getCallOperator(); NeedComma = false; for (const auto *P : Method->parameters()) { @@ -1936,9 +1942,8 @@ void StmtPrinter::VisitLambdaExpr(Lambda } // Print the body. - CompoundStmt *Body = Node->getBody(); OS << ' '; - PrintStmt(Body); + PrintRawCompoundStmt(Node->getBody()); } void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) { Modified: cfe/trunk/lib/AST/TypePrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/lib/AST/TypePrinter.cpp (original) +++ cfe/trunk/lib/AST/TypePrinter.cpp Sat May 4 03:49:46 2019 @@ -1217,8 +1217,18 @@ void TypePrinter::printTemplateTypeParmB raw_ostream &OS) { if (IdentifierInfo *Id = T->getIdentifier()) OS << Id->getName(); - else - OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); + else { + bool IsLambdaAutoParam = false; + if (auto D = T->getDecl()) { + if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext())) + IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda(); + } + + if (IsLambdaAutoParam) + OS << "auto"; + else + OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); + } spaceBeforePlaceHolder(OS); } Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Sat May 4 03:49:46 2019 @@ -638,6 +638,8 @@ ExprResult Parser::ParseCXXIdExpression( /// /// lambda-expression: /// lambda-introducer lambda-declarator[opt] compound-statement +/// lambda-introducer '<' template-parameter-list '>' +/// lambda-declarator[opt] compound-statement /// /// lambda-introducer: /// '[' lambda-capture[opt] ']' @@ -1121,6 +1123,33 @@ ExprResult Parser::ParseLambdaExpression << A.getName()->getName(); }; + // FIXME: Consider allowing this as an extension for GCC compatibiblity. + const bool HasExplicitTemplateParams = Tok.is(tok::less); + ParseScope TemplateParamScope(this, Scope::TemplateParamScope, + /*EnteredScope=*/HasExplicitTemplateParams); + if (HasExplicitTemplateParams) { + Diag(Tok, getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_lambda_template_parameter_list + : diag::ext_lambda_template_parameter_list); + + SmallVector<NamedDecl*, 4> TemplateParams; + SourceLocation LAngleLoc, RAngleLoc; + if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), + TemplateParams, LAngleLoc, RAngleLoc)) { + Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); + return ExprError(); + } + + if (TemplateParams.empty()) { + Diag(RAngleLoc, + diag::err_lambda_template_parameter_list_empty); + } else { + Actions.ActOnLambdaExplicitTemplateParameterList( + LAngleLoc, TemplateParams, RAngleLoc); + ++CurTemplateDepthTracker; + } + } + TypeResult TrailingReturnType; if (Tok.is(tok::l_paren)) { ParseScope PrototypeScope(this, @@ -1137,13 +1166,20 @@ ExprResult Parser::ParseLambdaExpression SourceLocation EllipsisLoc; if (Tok.isNot(tok::r_paren)) { - Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth); + Actions.RecordParsingTemplateParameterDepth( + CurTemplateDepthTracker.getOriginalDepth()); + ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); + // For a generic lambda, each 'auto' within the parameter declaration // clause creates a template type parameter, so increment the depth. + // If we've parsed any explicit template parameters, then the depth will + // have already been incremented. So we make sure that at most a single + // depth level is added. if (Actions.getCurGenericLambda()) - ++CurTemplateDepthTracker; + CurTemplateDepthTracker.setAddedDepth(1); } + T.consumeClose(); SourceLocation RParenLoc = T.getCloseLocation(); SourceLocation DeclEndLoc = RParenLoc; @@ -1298,6 +1334,7 @@ ExprResult Parser::ParseLambdaExpression StmtResult Stmt(ParseCompoundStatementBody()); BodyScope.Exit(); + TemplateParamScope.Exit(); if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid()) return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope()); Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Sat May 4 03:49:46 2019 @@ -1793,7 +1793,7 @@ LambdaScopeInfo *Sema::getCurLambda(bool // an associated template parameter list. LambdaScopeInfo *Sema::getCurGenericLambda() { if (LambdaScopeInfo *LSI = getCurLambda()) { - return (LSI->AutoTemplateParams.size() || + return (LSI->TemplateParams.size() || LSI->GLTemplateParameterList) ? LSI : nullptr; } return nullptr; Modified: cfe/trunk/lib/Sema/SemaLambda.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaLambda.cpp (original) +++ cfe/trunk/lib/Sema/SemaLambda.cpp Sat May 4 03:49:46 2019 @@ -20,6 +20,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" +#include "llvm/ADT/STLExtras.h" using namespace clang; using namespace sema; @@ -225,19 +226,14 @@ Optional<unsigned> clang::getStackIndexO static inline TemplateParameterList * getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) { - if (LSI->GLTemplateParameterList) - return LSI->GLTemplateParameterList; - - if (!LSI->AutoTemplateParams.empty()) { - SourceRange IntroRange = LSI->IntroducerRange; - SourceLocation LAngleLoc = IntroRange.getBegin(); - SourceLocation RAngleLoc = IntroRange.getEnd(); + if (!LSI->GLTemplateParameterList && !LSI->TemplateParams.empty()) { LSI->GLTemplateParameterList = TemplateParameterList::Create( SemaRef.Context, - /*Template kw loc*/ SourceLocation(), LAngleLoc, - llvm::makeArrayRef((NamedDecl *const *)LSI->AutoTemplateParams.data(), - LSI->AutoTemplateParams.size()), - RAngleLoc, nullptr); + /*Template kw loc*/ SourceLocation(), + /*L angle loc*/ LSI->ExplicitTemplateParamsRange.getBegin(), + LSI->TemplateParams, + /*R angle loc*/LSI->ExplicitTemplateParamsRange.getEnd(), + nullptr); } return LSI->GLTemplateParameterList; } @@ -492,6 +488,23 @@ void Sema::finishLambdaExplicitCaptures( LSI->finishedExplicitCaptures(); } +void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc, + ArrayRef<NamedDecl *> TParams, + SourceLocation RAngleLoc) { + LambdaScopeInfo *LSI = getCurLambda(); + assert(LSI && "Expected a lambda scope"); + assert(LSI->NumExplicitTemplateParams == 0 && + "Already acted on explicit template parameters"); + assert(LSI->TemplateParams.empty() && + "Explicit template parameters should come " + "before invented (auto) ones"); + assert(!TParams.empty() && + "No template parameters to act on"); + LSI->TemplateParams.append(TParams.begin(), TParams.end()); + LSI->NumExplicitTemplateParams = TParams.size(); + LSI->ExplicitTemplateParamsRange = {LAngleLoc, RAngleLoc}; +} + void Sema::addLambdaParameters( ArrayRef<LambdaIntroducer::LambdaCapture> Captures, CXXMethodDecl *CallOperator, Scope *CurScope) { @@ -832,17 +845,23 @@ FieldDecl *Sema::buildInitCaptureField(L void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope) { - // Determine if we're within a context where we know that the lambda will - // be dependent, because there are template parameters in scope. - bool KnownDependent = false; LambdaScopeInfo *const LSI = getCurLambda(); assert(LSI && "LambdaScopeInfo should be on stack!"); - // The lambda-expression's closure type might be dependent even if its - // semantic context isn't, if it appears within a default argument of a - // function template. - if (CurScope->getTemplateParamParent()) - KnownDependent = true; + // Determine if we're within a context where we know that the lambda will + // be dependent, because there are template parameters in scope. + bool KnownDependent; + if (LSI->NumExplicitTemplateParams > 0) { + auto *TemplateParamScope = CurScope->getTemplateParamParent(); + assert(TemplateParamScope && + "Lambda with explicit template param list should establish a " + "template param scope"); + assert(TemplateParamScope->getParent()); + KnownDependent = TemplateParamScope->getParent() + ->getTemplateParamParent() != nullptr; + } else { + KnownDependent = CurScope->getTemplateParamParent() != nullptr; + } // Determine the signature of the call operator. TypeSourceInfo *MethodTyInfo; Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Sat May 4 03:49:46 2019 @@ -2935,7 +2935,7 @@ static QualType GetDeclSpecTypeForDeclar sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda(); assert(LSI && "No LambdaScopeInfo on the stack!"); const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth; - const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size(); + const unsigned AutoParameterPosition = LSI->TemplateParams.size(); const bool IsParameterPack = D.hasEllipsis(); // Create the TemplateTypeParmDecl here to retrieve the corresponding @@ -2947,7 +2947,8 @@ static QualType GetDeclSpecTypeForDeclar /*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(), TemplateParameterDepth, AutoParameterPosition, /*Identifier*/ nullptr, false, IsParameterPack); - LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam); + CorrespondingTemplateParam->setImplicit(); + LSI->TemplateParams.push_back(CorrespondingTemplateParam); // Replace the 'auto' in the function parameter with this invented // template type parameter. // FIXME: Retain some type sugar to indicate that this was written Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p4.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p4.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p4.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p4.cpp Sat May 4 03:49:46 2019 @@ -213,8 +213,10 @@ namespace PackExpansionWithinLambda { }; #endif +#if __cplusplus > 201703L // - in a template parameter pack that is a pack expansion - // FIXME: We do not support any way to reach this case yet. + swallow([]<T *...v, template<T *> typename ...W>(W<v> ...wv) { }); +#endif // - in an initializer-list int arr[] = {T().x...}; @@ -279,11 +281,6 @@ namespace PackExpansionWithinLambda { struct T { int x; using U = int; }; void g() { f<T>(1, 2, 3); } - template<typename ...T, typename ...U> void pack_in_lambda(U ...u) { // expected-note {{here}} - // FIXME: Move this test into 'f' above once we support this syntax. - []<T *...v, template<T *> typename ...U>(U<v> ...uv) {}; // expected-error {{expected body of lambda}} expected-error {{does not refer to a value}} - } - template<typename ...T> void pack_expand_attr() { // FIXME: Move this test into 'f' above once we support this. [[gnu::aligned(alignof(T))...]] int x; // expected-error {{cannot be used as an attribute pack}} expected-error {{unexpanded}} Added: cfe/trunk/test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp?rev=359967&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp (added) +++ cfe/trunk/test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp Sat May 4 03:49:46 2019 @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++2a -triple %itanium_abi_triple -emit-llvm -o - %s -w | FileCheck %s + +template<class, int, class> +struct DummyType { }; + +inline void inline_func() { + // CHECK: UlvE + []{}(); + + // CHECK: UlTyvE + []<class>{}.operator()<int>(); + + // CHECK: UlTyT_E + []<class T>(T){}(1); + + // CHECK: UlTyTyT_T0_E + []<class T1, class T2>(T1, T2){}(1, 2); + + // CHECK: UlTyTyT0_T_E + []<class T1, class T2>(T2, T1){}(2, 1); + + // CHECK: UlTniTyTnjT0_E + []<int I, class T, unsigned U>(T){}.operator()<1, int, 2>(3); + + // CHECK: UlTyTtTyTniTyETniTyvE + []<class, + template<class, int, class> class, + int, + class>{}.operator()<unsigned, DummyType, 5, int>(); +} + +void call_inline_func() { + inline_func(); +} Modified: cfe/trunk/test/Index/print-display-names.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/print-display-names.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/test/Index/print-display-names.cpp (original) +++ cfe/trunk/test/Index/print-display-names.cpp Sat May 4 03:49:46 2019 @@ -20,7 +20,7 @@ template<> void g<int>(ClassTmpl<int, in // DISPLAY_NAME: print-display-names.cpp:13:17: FunctionDecl=g<>(ClassTmpl<int, int>):13:17 [Specialization of g:11:6] // RUN: env CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT=1 c-index-test -test-load-source all-pretty %s | FileCheck %s --check-prefix=PRETTY -// PRETTY: print-display-names.cpp:2:7: ClassTemplate=template <typename T, typename > class ClassTmpl {}:2:7 (Definition) Extent=[1:1 - 2:20] +// PRETTY: print-display-names.cpp:2:7: ClassTemplate=template <typename T, typename> class ClassTmpl {}:2:7 (Definition) Extent=[1:1 - 2:20] // PRETTY: print-display-names.cpp:4:13: TypedefDecl=typedef int Integer:4:13 (Definition) Extent=[4:1 - 4:20] // PRETTY: print-display-names.cpp:6:16: ClassDecl=template<> class ClassTmpl<int, int> {}:6:16 (Definition) [Specialization of ClassTmpl:2:7] Extent=[6:1 - 6:43] // PRETTY: print-display-names.cpp:8:6: FunctionDecl=void f(ClassTmpl<float, Integer> p):8:6 Extent=[8:1 - 8:36] Modified: cfe/trunk/test/PCH/cxx11-lambdas.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx11-lambdas.mm?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/test/PCH/cxx11-lambdas.mm (original) +++ cfe/trunk/test/PCH/cxx11-lambdas.mm Sat May 4 03:49:46 2019 @@ -54,7 +54,7 @@ int add(int x, int y) { } // CHECK-PRINT: inline int add_int_slowly_twice -// CHECK-PRINT: lambda = [&] (int z) +// CHECK-PRINT: lambda = [&](int z) // CHECK-PRINT: init_capture // CHECK-PRINT: [&, x(t)] Modified: cfe/trunk/test/PCH/cxx1y-lambdas.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx1y-lambdas.mm?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/test/PCH/cxx1y-lambdas.mm (original) +++ cfe/trunk/test/PCH/cxx1y-lambdas.mm Sat May 4 03:49:46 2019 @@ -50,7 +50,7 @@ int add(int x, int y) { } // CHECK-PRINT: inline int add_int_slowly_twice -// CHECK-PRINT: lambda = [] (type-parameter-0-0 z +// CHECK-PRINT: lambda = [](auto z // CHECK-PRINT: init_capture // CHECK-PRINT: [&, x(t)] Added: cfe/trunk/test/PCH/cxx2a-template-lambdas.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx2a-template-lambdas.cpp?rev=359967&view=auto ============================================================================== --- cfe/trunk/test/PCH/cxx2a-template-lambdas.cpp (added) +++ cfe/trunk/test/PCH/cxx2a-template-lambdas.cpp Sat May 4 03:49:46 2019 @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t +// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s + +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +auto l1 = []<int I>() constexpr -> int { + return I; +}; + +auto l2 = []<auto I>() constexpr -> decltype(I) { + return I; +}; + +auto l3 = []<class T>(auto i) constexpr -> T { + return T(i); +}; + +auto l4 = []<template<class> class T, class U>(T<U>, auto i) constexpr -> U { + return U(i); +}; + +#else /*included pch*/ + +static_assert(l1.operator()<5>() == 5); +static_assert(l1.operator()<6>() == 6); + +static_assert(l2.operator()<7>() == 7); +static_assert(l2.operator()<nullptr>() == nullptr); + +static_assert(l3.operator()<int>(8.4) == 8); +static_assert(l3.operator()<int>(9.9) == 9); + +template<typename T> +struct DummyTemplate { }; + +static_assert(l4(DummyTemplate<float>(), 12) == 12.0); +static_assert(l4(DummyTemplate<int>(), 19.8) == 19); + +#endif // HEADER Added: cfe/trunk/test/Parser/cxx2a-template-lambdas.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-template-lambdas.cpp?rev=359967&view=auto ============================================================================== --- cfe/trunk/test/Parser/cxx2a-template-lambdas.cpp (added) +++ cfe/trunk/test/Parser/cxx2a-template-lambdas.cpp Sat May 4 03:49:46 2019 @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -std=c++2a %s -verify + +auto L0 = []<> { }; //expected-error {{cannot be empty}} + +auto L1 = []<typename T1, typename T2> { }; +auto L2 = []<typename T1, typename T2>(T1 arg1, T2 arg2) -> T1 { }; +auto L3 = []<typename T>(auto arg) { T t; }; +auto L4 = []<int I>() { }; Added: cfe/trunk/test/SemaCXX/cxx2a-template-lambdas.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx2a-template-lambdas.cpp?rev=359967&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/cxx2a-template-lambdas.cpp (added) +++ cfe/trunk/test/SemaCXX/cxx2a-template-lambdas.cpp Sat May 4 03:49:46 2019 @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +template<typename, typename> +constexpr bool is_same = false; + +template<typename T> +constexpr bool is_same<T, T> = true; + +template<typename T> +struct DummyTemplate { }; + +void func() { + auto L0 = []<typename T>(T arg) { + static_assert(is_same<T, int>); // expected-error {{static_assert failed}} + }; + L0(0); + L0(0.0); // expected-note {{in instantiation}} + + auto L1 = []<int I> { + static_assert(I == 5); // expected-error {{static_assert failed}} + }; + L1.operator()<5>(); + L1.operator()<6>(); // expected-note {{in instantiation}} + + auto L2 = []<template<typename> class T, class U>(T<U> &&arg) { + static_assert(is_same<T<U>, DummyTemplate<float>>); // // expected-error {{static_assert failed}} + }; + L2(DummyTemplate<float>()); + L2(DummyTemplate<double>()); // expected-note {{in instantiation}} +} + +template<typename T> // expected-note {{declared here}} +struct ShadowMe { + void member_func() { + auto L = []<typename T> { }; // expected-error {{'T' shadows template parameter}} + } +}; + +template<typename T> +constexpr T outer() { + return []<T x>() { return x; }.template operator()<123>(); // expected-error {{no matching member function}} \ + expected-note {{candidate template ignored}} +} +static_assert(outer<int>() == 123); +template int *outer<int *>(); // expected-note {{in instantiation}} Modified: cfe/trunk/unittests/AST/StmtPrinterTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/StmtPrinterTest.cpp?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/unittests/AST/StmtPrinterTest.cpp (original) +++ cfe/trunk/unittests/AST/StmtPrinterTest.cpp Sat May 4 03:49:46 2019 @@ -157,6 +157,43 @@ TEST(StmtPrinter, TestCXXConversionDeclE // WRONG; Should be: (a & b).operator void *() } +TEST(StmtPrinter, TestCXXLamda) { + ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11, + "void A() {" + " auto l = [] { };" + "}", + lambdaExpr(anything()).bind("id"), + "[] {\n" + "}")); + + ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11, + "void A() {" + " int a = 0, b = 1;" + " auto l = [a,b](int c, float d) { };" + "}", + lambdaExpr(anything()).bind("id"), + "[a, b](int c, float d) {\n" + "}")); + + ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX14, + "void A() {" + " auto l = [](auto a, int b, auto c, int, auto) { };" + "}", + lambdaExpr(anything()).bind("id"), + "[](auto a, int b, auto c, int, auto) {\n" + "}")); + + ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX2a, + "void A() {" + " auto l = []<typename T1, class T2, int I," + " template<class, typename> class T3>" + " (int a, auto, int, auto d) { };" + "}", + lambdaExpr(anything()).bind("id"), + "[]<typename T1, class T2, int I, template <class, typename> class T3>(int a, auto, int, auto d) {\n" + "}")); +} + TEST(StmtPrinter, TestNoImplicitBases) { const char *CPPSource = R"( class A { Added: cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp?rev=359967&view=auto ============================================================================== --- cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp (added) +++ cfe/trunk/unittests/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp Sat May 4 03:49:46 2019 @@ -0,0 +1,53 @@ +//===- unittest/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TestVisitor.h" + +using namespace clang; + +namespace { + +// Matches (optional) explicit template parameters. +class LambdaTemplateParametersVisitor + : public ExpectedLocationVisitor<LambdaTemplateParametersVisitor> { +public: + bool shouldVisitImplicitCode() const { return false; } + + bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + EXPECT_FALSE(D->isImplicit()); + Match(D->getName(), D->getLocStart()); + return true; + } + + bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + EXPECT_FALSE(D->isImplicit()); + Match(D->getName(), D->getLocStart()); + return true; + } + + bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + EXPECT_FALSE(D->isImplicit()); + Match(D->getName(), D->getLocStart()); + return true; + } +}; + +TEST(RecursiveASTVisitor, VisitsLambdaExplicitTemplateParameters) { + LambdaTemplateParametersVisitor Visitor; + Visitor.ExpectMatch("T", 2, 15); + Visitor.ExpectMatch("I", 2, 24); + Visitor.ExpectMatch("TT", 2, 31); + EXPECT_TRUE(Visitor.runOver( + "void f() { \n" + " auto l = []<class T, int I, template<class> class TT>(auto p) { }; \n" + "}", + LambdaTemplateParametersVisitor::Lang_CXX2a)); +} + +} // end anonymous namespace Modified: cfe/trunk/www/cxx_status.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=359967&r1=359966&r2=359967&view=diff ============================================================================== --- cfe/trunk/www/cxx_status.html (original) +++ cfe/trunk/www/cxx_status.html Sat May 4 03:49:46 2019 @@ -868,7 +868,7 @@ as the draft C++2a standard evolves. <tr> <td><i>template-parameter-list</i> for generic lambdas</td> <td><a href="http://wg21.link/p0428r2">P0428R2</a></td> - <td class="none" align="center">No</td> + <td class="svn" align="center">SVN</td> </tr> <tr id="p0734"> <td rowspan="4">Concepts</td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits