/// 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;
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 {
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
}
};
-/// 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
/// \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;
/// 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; }
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;
}
}
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) {
"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">;
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<
"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<
/// 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.
/// variables appropriately.
VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
QualType InitCaptureType,
+ SourceLocation EllipsisLoc,
IdentifierInfo *Id,
unsigned InitStyle, Expr *Init);
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
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
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
/// 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);
if (AutoDeductTy.isNull())
AutoDeductTy = QualType(
new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
- /*dependent*/false),
+ /*dependent*/false, /*pack*/false),
0);
return AutoDeductTy;
}
return Eval->IsICE;
}
+bool VarDecl::isParameterPack() const {
+ return isa<PackExpansionType>(getType());
+}
+
template<typename DeclT>
static DeclT *getDefinitionOrSelf(DeclT *D) {
assert(D);
!Init.isNull();
}
-bool ParmVarDecl::isParameterPack() const {
- return isa<PackExpansionType>(getType());
-}
-
void ParmVarDecl::setParameterIndexLarge(unsigned parameterIndex) {
getASTContext().setParameterIndex(this, parameterIndex);
ParmVarDeclBits.ParameterIndex = ParameterIndexSentinel;
}
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();
}
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);
}
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);
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>
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!
// FIXME: not clear how to mangle this!
const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E);
Out << "v110_SUBSTPACK";
- mangleFunctionParam(FPPE->getParameterPack());
+ mangleDeclRefExpr(FPPE->getParameterPack());
break;
}
case VarDecl::ListInit: JOS.attribute("init", "list"); break;
}
}
+ attributeOnlyIfTrue("isParameterPack", VD->isParameterPack());
}
void JSONNodeDumper::VisitFieldDecl(const FieldDecl *FD) {
break;
}
}
+ if (D->isParameterPack())
+ OS << " pack";
}
void TextNodeDumper::VisitBindingDecl(const BindingDecl *D) {
Type *VisitAdjustedType(const AdjustedType *T) {
return Visit(T->getOriginalType());
}
+
+ Type *VisitPackExpansionType(const PackExpansionType *T) {
+ return Visit(T->getPattern());
+ }
};
} // namespace
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "llvm/Support/ErrorHandling.h"
-
+#include <numeric>
using namespace clang;
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();
}
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))) {
LambdaCaptureInitKind InitKind = LambdaCaptureInitKind::NoInit;
SourceLocation Loc;
IdentifierInfo *Id = nullptr;
- SourceLocation EllipsisLoc;
+ SourceLocation EllipsisLocs[4];
ExprResult Init;
SourceLocation LocStart = Tok.getLocation();
Kind = LCK_This;
Loc = ConsumeToken();
} else {
+ TryConsumeToken(tok::ellipsis, EllipsisLocs[0]);
+
if (Tok.is(tok::amp)) {
Kind = LCK_ByRef;
ConsumeToken();
}
}
+ TryConsumeToken(tok::ellipsis, EllipsisLocs[1]);
+
if (Tok.is(tok::identifier)) {
Id = Tok.getIdentifierInfo();
Loc = ConsumeToken();
});
}
+ TryConsumeToken(tok::ellipsis, EllipsisLocs[2]);
+
if (Tok.is(tok::l_paren)) {
BalancedDelimiterTracker Parens(*this, tok::l_paren);
Parens.consumeOpen();
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.
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;
}
}
-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();
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.
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.
? 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.
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:
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
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.
}
}
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) &&
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;
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;
}
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;
}
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);
}
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);
}
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.
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
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);
}
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());
// 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);
}
// 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
}
// 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);
#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);
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;
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);
}
}
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();
// 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 *>()) {
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);
// 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;
// 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;
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
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();
/// 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.
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
// 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
NewCallOpTSI,
/*KnownDependent=*/false,
E->getCaptureDefault());
- getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
+ getDerived().transformedLocalDecl(E->getLambdaClass(), {Class});
// Build the call operator.
CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
}
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,
// 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;
}
VarDecl *oldCapture = I.getVariable();
// Ignore parameter packs.
- if (isa<ParmVarDecl>(oldCapture) &&
- cast<ParmVarDecl>(oldCapture)->isParameterPack())
+ if (oldCapture->isParameterPack())
continue;
VarDecl *newCapture =
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: {
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) {
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;
}
--- /dev/null
+// 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);
-// 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();
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>
--- /dev/null
+// 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}}
+ );
+}
--- /dev/null
+// 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}}
+}
// 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<>();
<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>