Author: rsmith Date: Tue May 21 13:10:50 2019 New Revision: 361300 URL: http://llvm.org/viewvc/llvm-project?rev=361300&view=rev Log: [c++20] P0780R2: Support pack-expansion of init-captures.
This permits an init-capture to introduce a new pack: template<typename ...T> auto x = [...a = T()] { /* a is a pack */ }; To support this, the mechanism for allowing ParmVarDecls to be packs has been extended to support arbitrary local VarDecls. Added: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.capture/ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.capture/p17.cpp cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp cfe/trunk/test/FixIt/fixit-c++2a.cpp Modified: cfe/trunk/include/clang/AST/ASTContext.h cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/AST/ExprCXX.h cfe/trunk/include/clang/AST/Type.h cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/include/clang/Sema/Template.h cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/AST/DeclBase.cpp cfe/trunk/lib/AST/ExprCXX.cpp cfe/trunk/lib/AST/ItaniumMangle.cpp cfe/trunk/lib/AST/JSONNodeDumper.cpp cfe/trunk/lib/AST/TextNodeDumper.cpp cfe/trunk/lib/AST/Type.cpp cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Sema/SemaLambda.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp cfe/trunk/lib/Sema/TreeTransform.h cfe/trunk/lib/Serialization/ASTReader.cpp cfe/trunk/lib/Serialization/ASTReaderStmt.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp cfe/trunk/test/SemaTemplate/sizeof-pack.cpp cfe/trunk/www/cxx_status.html Modified: cfe/trunk/include/clang/AST/ASTContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h (original) +++ cfe/trunk/include/clang/AST/ASTContext.h Tue May 21 13:10:50 2019 @@ -1522,7 +1522,7 @@ public: /// C++11 deduced auto type. QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent) const; + bool IsDependent, bool IsPack = false) const; /// C++11 deduction pattern for 'auto' type. QualType getAutoDeductType() const; Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Tue May 21 13:10:50 2019 @@ -1395,6 +1395,10 @@ public: NonParmVarDeclBits.IsInitCapture = IC; } + /// Determine whether this variable is actually a function parameter pack or + /// init-capture pack. + bool isParameterPack() const; + /// Whether this local extern variable declaration's previous declaration /// was declared in the same block scope. Only correct in C++. bool isPreviousDeclInSameBlockScope() const { @@ -1688,10 +1692,6 @@ public: QualType getOriginalType() const; - /// Determine whether this parameter is actually a function - /// parameter pack. - bool isParameterPack() const; - /// Sets the function declaration that owns this /// ParmVarDecl. Since ParmVarDecls are often created before the /// FunctionDecls that own them, this routine is required to update Modified: cfe/trunk/include/clang/AST/ExprCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ExprCXX.h (original) +++ cfe/trunk/include/clang/AST/ExprCXX.h Tue May 21 13:10:50 2019 @@ -4233,8 +4233,8 @@ public: } }; -/// Represents a reference to a function parameter pack that has been -/// substituted but not yet expanded. +/// Represents a reference to a function parameter pack or init-capture pack +/// that has been substituted but not yet expanded. /// /// When a pack expansion contains multiple parameter packs at different levels, /// this node is used to represent a function parameter pack at an outer level @@ -4249,13 +4249,13 @@ public: /// \endcode class FunctionParmPackExpr final : public Expr, - private llvm::TrailingObjects<FunctionParmPackExpr, ParmVarDecl *> { + private llvm::TrailingObjects<FunctionParmPackExpr, VarDecl *> { friend class ASTReader; friend class ASTStmtReader; friend TrailingObjects; /// The function parameter pack which was referenced. - ParmVarDecl *ParamPack; + VarDecl *ParamPack; /// The location of the function parameter pack reference. SourceLocation NameLoc; @@ -4263,35 +4263,35 @@ class FunctionParmPackExpr final /// The number of expansions of this pack. unsigned NumParameters; - FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack, + FunctionParmPackExpr(QualType T, VarDecl *ParamPack, SourceLocation NameLoc, unsigned NumParams, - ParmVarDecl *const *Params); + VarDecl *const *Params); public: static FunctionParmPackExpr *Create(const ASTContext &Context, QualType T, - ParmVarDecl *ParamPack, + VarDecl *ParamPack, SourceLocation NameLoc, - ArrayRef<ParmVarDecl *> Params); + ArrayRef<VarDecl *> Params); static FunctionParmPackExpr *CreateEmpty(const ASTContext &Context, unsigned NumParams); /// Get the parameter pack which this expression refers to. - ParmVarDecl *getParameterPack() const { return ParamPack; } + VarDecl *getParameterPack() const { return ParamPack; } /// Get the location of the parameter pack. SourceLocation getParameterPackLocation() const { return NameLoc; } /// Iterators over the parameters which the parameter pack expanded /// into. - using iterator = ParmVarDecl * const *; - iterator begin() const { return getTrailingObjects<ParmVarDecl *>(); } + using iterator = VarDecl * const *; + iterator begin() const { return getTrailingObjects<VarDecl *>(); } iterator end() const { return begin() + NumParameters; } /// Get the number of parameters in this parameter pack. unsigned getNumExpansions() const { return NumParameters; } /// Get an expansion of the parameter pack by index. - ParmVarDecl *getExpansion(unsigned I) const { return begin()[I]; } + VarDecl *getExpansion(unsigned I) const { return begin()[I]; } SourceLocation getBeginLoc() const LLVM_READONLY { return NameLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return NameLoc; } Modified: cfe/trunk/include/clang/AST/Type.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Type.h (original) +++ cfe/trunk/include/clang/AST/Type.h Tue May 21 13:10:50 2019 @@ -4797,9 +4797,9 @@ class AutoType : public DeducedType, pub friend class ASTContext; // ASTContext creates these AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - bool IsDeducedAsDependent) + bool IsDeducedAsDependent, bool IsDeducedAsPack) : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent, - IsDeducedAsDependent, /*ContainsPack=*/false) { + IsDeducedAsDependent, IsDeducedAsPack) { AutoTypeBits.Keyword = (unsigned)Keyword; } @@ -4813,14 +4813,16 @@ public: } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDeducedType(), getKeyword(), isDependentType()); + Profile(ID, getDeducedType(), getKeyword(), isDependentType(), + containsUnexpandedParameterPack()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced, - AutoTypeKeyword Keyword, bool IsDependent) { + AutoTypeKeyword Keyword, bool IsDependent, bool IsPack) { ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddInteger((unsigned)Keyword); ID.AddBoolean(IsDependent); + ID.AddBoolean(IsPack); } static bool classof(const Type *T) { Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Tue May 21 13:10:50 2019 @@ -878,6 +878,11 @@ def err_lambda_missing_parens : Error< "attribute specifier|'constexpr'}0">; def err_lambda_decl_specifier_repeated : Error< "%select{'mutable'|'constexpr'}0 cannot appear multiple times in a lambda declarator">; +def err_lambda_capture_misplaced_ellipsis : Error< + "ellipsis in pack %select{|init-}0capture must appear %select{after|before}0 " + "the name of the capture">; +def err_lambda_capture_multiple_ellipses : Error< + "multiple ellipses in pack capture">; // C++17 lambda expressions def err_expected_star_this_capture : Error< "expected 'this' following '*' in lambda capture list">; @@ -889,15 +894,15 @@ 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< +// 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">; +def err_lambda_template_parameter_list_empty : Error< + "lambda template parameter list cannot be empty">; // Availability attribute def err_expected_version : Error< Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue May 21 13:10:50 2019 @@ -6663,6 +6663,11 @@ let CategoryName = "Lambda Issue" in { "cannot deduce type for lambda capture %0 from initializer of type %2">; def err_init_capture_deduction_failure_from_init_list : Error< "cannot deduce type for lambda capture %0 from initializer list">; + def warn_cxx17_compat_init_capture_pack : Warning< + "initialized lambda capture packs are incompatible with C++ standards " + "before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore; + def ext_init_capture_pack : ExtWarn< + "initialized lambda pack captures are a C++2a extension">, InGroup<CXX2a>; // C++14 generic lambdas. def warn_cxx11_compat_generic_lambda : Warning< Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue May 21 13:10:50 2019 @@ -5711,14 +5711,16 @@ public: /// any implicit conversions such as an lvalue-to-rvalue conversion if /// not being used to initialize a reference. ParsedType actOnLambdaInitCaptureInitialization( - SourceLocation Loc, bool ByRef, IdentifierInfo *Id, - LambdaCaptureInitKind InitKind, Expr *&Init) { + SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, + IdentifierInfo *Id, LambdaCaptureInitKind InitKind, Expr *&Init) { return ParsedType::make(buildLambdaInitCaptureInitialization( - Loc, ByRef, Id, InitKind != LambdaCaptureInitKind::CopyInit, Init)); + Loc, ByRef, EllipsisLoc, None, Id, + InitKind != LambdaCaptureInitKind::CopyInit, Init)); } - QualType buildLambdaInitCaptureInitialization(SourceLocation Loc, bool ByRef, - IdentifierInfo *Id, - bool DirectInit, Expr *&Init); + QualType buildLambdaInitCaptureInitialization( + SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, + Optional<unsigned> NumExpansions, IdentifierInfo *Id, bool DirectInit, + Expr *&Init); /// Create a dummy variable within the declcontext of the lambda's /// call operator, for name lookup purposes for a lambda init capture. @@ -5727,6 +5729,7 @@ public: /// variables appropriately. VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc, QualType InitCaptureType, + SourceLocation EllipsisLoc, IdentifierInfo *Id, unsigned InitStyle, Expr *Init); Modified: cfe/trunk/include/clang/Sema/Template.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Template.h?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Template.h (original) +++ cfe/trunk/include/clang/Sema/Template.h Tue May 21 13:10:50 2019 @@ -227,7 +227,7 @@ class VarDecl; class LocalInstantiationScope { public: /// A set of declarations. - using DeclArgumentPack = SmallVector<ParmVarDecl *, 4>; + using DeclArgumentPack = SmallVector<VarDecl *, 4>; private: /// Reference to the semantic analysis that is performing @@ -378,7 +378,7 @@ class VarDecl; findInstantiationOf(const Decl *D); void InstantiatedLocal(const Decl *D, Decl *Inst); - void InstantiatedLocalPackArg(const Decl *D, ParmVarDecl *Inst); + void InstantiatedLocalPackArg(const Decl *D, VarDecl *Inst); void MakeInstantiatedLocalArgPack(const Decl *D); /// Note that the given parameter pack has been partially substituted Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Tue May 21 13:10:50 2019 @@ -4372,7 +4372,13 @@ QualType ASTContext::getPackExpansionTyp llvm::FoldingSetNodeID ID; PackExpansionType::Profile(ID, Pattern, NumExpansions); - assert(Pattern->containsUnexpandedParameterPack() && + // A deduced type can deduce to a pack, eg + // auto ...x = some_pack; + // That declaration isn't (yet) valid, but is created as part of building an + // init-capture pack: + // [...x = some_pack] {} + assert((Pattern->containsUnexpandedParameterPack() || + Pattern->getContainedDeducedType()) && "Pack expansions must expand one or more parameter packs"); void *InsertPos = nullptr; PackExpansionType *T @@ -4872,19 +4878,20 @@ QualType ASTContext::getUnaryTransformTy /// deduced to the given type, or to the canonical undeduced 'auto' type, or the /// canonical deduced-but-dependent 'auto' type. QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent) const { + bool IsDependent, bool IsPack) const { + assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent) return getAutoDeductType(); // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType, Keyword, IsDependent); + AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); auto *AT = new (*this, TypeAlignment) - AutoType(DeducedType, Keyword, IsDependent); + AutoType(DeducedType, Keyword, IsDependent, IsPack); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -4946,7 +4953,7 @@ QualType ASTContext::getAutoDeductType() if (AutoDeductTy.isNull()) AutoDeductTy = QualType( new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, - /*dependent*/false), + /*dependent*/false, /*pack*/false), 0); return AutoDeductTy; } Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Tue May 21 13:10:50 2019 @@ -2397,6 +2397,10 @@ bool VarDecl::checkInitIsICE() const { return Eval->IsICE; } +bool VarDecl::isParameterPack() const { + return isa<PackExpansionType>(getType()); +} + template<typename DeclT> static DeclT *getDefinitionOrSelf(DeclT *D) { assert(D); @@ -2683,10 +2687,6 @@ bool ParmVarDecl::hasDefaultArg() const !Init.isNull(); } -bool ParmVarDecl::isParameterPack() const { - return isa<PackExpansionType>(getType()); -} - void ParmVarDecl::setParameterIndexLarge(unsigned parameterIndex) { getASTContext().setParameterIndex(this, parameterIndex); ParmVarDeclBits.ParameterIndex = ParameterIndexSentinel; Modified: cfe/trunk/lib/AST/DeclBase.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclBase.cpp (original) +++ cfe/trunk/lib/AST/DeclBase.cpp Tue May 21 13:10:50 2019 @@ -208,8 +208,8 @@ bool Decl::isTemplateParameterPack() con } bool Decl::isParameterPack() const { - if (const auto *Parm = dyn_cast<ParmVarDecl>(this)) - return Parm->isParameterPack(); + if (const auto *Var = dyn_cast<VarDecl>(this)) + return Var->isParameterPack(); return isTemplateParameterPack(); } Modified: cfe/trunk/lib/AST/ExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprCXX.cpp (original) +++ cfe/trunk/lib/AST/ExprCXX.cpp Tue May 21 13:10:50 2019 @@ -1541,30 +1541,30 @@ TemplateArgument SubstNonTypeTemplatePar return TemplateArgument(llvm::makeArrayRef(Arguments, NumArguments)); } -FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack, +FunctionParmPackExpr::FunctionParmPackExpr(QualType T, VarDecl *ParamPack, SourceLocation NameLoc, unsigned NumParams, - ParmVarDecl *const *Params) + VarDecl *const *Params) : Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary, true, true, true, true), ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) { if (Params) std::uninitialized_copy(Params, Params + NumParams, - getTrailingObjects<ParmVarDecl *>()); + getTrailingObjects<VarDecl *>()); } FunctionParmPackExpr * FunctionParmPackExpr::Create(const ASTContext &Context, QualType T, - ParmVarDecl *ParamPack, SourceLocation NameLoc, - ArrayRef<ParmVarDecl *> Params) { - return new (Context.Allocate(totalSizeToAlloc<ParmVarDecl *>(Params.size()))) + VarDecl *ParamPack, SourceLocation NameLoc, + ArrayRef<VarDecl *> Params) { + return new (Context.Allocate(totalSizeToAlloc<VarDecl *>(Params.size()))) FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data()); } FunctionParmPackExpr * FunctionParmPackExpr::CreateEmpty(const ASTContext &Context, unsigned NumParams) { - return new (Context.Allocate(totalSizeToAlloc<ParmVarDecl *>(NumParams))) + return new (Context.Allocate(totalSizeToAlloc<VarDecl *>(NumParams))) FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr); } Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Tue May 21 13:10:50 2019 @@ -538,6 +538,7 @@ private: unsigned knownArity); void mangleCastExpression(const Expr *E, StringRef CastEncoding); void mangleInitListElements(const InitListExpr *InitList); + void mangleDeclRefExpr(const NamedDecl *D); void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom); void mangleCXXDtorType(CXXDtorType T); @@ -3499,6 +3500,32 @@ void CXXNameMangler::mangleInitListEleme mangleExpression(InitList->getInit(i)); } +void CXXNameMangler::mangleDeclRefExpr(const NamedDecl *D) { + switch (D->getKind()) { + default: + // <expr-primary> ::= L <mangled-name> E # external name + Out << 'L'; + mangle(D); + Out << 'E'; + break; + + case Decl::ParmVar: + mangleFunctionParam(cast<ParmVarDecl>(D)); + break; + + case Decl::EnumConstant: { + const EnumConstantDecl *ED = cast<EnumConstantDecl>(D); + mangleIntegerLiteral(ED->getType(), ED->getInitVal()); + break; + } + + case Decl::NonTypeTemplateParm: + const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D); + mangleTemplateParameter(PD->getIndex()); + break; + } +} + void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { // <expression> ::= <unary operator-name> <expression> // ::= <binary operator-name> <expression> <expression> @@ -4089,37 +4116,9 @@ recurse: mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity); break; - case Expr::DeclRefExprClass: { - const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); - - switch (D->getKind()) { - default: - // <expr-primary> ::= L <mangled-name> E # external name - Out << 'L'; - mangle(D); - Out << 'E'; - break; - - case Decl::ParmVar: - mangleFunctionParam(cast<ParmVarDecl>(D)); - break; - - case Decl::EnumConstant: { - const EnumConstantDecl *ED = cast<EnumConstantDecl>(D); - mangleIntegerLiteral(ED->getType(), ED->getInitVal()); - break; - } - - case Decl::NonTypeTemplateParm: { - const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D); - mangleTemplateParameter(PD->getIndex()); - break; - } - - } - + case Expr::DeclRefExprClass: + mangleDeclRefExpr(cast<DeclRefExpr>(E)->getDecl()); break; - } case Expr::SubstNonTypeTemplateParmPackExprClass: // FIXME: not clear how to mangle this! @@ -4133,7 +4132,7 @@ recurse: // FIXME: not clear how to mangle this! const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E); Out << "v110_SUBSTPACK"; - mangleFunctionParam(FPPE->getParameterPack()); + mangleDeclRefExpr(FPPE->getParameterPack()); break; } Modified: cfe/trunk/lib/AST/JSONNodeDumper.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/JSONNodeDumper.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/AST/JSONNodeDumper.cpp (original) +++ cfe/trunk/lib/AST/JSONNodeDumper.cpp Tue May 21 13:10:50 2019 @@ -539,6 +539,7 @@ void JSONNodeDumper::VisitVarDecl(const case VarDecl::ListInit: JOS.attribute("init", "list"); break; } } + attributeOnlyIfTrue("isParameterPack", VD->isParameterPack()); } void JSONNodeDumper::VisitFieldDecl(const FieldDecl *FD) { Modified: cfe/trunk/lib/AST/TextNodeDumper.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TextNodeDumper.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/AST/TextNodeDumper.cpp (original) +++ cfe/trunk/lib/AST/TextNodeDumper.cpp Tue May 21 13:10:50 2019 @@ -1366,6 +1366,8 @@ void TextNodeDumper::VisitVarDecl(const break; } } + if (D->isParameterPack()) + OS << " pack"; } void TextNodeDumper::VisitBindingDecl(const BindingDecl *D) { Modified: cfe/trunk/lib/AST/Type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/AST/Type.cpp (original) +++ cfe/trunk/lib/AST/Type.cpp Tue May 21 13:10:50 2019 @@ -1743,6 +1743,10 @@ namespace { Type *VisitAdjustedType(const AdjustedType *T) { return Visit(T->getOriginalType()); } + + Type *VisitPackExpansionType(const PackExpansionType *T) { + return Visit(T->getPattern()); + } }; } // namespace Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue May 21 13:10:50 2019 @@ -20,7 +20,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "llvm/Support/ErrorHandling.h" - +#include <numeric> using namespace clang; @@ -714,10 +714,10 @@ ExprResult Parser::TryParseLambdaExpress if (Next.is(tok::r_square) || // [] Next.is(tok::equal) || // [= (Next.is(tok::amp) && // [&] or [&, - (After.is(tok::r_square) || - After.is(tok::comma))) || + After.isOneOf(tok::r_square, tok::comma)) || (Next.is(tok::identifier) && // [identifier] - After.is(tok::r_square))) { + After.is(tok::r_square)) || + Next.is(tok::ellipsis)) { // [... return ParseLambdaExpression(); } @@ -798,6 +798,15 @@ bool Parser::ParseLambdaIntroducer(Lambd return true; }; + // Perform some irreversible action if this is a non-tentative parse; + // otherwise note that our actions were incomplete. + auto NonTentativeAction = [&](llvm::function_ref<void()> Action) { + if (Tentative) + *Tentative = LambdaIntroducerTentativeParse::Incomplete; + else + Action(); + }; + // Parse capture-default. if (Tok.is(tok::amp) && (NextToken().is(tok::comma) || NextToken().is(tok::r_square))) { @@ -857,7 +866,7 @@ bool Parser::ParseLambdaIntroducer(Lambd LambdaCaptureInitKind InitKind = LambdaCaptureInitKind::NoInit; SourceLocation Loc; IdentifierInfo *Id = nullptr; - SourceLocation EllipsisLoc; + SourceLocation EllipsisLocs[4]; ExprResult Init; SourceLocation LocStart = Tok.getLocation(); @@ -875,6 +884,8 @@ bool Parser::ParseLambdaIntroducer(Lambd Kind = LCK_This; Loc = ConsumeToken(); } else { + TryConsumeToken(tok::ellipsis, EllipsisLocs[0]); + if (Tok.is(tok::amp)) { Kind = LCK_ByRef; ConsumeToken(); @@ -887,6 +898,8 @@ bool Parser::ParseLambdaIntroducer(Lambd } } + TryConsumeToken(tok::ellipsis, EllipsisLocs[1]); + if (Tok.is(tok::identifier)) { Id = Tok.getIdentifierInfo(); Loc = ConsumeToken(); @@ -901,6 +914,8 @@ bool Parser::ParseLambdaIntroducer(Lambd }); } + TryConsumeToken(tok::ellipsis, EllipsisLocs[2]); + if (Tok.is(tok::l_paren)) { BalancedDelimiterTracker Parens(*this, tok::l_paren); Parens.consumeOpen(); @@ -982,9 +997,9 @@ bool Parser::ParseLambdaIntroducer(Lambd ConsumeAnnotationToken(); } } - } else { - TryConsumeToken(tok::ellipsis, EllipsisLoc); } + + TryConsumeToken(tok::ellipsis, EllipsisLocs[3]); } // Check if this is a message send before we act on a possible init-capture. @@ -995,60 +1010,81 @@ bool Parser::ParseLambdaIntroducer(Lambd return false; } - // If this is an init capture, process the initialization expression - // right away. For lambda init-captures such as the following: - // const int x = 10; - // auto L = [i = x+1](int a) { - // return [j = x+2, - // &k = x](char b) { }; - // }; - // keep in mind that each lambda init-capture has to have: - // - its initialization expression executed in the context - // of the enclosing/parent decl-context. - // - but the variable itself has to be 'injected' into the - // decl-context of its lambda's call-operator (which has - // not yet been created). - // Each init-expression is a full-expression that has to get - // Sema-analyzed (for capturing etc.) before its lambda's - // call-operator's decl-context, scope & scopeinfo are pushed on their - // respective stacks. Thus if any variable is odr-used in the init-capture - // it will correctly get captured in the enclosing lambda, if one exists. - // The init-variables above are created later once the lambdascope and - // call-operators decl-context is pushed onto its respective stack. - - // Since the lambda init-capture's initializer expression occurs in the - // context of the enclosing function or lambda, therefore we can not wait - // till a lambda scope has been pushed on before deciding whether the - // variable needs to be captured. We also need to process all - // lvalue-to-rvalue conversions and discarded-value conversions, - // so that we can avoid capturing certain constant variables. - // For e.g., - // void test() { - // const int x = 10; - // auto L = [&z = x](char a) { <-- don't capture by the current lambda - // return [y = x](int i) { <-- don't capture by enclosing lambda - // return y; - // } - // }; - // } - // If x was not const, the second use would require 'L' to capture, and - // that would be an error. + // Ensure that any ellipsis was in the right place. + SourceLocation EllipsisLoc; + if (std::any_of(std::begin(EllipsisLocs), std::end(EllipsisLocs), + [](SourceLocation Loc) { return Loc.isValid(); })) { + // The '...' should appear before the identifier in an init-capture, and + // after the identifier otherwise. + bool InitCapture = InitKind != LambdaCaptureInitKind::NoInit; + SourceLocation *ExpectedEllipsisLoc = + !InitCapture ? &EllipsisLocs[2] : + Kind == LCK_ByRef ? &EllipsisLocs[1] : + &EllipsisLocs[0]; + EllipsisLoc = *ExpectedEllipsisLoc; + + unsigned DiagID = 0; + if (EllipsisLoc.isInvalid()) { + DiagID = diag::err_lambda_capture_misplaced_ellipsis; + for (SourceLocation Loc : EllipsisLocs) { + if (Loc.isValid()) + EllipsisLoc = Loc; + } + } else { + unsigned NumEllipses = std::accumulate( + std::begin(EllipsisLocs), std::end(EllipsisLocs), 0, + [](int N, SourceLocation Loc) { return N + Loc.isValid(); }); + if (NumEllipses > 1) + DiagID = diag::err_lambda_capture_multiple_ellipses; + } + if (DiagID) { + NonTentativeAction([&] { + // Point the diagnostic at the first misplaced ellipsis. + SourceLocation DiagLoc; + for (SourceLocation &Loc : EllipsisLocs) { + if (&Loc != ExpectedEllipsisLoc && Loc.isValid()) { + DiagLoc = Loc; + break; + } + } + assert(DiagLoc.isValid() && "no location for diagnostic"); + // Issue the diagnostic and produce fixits showing where the ellipsis + // should have been written. + auto &&D = Diag(DiagLoc, DiagID); + if (DiagID == diag::err_lambda_capture_misplaced_ellipsis) { + SourceLocation ExpectedLoc = + InitCapture ? Loc + : Lexer::getLocForEndOfToken( + Loc, 0, PP.getSourceManager(), getLangOpts()); + D << InitCapture << FixItHint::CreateInsertion(ExpectedLoc, "..."); + } + for (SourceLocation &Loc : EllipsisLocs) { + if (&Loc != ExpectedEllipsisLoc && Loc.isValid()) + D << FixItHint::CreateRemoval(Loc); + } + }); + } + } + + // Process the init-capture initializers now rather than delaying until we + // form the lambda-expression so that they can be handled in the context + // enclosing the lambda-expression, rather than in the context of the + // lambda-expression itself. ParsedType InitCaptureType; - if (Tentative && Init.isUsable()) - *Tentative = LambdaIntroducerTentativeParse::Incomplete; - else if (Init.isUsable()) { + if (Init.isUsable()) Init = Actions.CorrectDelayedTyposInExpr(Init.get()); - if (Init.isUsable()) { + if (Init.isUsable()) { + NonTentativeAction([&] { // Get the pointer and store it in an lvalue, so we can use it as an // out argument. Expr *InitExpr = Init.get(); // This performs any lvalue-to-rvalue conversions if necessary, which // can affect what gets captured in the containing decl-context. InitCaptureType = Actions.actOnLambdaInitCaptureInitialization( - Loc, Kind == LCK_ByRef, Id, InitKind, InitExpr); + Loc, Kind == LCK_ByRef, EllipsisLoc, Id, InitKind, InitExpr); Init = InitExpr; - } + }); } SourceLocation LocEnd = PrevTokLocation; Modified: cfe/trunk/lib/Sema/SemaLambda.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaLambda.cpp (original) +++ cfe/trunk/lib/Sema/SemaLambda.cpp Tue May 21 13:10:50 2019 @@ -753,11 +753,10 @@ void Sema::deduceClosureReturnType(Captu } } -QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc, - bool ByRef, - IdentifierInfo *Id, - bool IsDirectInit, - Expr *&Init) { +QualType Sema::buildLambdaInitCaptureInitialization( + SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, + Optional<unsigned> NumExpansions, IdentifierInfo *Id, bool IsDirectInit, + Expr *&Init) { // Create an 'auto' or 'auto&' TypeSourceInfo that we can use to // deduce against. QualType DeductType = Context.getAutoDeductType(); @@ -768,6 +767,18 @@ QualType Sema::buildLambdaInitCaptureIni assert(!DeductType.isNull() && "can't build reference to auto"); TLB.push<ReferenceTypeLoc>(DeductType).setSigilLoc(Loc); } + if (EllipsisLoc.isValid()) { + if (Init->containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_init_capture_pack + : diag::ext_init_capture_pack); + DeductType = Context.getPackExpansionType(DeductType, NumExpansions); + TLB.push<PackExpansionTypeLoc>(DeductType).setEllipsisLoc(EllipsisLoc); + } else { + // Just ignore the ellipsis for now and form a non-pack variable. We'll + // diagnose this later when we try to capture it. + } + } TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType); // Deduce the type of the init capture. @@ -808,10 +819,15 @@ QualType Sema::buildLambdaInitCaptureIni VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc, QualType InitCaptureType, + SourceLocation EllipsisLoc, IdentifierInfo *Id, unsigned InitStyle, Expr *Init) { - TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType, - Loc); + // FIXME: Retain the TypeSourceInfo from buildLambdaInitCaptureInitialization + // rather than reconstructing it here. + TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType, Loc); + if (auto PETL = TSI->getTypeLoc().getAs<PackExpansionTypeLoc>()) + PETL.setEllipsisLoc(EllipsisLoc); + // Create a dummy variable representing the init-capture. This is not actually // used as a variable, and only exists as a way to name and refer to the // init-capture. @@ -1036,8 +1052,6 @@ void Sema::ActOnStartOfLambdaDefinition( ? diag::warn_cxx11_compat_init_capture : diag::ext_init_capture); - if (C->Init.get()->containsUnexpandedParameterPack()) - ContainsUnexpandedParameterPack = true; // If the initializer expression is usable, but the InitCaptureType // is not, then an error has occurred - so ignore the capture for now. // for e.g., [n{0}] { }; <-- if no <initializer_list> is included. @@ -1046,6 +1060,10 @@ void Sema::ActOnStartOfLambdaDefinition( if (C->InitCaptureType.get().isNull()) continue; + if (C->Init.get()->containsUnexpandedParameterPack() && + !C->InitCaptureType.get()->getAs<PackExpansionType>()) + ContainsUnexpandedParameterPack = true; + unsigned InitStyle; switch (C->InitKind) { case LambdaCaptureInitKind::NoInit: @@ -1061,7 +1079,8 @@ void Sema::ActOnStartOfLambdaDefinition( break; } Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(), - C->Id, InitStyle, C->Init.get()); + C->EllipsisLoc, C->Id, InitStyle, + C->Init.get()); // C++1y [expr.prim.lambda]p11: // An init-capture behaves as if it declares and explicitly // captures a variable [...] whose declarative region is the @@ -1153,7 +1172,8 @@ void Sema::ActOnStartOfLambdaDefinition( EllipsisLoc = C->EllipsisLoc; } else { Diag(C->EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) - << SourceRange(C->Loc); + << (C->Init.isUsable() ? C->Init.get()->getSourceRange() + : SourceRange(C->Loc)); // Just ignore the ellipsis. } Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Tue May 21 13:10:50 2019 @@ -4280,19 +4280,26 @@ Sema::TemplateDeductionResult Sema::Dedu } namespace { + struct DependentAuto { bool IsPack; }; /// Substitute the 'auto' specifier or deduced template specialization type /// specifier within a type for a given replacement type. class SubstituteDeducedTypeTransform : public TreeTransform<SubstituteDeducedTypeTransform> { QualType Replacement; + bool ReplacementIsPack; bool UseTypeSugar; public: + SubstituteDeducedTypeTransform(Sema &SemaRef, DependentAuto DA) + : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef), Replacement(), + ReplacementIsPack(DA.IsPack), UseTypeSugar(true) {} + SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement, - bool UseTypeSugar = true) + bool UseTypeSugar = true) : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef), - Replacement(Replacement), UseTypeSugar(UseTypeSugar) {} + Replacement(Replacement), ReplacementIsPack(false), + UseTypeSugar(UseTypeSugar) {} QualType TransformDesugared(TypeLocBuilder &TLB, DeducedTypeLoc TL) { assert(isa<TemplateTypeParmType>(Replacement) && @@ -4317,7 +4324,8 @@ namespace { return TransformDesugared(TLB, TL); QualType Result = SemaRef.Context.getAutoType( - Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull()); + Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(), + ReplacementIsPack); auto NewTL = TLB.push<AutoTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -4408,9 +4416,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr Init = NonPlaceholder.get(); } + DependentAuto DependentResult = { + /*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()}; + if (!DependentDeductionDepth && (Type.getType()->isDependentType() || Init->isTypeDependent())) { - Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type); + Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; } @@ -4478,7 +4489,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr auto DeductionFailed = [&](TemplateDeductionResult TDK, ArrayRef<SourceRange> Ranges) -> DeduceAutoResult { if (Init->isTypeDependent()) { - Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type); + Result = + SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; } @@ -4559,7 +4571,10 @@ Sema::DeduceAutoType(TypeLoc Type, Expr QualType Sema::SubstAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { if (TypeToReplaceAuto->isDependentType()) - TypeToReplaceAuto = QualType(); + return SubstituteDeducedTypeTransform( + *this, DependentAuto{ + TypeToReplaceAuto->containsUnexpandedParameterPack()}) + .TransformType(TypeWithAuto); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } @@ -4567,7 +4582,11 @@ QualType Sema::SubstAutoType(QualType Ty TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType TypeToReplaceAuto) { if (TypeToReplaceAuto->isDependentType()) - TypeToReplaceAuto = QualType(); + return SubstituteDeducedTypeTransform( + *this, + DependentAuto{ + TypeToReplaceAuto->containsUnexpandedParameterPack()}) + .TransformType(TypeWithAuto); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue May 21 13:10:50 2019 @@ -819,7 +819,19 @@ namespace { SemaRef.InstantiateAttrs(TemplateArgs, Old, New); } - void transformedLocalDecl(Decl *Old, Decl *New) { + void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> NewDecls) { + if (Old->isParameterPack()) { + SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Old); + for (auto *New : NewDecls) + SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg( + Old, cast<VarDecl>(New)); + return; + } + + assert(NewDecls.size() == 1 && + "should only have multiple expansions for a pack"); + Decl *New = NewDecls.front(); + // If we've instantiated the call operator of a lambda or the call // operator template of a generic lambda, update the "instantiation of" // information. @@ -888,12 +900,11 @@ namespace { ExprResult TransformSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E); - /// Rebuild a DeclRefExpr for a ParmVarDecl reference. - ExprResult RebuildParmVarDeclRefExpr(ParmVarDecl *PD, SourceLocation Loc); + /// Rebuild a DeclRefExpr for a VarDecl reference. + ExprResult RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc); - /// Transform a reference to a function parameter pack. - ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, - ParmVarDecl *PD); + /// Transform a reference to a function or init-capture parameter pack. + ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, VarDecl *PD); /// Transform a FunctionParmPackExpr which was built when we couldn't /// expand a function parameter pack reference which refers to an expanded @@ -1324,9 +1335,8 @@ TemplateInstantiator::TransformSubstNonT Arg); } -ExprResult -TemplateInstantiator::RebuildParmVarDeclRefExpr(ParmVarDecl *PD, - SourceLocation Loc) { +ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD, + SourceLocation Loc) { DeclarationNameInfo NameInfo(PD->getDeclName(), Loc); return getSema().BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, PD); } @@ -1335,11 +1345,11 @@ ExprResult TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) { if (getSema().ArgumentPackSubstitutionIndex != -1) { // We can expand this parameter pack now. - ParmVarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex); - ValueDecl *VD = cast_or_null<ValueDecl>(TransformDecl(E->getExprLoc(), D)); + VarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex); + VarDecl *VD = cast_or_null<VarDecl>(TransformDecl(E->getExprLoc(), D)); if (!VD) return ExprError(); - return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(VD), E->getExprLoc()); + return RebuildVarDeclRefExpr(VD, E->getExprLoc()); } QualType T = TransformType(E->getType()); @@ -1348,25 +1358,24 @@ TemplateInstantiator::TransformFunctionP // Transform each of the parameter expansions into the corresponding // parameters in the instantiation of the function decl. - SmallVector<ParmVarDecl *, 8> Parms; - Parms.reserve(E->getNumExpansions()); + SmallVector<VarDecl *, 8> Vars; + Vars.reserve(E->getNumExpansions()); for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end(); I != End; ++I) { - ParmVarDecl *D = - cast_or_null<ParmVarDecl>(TransformDecl(E->getExprLoc(), *I)); + VarDecl *D = cast_or_null<VarDecl>(TransformDecl(E->getExprLoc(), *I)); if (!D) return ExprError(); - Parms.push_back(D); + Vars.push_back(D); } return FunctionParmPackExpr::Create(getSema().Context, T, E->getParameterPack(), - E->getParameterPackLocation(), Parms); + E->getParameterPackLocation(), Vars); } ExprResult TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E, - ParmVarDecl *PD) { + VarDecl *PD) { typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found = getSema().CurrentInstantiationScope->findInstantiationOf(PD); @@ -1390,8 +1399,7 @@ TemplateInstantiator::TransformFunctionP } // We have either an unexpanded pack or a specific expansion. - return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(TransformedDecl), - E->getExprLoc()); + return RebuildVarDeclRefExpr(cast<VarDecl>(TransformedDecl), E->getExprLoc()); } ExprResult @@ -1409,7 +1417,7 @@ TemplateInstantiator::TransformDeclRefEx } // Handle references to function parameter packs. - if (ParmVarDecl *PD = dyn_cast<ParmVarDecl>(D)) + if (VarDecl *PD = dyn_cast<VarDecl>(D)) if (PD->isParameterPack()) return TransformFunctionParmPackRefExpr(E, PD); @@ -2984,14 +2992,14 @@ void LocalInstantiationScope::Instantiat #endif Stored = Inst; } else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) { - Pack->push_back(cast<ParmVarDecl>(Inst)); + Pack->push_back(cast<VarDecl>(Inst)); } else { assert(Stored.get<Decl *>() == Inst && "Already instantiated this local"); } } void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, - ParmVarDecl *Inst) { + VarDecl *Inst) { D = getCanonicalParmVarDecl(D); DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>(); Pack->push_back(Inst); Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Tue May 21 13:10:50 2019 @@ -39,11 +39,11 @@ namespace { unsigned DepthLimit = (unsigned)-1; void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) { - if (auto *PVD = dyn_cast<ParmVarDecl>(ND)) { + if (auto *VD = dyn_cast<VarDecl>(ND)) { // For now, the only problematic case is a generic lambda's templated // call operator, so we don't need to look for all the other ways we // could have reached a dependent parameter pack. - auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext()); + auto *FD = dyn_cast<FunctionDecl>(VD->getDeclContext()); auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr; if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit) return; @@ -313,11 +313,11 @@ Sema::DiagnoseUnexpandedParameterPacks(S if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) { if (N == FunctionScopes.size()) { - for (auto &Param : Unexpanded) { - auto *PD = dyn_cast_or_null<ParmVarDecl>( - Param.first.dyn_cast<NamedDecl *>()); - if (PD && PD->getDeclContext() == LSI->CallOperator) - LambdaParamPackReferences.push_back(Param); + for (auto &Pack : Unexpanded) { + auto *VD = dyn_cast_or_null<VarDecl>( + Pack.first.dyn_cast<NamedDecl *>()); + if (VD && VD->getDeclContext() == LSI->CallOperator) + LambdaParamPackReferences.push_back(Pack); } } @@ -586,11 +586,15 @@ Sema::CheckPackExpansion(TypeSourceInfo QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, Optional<unsigned> NumExpansions) { - // C++0x [temp.variadic]p5: + // C++11 [temp.variadic]p5: // The pattern of a pack expansion shall name one or more // parameter packs that are not expanded by a nested pack // expansion. - if (!Pattern->containsUnexpandedParameterPack()) { + // + // A pattern containing a deduced type can't occur "naturally" but arises in + // the desugaring of an init-capture pack. + if (!Pattern->containsUnexpandedParameterPack() && + !Pattern->getContainedDeducedType()) { Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << PatternRange; return QualType(); @@ -641,7 +645,7 @@ bool Sema::CheckParameterPacksForExpansi // Compute the depth and index for this parameter pack. unsigned Depth = 0, Index = 0; IdentifierInfo *Name; - bool IsFunctionParameterPack = false; + bool IsVarDeclPack = false; if (const TemplateTypeParmType *TTP = i->first.dyn_cast<const TemplateTypeParmType *>()) { @@ -650,8 +654,8 @@ bool Sema::CheckParameterPacksForExpansi Name = TTP->getIdentifier(); } else { NamedDecl *ND = i->first.get<NamedDecl *>(); - if (isa<ParmVarDecl>(ND)) - IsFunctionParameterPack = true; + if (isa<VarDecl>(ND)) + IsVarDeclPack = true; else std::tie(Depth, Index) = getDepthAndIndex(ND); @@ -660,7 +664,7 @@ bool Sema::CheckParameterPacksForExpansi // Determine the size of this argument pack. unsigned NewPackSize; - if (IsFunctionParameterPack) { + if (IsVarDeclPack) { // Figure out whether we're instantiating to an argument pack or not. typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; @@ -694,7 +698,7 @@ bool Sema::CheckParameterPacksForExpansi // Template argument deduction can extend the sequence of template // arguments corresponding to a template parameter pack, even when the // sequence contains explicitly specified template arguments. - if (!IsFunctionParameterPack && CurrentInstantiationScope) { + if (!IsVarDeclPack && CurrentInstantiationScope) { if (NamedDecl *PartialPack = CurrentInstantiationScope->getPartiallySubstitutedPack()){ unsigned PartialDepth, PartialIndex; @@ -778,8 +782,8 @@ Optional<unsigned> Sema::getNumArguments Index = TTP->getIndex(); } else { NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); - if (isa<ParmVarDecl>(ND)) { - // Function parameter pack. + if (isa<VarDecl>(ND)) { + // Function parameter pack or init-capture pack. typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation @@ -1084,7 +1088,7 @@ Optional<unsigned> Sema::getFullyPackExp dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr())) Pack = Subst->getArgumentPack(); else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) { - for (ParmVarDecl *PD : *Subst) + for (VarDecl *PD : *Subst) if (PD->isParameterPack()) return None; return Subst->getNumExpansions(); Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Tue May 21 13:10:50 2019 @@ -450,8 +450,10 @@ public: /// TransformDefinition. However, in some cases (e.g., lambda expressions), /// the transformer itself has to transform the declarations. This routine /// can be overridden by a subclass that keeps track of such mappings. - void transformedLocalDecl(Decl *Old, Decl *New) { - TransformedLocalDecls[Old] = New; + void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> New) { + assert(New.size() == 1 && + "must override transformedLocalDecl if performing pack expansion"); + TransformedLocalDecls[Old] = New.front(); } /// Transform the definition of the given declaration. @@ -7122,7 +7124,7 @@ TreeTransform<Derived>::TransformCorouti auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation()); if (!Promise) return StmtError(); - getDerived().transformedLocalDecl(S->getPromiseDecl(), Promise); + getDerived().transformedLocalDecl(S->getPromiseDecl(), {Promise}); ScopeInfo->CoroutinePromise = Promise; // Transform the implicit coroutine statements we built during the initial @@ -11176,33 +11178,80 @@ TreeTransform<Derived>::TransformLambdaE // Transform any init-capture expressions before entering the scope of the // lambda body, because they are not semantically within that scope. typedef std::pair<ExprResult, QualType> InitCaptureInfoTy; - SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes; - InitCaptureExprsAndTypes.resize(E->explicit_capture_end() - - E->explicit_capture_begin()); + struct TransformedInitCapture { + // The location of the ... if the result is retaining a pack expansion. + SourceLocation EllipsisLoc; + // Zero or more expansions of the init-capture. + SmallVector<InitCaptureInfoTy, 4> Expansions; + }; + SmallVector<TransformedInitCapture, 4> InitCaptures; + InitCaptures.resize(E->explicit_capture_end() - E->explicit_capture_begin()); for (LambdaExpr::capture_iterator C = E->capture_begin(), CEnd = E->capture_end(); C != CEnd; ++C) { if (!E->isInitCapture(C)) continue; - EnterExpressionEvaluationContext EEEC( - getSema(), Sema::ExpressionEvaluationContext::PotentiallyEvaluated); - ExprResult NewExprInitResult = getDerived().TransformInitializer( - C->getCapturedVar()->getInit(), - C->getCapturedVar()->getInitStyle() == VarDecl::CallInit); - - if (NewExprInitResult.isInvalid()) - return ExprError(); - Expr *NewExprInit = NewExprInitResult.get(); + TransformedInitCapture &Result = InitCaptures[C - E->capture_begin()]; VarDecl *OldVD = C->getCapturedVar(); - QualType NewInitCaptureType = - getSema().buildLambdaInitCaptureInitialization( - C->getLocation(), OldVD->getType()->isReferenceType(), - OldVD->getIdentifier(), - C->getCapturedVar()->getInitStyle() != VarDecl::CInit, NewExprInit); - NewExprInitResult = NewExprInit; - InitCaptureExprsAndTypes[C - E->capture_begin()] = - std::make_pair(NewExprInitResult, NewInitCaptureType); + + auto SubstInitCapture = [&](SourceLocation EllipsisLoc, + Optional<unsigned> NumExpansions) { + EnterExpressionEvaluationContext EEEC( + getSema(), Sema::ExpressionEvaluationContext::PotentiallyEvaluated); + ExprResult NewExprInitResult = getDerived().TransformInitializer( + OldVD->getInit(), OldVD->getInitStyle() == VarDecl::CallInit); + + if (NewExprInitResult.isInvalid()) { + Result.Expansions.push_back(InitCaptureInfoTy(ExprError(), QualType())); + return; + } + Expr *NewExprInit = NewExprInitResult.get(); + + QualType NewInitCaptureType = + getSema().buildLambdaInitCaptureInitialization( + C->getLocation(), OldVD->getType()->isReferenceType(), + EllipsisLoc, NumExpansions, OldVD->getIdentifier(), + C->getCapturedVar()->getInitStyle() != VarDecl::CInit, + NewExprInit); + Result.Expansions.push_back( + InitCaptureInfoTy(NewExprInit, NewInitCaptureType)); + }; + + // If this is an init-capture pack, consider expanding the pack now. + if (OldVD->isParameterPack()) { + PackExpansionTypeLoc ExpansionTL = OldVD->getTypeSourceInfo() + ->getTypeLoc() + .castAs<PackExpansionTypeLoc>(); + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(OldVD->getInit(), Unexpanded); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + Optional<unsigned> OrigNumExpansions = + ExpansionTL.getTypePtr()->getNumExpansions(); + Optional<unsigned> NumExpansions = OrigNumExpansions; + if (getDerived().TryExpandParameterPacks( + ExpansionTL.getEllipsisLoc(), + OldVD->getInit()->getSourceRange(), Unexpanded, Expand, + RetainExpansion, NumExpansions)) + return ExprError(); + if (Expand) { + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); + SubstInitCapture(SourceLocation(), None); + } + } + if (!Expand || RetainExpansion) { + ForgetPartiallySubstitutedPackRAII Forget(getDerived()); + SubstInitCapture(ExpansionTL.getEllipsisLoc(), NumExpansions); + Result.EllipsisLoc = ExpansionTL.getEllipsisLoc(); + } + } else { + SubstInitCapture(SourceLocation(), None); + } } // Transform the template parameters, and add them to the current @@ -11245,7 +11294,7 @@ TreeTransform<Derived>::TransformLambdaE NewCallOpTSI, /*KnownDependent=*/false, E->getCaptureDefault()); - getDerived().transformedLocalDecl(E->getLambdaClass(), Class); + getDerived().transformedLocalDecl(E->getLambdaClass(), {Class}); // Build the call operator. CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition( @@ -11270,7 +11319,7 @@ TreeTransform<Derived>::TransformLambdaE } getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); - getDerived().transformedLocalDecl(E->getCallOperator(), NewCallOperator); + getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); // Introduce the context of the call operator. Sema::ContextRAII SavedContext(getSema(), NewCallOperator, @@ -11313,24 +11362,33 @@ TreeTransform<Derived>::TransformLambdaE // Rebuild init-captures, including the implied field declaration. if (E->isInitCapture(C)) { - InitCaptureInfoTy InitExprTypePair = - InitCaptureExprsAndTypes[C - E->capture_begin()]; - ExprResult Init = InitExprTypePair.first; - QualType InitQualType = InitExprTypePair.second; - if (Init.isInvalid() || InitQualType.isNull()) { - Invalid = true; - continue; - } + TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()]; + VarDecl *OldVD = C->getCapturedVar(); - VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl( - OldVD->getLocation(), InitExprTypePair.second, OldVD->getIdentifier(), - OldVD->getInitStyle(), Init.get()); - if (!NewVD) - Invalid = true; - else { - getDerived().transformedLocalDecl(OldVD, NewVD); + llvm::SmallVector<Decl*, 4> NewVDs; + + for (InitCaptureInfoTy &Info : NewC.Expansions) { + ExprResult Init = Info.first; + QualType InitQualType = Info.second; + if (Init.isInvalid() || InitQualType.isNull()) { + Invalid = true; + break; + } + VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl( + OldVD->getLocation(), InitQualType, NewC.EllipsisLoc, + OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get()); + if (!NewVD) { + Invalid = true; + break; + } + NewVDs.push_back(NewVD); + getSema().buildInitCaptureField(LSI, NewVD); } - getSema().buildInitCaptureField(LSI, NewVD); + + if (Invalid) + break; + + getDerived().transformedLocalDecl(OldVD, NewVDs); continue; } @@ -12471,8 +12529,7 @@ TreeTransform<Derived>::TransformBlockEx VarDecl *oldCapture = I.getVariable(); // Ignore parameter packs. - if (isa<ParmVarDecl>(oldCapture) && - cast<ParmVarDecl>(oldCapture)->isParameterPack()) + if (oldCapture->isParameterPack()) continue; VarDecl *newCapture = Modified: cfe/trunk/lib/Serialization/ASTReader.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue May 21 13:10:50 2019 @@ -6141,8 +6141,13 @@ QualType ASTReader::readTypeRecord(unsig case TYPE_AUTO: { QualType Deduced = readType(*Loc.F, Record, Idx); AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++]; - bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; - return Context.getAutoType(Deduced, Keyword, IsDependent); + bool IsDependent = false, IsPack = false; + if (Deduced.isNull()) { + IsDependent = Record[Idx] > 0; + IsPack = Record[Idx] > 1; + ++Idx; + } + return Context.getAutoType(Deduced, Keyword, IsDependent, IsPack); } case TYPE_DEDUCED_TEMPLATE_SPECIALIZATION: { Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue May 21 13:10:50 2019 @@ -1803,9 +1803,9 @@ void ASTStmtReader::VisitFunctionParmPac E->NumParameters = Record.readInt(); E->ParamPack = ReadDeclAs<ParmVarDecl>(); E->NameLoc = ReadSourceLocation(); - auto **Parms = E->getTrailingObjects<ParmVarDecl *>(); + auto **Parms = E->getTrailingObjects<VarDecl *>(); for (unsigned i = 0, n = E->NumParameters; i != n; ++i) - Parms[i] = ReadDeclAs<ParmVarDecl>(); + Parms[i] = ReadDeclAs<VarDecl>(); } void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue May 21 13:10:50 2019 @@ -369,7 +369,8 @@ void ASTTypeWriter::VisitAutoType(const Record.AddTypeRef(T->getDeducedType()); Record.push_back((unsigned)T->getKeyword()); if (T->getDeducedType().isNull()) - Record.push_back(T->isDependentType()); + Record.push_back(T->containsUnexpandedParameterPack() ? 2 : + T->isDependentType() ? 1 : 0); Code = TYPE_AUTO; } Added: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.capture/p17.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.capture/p17.cpp?rev=361300&view=auto ============================================================================== --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.capture/p17.cpp (added) +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.capture/p17.cpp Tue May 21 13:10:50 2019 @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +namespace std_example { + namespace std { template<typename T> T &&move(T &); } + + void g(...); + + template <class... Args> void f(Args... args) { + auto lm = [&, args...] { return g(args...); }; + lm(); + + auto lm2 = [... xs = std::move(args)] { return g(xs...); }; + lm2(); + } +} + +template<typename ...T> constexpr int f(int k, T ...t) { + auto a = [...v = t] (bool b) mutable { + if (!b) { + ((v += 1), ...); + return (__SIZE_TYPE__)0; + } + return (v * ... * 1) + sizeof...(v); + }; + for (int i = 0; i != k; ++i) + a(false); + return a(true); +} + +static_assert(f(1, 2, 3, 4) == 3 * 4 * 5 + 3); +static_assert(f(5) == 1); + +auto q = [...x = 0] {}; // expected-error {{does not contain any unexpanded parameter packs}} + +template<typename ...T> constexpr int nested(T ...t) { + return [...a = t] { + return [a...] { + return (a + ...); + }(); + }(); +} +static_assert(nested(1, 2, 3) == 6); Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp (original) +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp Tue May 21 13:10:50 2019 @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify -Wno-c++1y-extensions -// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify +// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify -Wno-c++1y-extensions -Wno-c++2a-extensions +// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify -Wno-c++2a-extensions +// RUN: %clang_cc1 -fsyntax-only -std=c++2a %s -verify void print(); @@ -60,8 +61,25 @@ template void variadic_lambda(int*, floa template<typename ...Args> void init_capture_pack_err(Args ...args) { - [as(args)...] {} (); // expected-error {{expected ','}} - [as...(args)]{} (); // expected-error {{expected ','}} + [...as(args)]{} (); + [as(args)...] {} (); // expected-error {{ellipsis in pack init-capture must appear before the name of the capture}} + [as...(args)]{} (); // expected-error {{ellipsis in pack init-capture must appear before the name of the capture}} + [...as{args}]{} (); + [as{args}...] {} (); // expected-error {{ellipsis in pack init-capture must appear before the name of the capture}} + [as...{args}]{} (); // expected-error {{ellipsis in pack init-capture must appear before the name of the capture}} + [...as = args]{} (); + [as = args...] {} (); // expected-error {{ellipsis in pack init-capture must appear before the name of the capture}} + [as... = args]{} (); // expected-error {{ellipsis in pack init-capture must appear before the name of the capture}} + + [&...as(args)]{} (); + [...&as(args)]{} (); // expected-error {{ellipsis in pack init-capture must appear before the name of the capture}} + + [args...] {} (); + [...args] {} (); // expected-error {{ellipsis in pack capture must appear after the name of the capture}} + + [&args...] {} (); + [...&args] {} (); // expected-error {{ellipsis in pack capture must appear after the name of the capture}} + [&...args] {} (); // expected-error {{ellipsis in pack capture must appear after the name of the capture}} } template<typename ...Args> Added: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp?rev=361300&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp (added) +++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp Tue May 21 13:10:50 2019 @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +namespace p3 { + void bar(...); + template <typename... Args> void foo(Args... args) { + (void)[... xs = args] { + bar(xs...); + }; + } + + void use() { + foo(); + foo(1); + } +} + +template<typename ...T> void f(T ...t) { + (void)[&...x = t] { + x; // expected-error {{unexpanded parameter pack 'x'}} + }; + + // Not OK: can't expand 'x' outside its scope. + weird((void)[&...x = t] { + return &x; // expected-error {{unexpanded parameter pack 'x'}} + }... // expected-error {{does not contain any unexpanded}} + ); + + // OK, capture only one 'slice' of 'x'. + weird((void)[&x = t] { + return &x; + }... + ); + + // 'x' is not expanded by the outer '...', but 'T' is. + weird((void)[&... x = t] { + return T() + &x; // expected-error {{unexpanded parameter pack 'x'}} + }... // expected-error {{does not contain any unexpanded}} + ); +} Added: cfe/trunk/test/FixIt/fixit-c++2a.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-c%2B%2B2a.cpp?rev=361300&view=auto ============================================================================== --- cfe/trunk/test/FixIt/fixit-c++2a.cpp (added) +++ cfe/trunk/test/FixIt/fixit-c++2a.cpp Tue May 21 13:10:50 2019 @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify -std=c++2a %s +// RUN: cp %s %t +// RUN: not %clang_cc1 -x c++ -std=c++2a -fixit %t +// RUN: %clang_cc1 -Wall -pedantic -x c++ -std=c++2a %t + +/* This is a test of the various code modification hints that only + apply in C++2a. */ +template<typename ...T> void init_capture_pack(T ...a) { + [x... = a]{}; // expected-error {{must appear before the name}} + [x = a...]{}; // expected-error {{must appear before the name}} + [...&x = a]{}; // expected-error {{must appear before the name}} + [...a]{}; // expected-error {{must appear after the name}} + [&...a]{}; // expected-error {{must appear after the name}} + [...&a]{}; // expected-error {{must appear after the name}} +} Modified: cfe/trunk/test/SemaTemplate/sizeof-pack.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/sizeof-pack.cpp?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/sizeof-pack.cpp (original) +++ cfe/trunk/test/SemaTemplate/sizeof-pack.cpp Tue May 21 13:10:50 2019 @@ -1,7 +1,13 @@ // RUN: %clang_cc1 -std=c++11 -verify %s -// expected-no-diagnostics template<int &...Ns> int f() { return sizeof...(Ns); } template int f<>(); + +template<typename ...T> int g() { + return [...x = T()] { // expected-warning 2{{extension}} + return sizeof...(x); + }(); +} +template int g<>(); Modified: cfe/trunk/www/cxx_status.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=361300&r1=361299&r2=361300&view=diff ============================================================================== --- cfe/trunk/www/cxx_status.html (original) +++ cfe/trunk/www/cxx_status.html Tue May 21 13:10:50 2019 @@ -949,7 +949,7 @@ as the draft C++2a standard evolves. <tr> <td>Pack expansion in lambda <i>init-capture</i></td> <td><a href="http://wg21.link/p0780r2">P0780R2</a></td> - <td class="none" align="center">No</td> + <td class="svn" align="center">SVN</td> </tr> <!-- Rapperswil papers --> <tr> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits