[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.

llvm-svn: 361300
This commit is contained in:
Richard Smith 2019-05-21 20:10:50 +00:00
parent 6e19543a2a
commit b2997f579a
31 changed files with 543 additions and 245 deletions

View File

@ -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;

View File

@ -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

View File

@ -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; }

View File

@ -4797,9 +4797,9 @@ class AutoType : public DeducedType, public llvm::FoldingSetNode {
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) {

View File

@ -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_lambda : Warning<
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<

View File

@ -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<

View File

@ -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);

View File

@ -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

View File

@ -4372,7 +4372,13 @@ QualType ASTContext::getPackExpansionType(QualType Pattern,
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::getUnaryTransformType(QualType BaseType,
/// 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() const {
if (AutoDeductTy.isNull())
AutoDeductTy = QualType(
new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
/*dependent*/false),
/*dependent*/false, /*pack*/false),
0);
return AutoDeductTy;
}

View File

@ -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;

View File

@ -208,8 +208,8 @@ bool Decl::isTemplateParameterPack() const {
}
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();
}

View File

@ -1541,30 +1541,30 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
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);
}

View File

@ -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::mangleInitListElements(const InitListExpr *InitList) {
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;
}

View File

@ -539,6 +539,7 @@ void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) {
case VarDecl::ListInit: JOS.attribute("init", "list"); break;
}
}
attributeOnlyIfTrue("isParameterPack", VD->isParameterPack());
}
void JSONNodeDumper::VisitFieldDecl(const FieldDecl *FD) {

View File

@ -1366,6 +1366,8 @@ void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
break;
}
}
if (D->isParameterPack())
OS << " pack";
}
void TextNodeDumper::VisitBindingDecl(const BindingDecl *D) {

View File

@ -1743,6 +1743,10 @@ namespace {
Type *VisitAdjustedType(const AdjustedType *T) {
return Visit(T->getOriginalType());
}
Type *VisitPackExpansionType(const PackExpansionType *T) {
return Visit(T->getPattern());
}
};
} // namespace

View File

@ -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::TryParseLambdaExpression() {
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(LambdaIntroducer &Intro,
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(LambdaIntroducer &Intro,
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(LambdaIntroducer &Intro,
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(LambdaIntroducer &Intro,
}
}
TryConsumeToken(tok::ellipsis, EllipsisLocs[1]);
if (Tok.is(tok::identifier)) {
Id = Tok.getIdentifierInfo();
Loc = ConsumeToken();
@ -901,6 +914,8 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
});
}
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(LambdaIntroducer &Intro,
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(LambdaIntroducer &Intro,
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.
// 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;
// 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.
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;

View File

@ -753,11 +753,10 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
}
}
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::buildLambdaInitCaptureInitialization(SourceLocation Loc,
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::buildLambdaInitCaptureInitialization(SourceLocation Loc,
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(LambdaIntroducer &Intro,
? 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(LambdaIntroducer &Intro,
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(LambdaIntroducer &Intro,
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(LambdaIntroducer &Intro,
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.
}

View File

@ -4280,19 +4280,26 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
}
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, QualType &Result,
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 *&Init, QualType &Result,
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 *&Init, QualType &Result,
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 TypeWithAuto,
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);
}

View File

@ -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::TransformSubstNonTypeTemplateParmPackExpr(
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::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
// 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::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
}
// 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::TransformDeclRefExpr(DeclRefExpr *E) {
}
// 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::InstantiatedLocal(const Decl *D, Decl *Inst) {
#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);

View File

@ -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(SourceLocation Loc,
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 *Pattern, SourceLocation EllipsisLoc,
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::CheckParameterPacksForExpansion(
// 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::CheckParameterPacksForExpansion(
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::CheckParameterPacksForExpansion(
// 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::CheckParameterPacksForExpansion(
// 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::getNumArgumentsInExpansion(QualType T,
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::getFullyPackExpandedSize(TemplateArgument Arg) {
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();

View File

@ -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>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
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>::TransformLambdaExpr(LambdaExpr *E) {
// 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>::TransformLambdaExpr(LambdaExpr *E) {
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>::TransformLambdaExpr(LambdaExpr *E) {
}
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>::TransformLambdaExpr(LambdaExpr *E) {
// 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>::TransformBlockExpr(BlockExpr *E) {
VarDecl *oldCapture = I.getVariable();
// Ignore parameter packs.
if (isa<ParmVarDecl>(oldCapture) &&
cast<ParmVarDecl>(oldCapture)->isParameterPack())
if (oldCapture->isParameterPack())
continue;
VarDecl *newCapture =

View File

@ -6141,8 +6141,13 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
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: {

View File

@ -1803,9 +1803,9 @@ void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
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) {

View File

@ -369,7 +369,8 @@ void ASTTypeWriter::VisitAutoType(const AutoType *T) {
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;
}

View File

@ -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);

View File

@ -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*, float*, double*);
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>

View File

@ -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}}
);
}

View File

@ -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}}
}

View File

@ -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<>();

View File

@ -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>