forked from OSchip/llvm-project
[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:
parent
6e19543a2a
commit
b2997f579a
|
@ -1522,7 +1522,7 @@ public:
|
||||||
|
|
||||||
/// C++11 deduced auto type.
|
/// C++11 deduced auto type.
|
||||||
QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
|
QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
|
||||||
bool IsDependent) const;
|
bool IsDependent, bool IsPack = false) const;
|
||||||
|
|
||||||
/// C++11 deduction pattern for 'auto' type.
|
/// C++11 deduction pattern for 'auto' type.
|
||||||
QualType getAutoDeductType() const;
|
QualType getAutoDeductType() const;
|
||||||
|
|
|
@ -1395,6 +1395,10 @@ public:
|
||||||
NonParmVarDeclBits.IsInitCapture = IC;
|
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
|
/// Whether this local extern variable declaration's previous declaration
|
||||||
/// was declared in the same block scope. Only correct in C++.
|
/// was declared in the same block scope. Only correct in C++.
|
||||||
bool isPreviousDeclInSameBlockScope() const {
|
bool isPreviousDeclInSameBlockScope() const {
|
||||||
|
@ -1688,10 +1692,6 @@ public:
|
||||||
|
|
||||||
QualType getOriginalType() const;
|
QualType getOriginalType() const;
|
||||||
|
|
||||||
/// Determine whether this parameter is actually a function
|
|
||||||
/// parameter pack.
|
|
||||||
bool isParameterPack() const;
|
|
||||||
|
|
||||||
/// Sets the function declaration that owns this
|
/// Sets the function declaration that owns this
|
||||||
/// ParmVarDecl. Since ParmVarDecls are often created before the
|
/// ParmVarDecl. Since ParmVarDecls are often created before the
|
||||||
/// FunctionDecls that own them, this routine is required to update
|
/// FunctionDecls that own them, this routine is required to update
|
||||||
|
|
|
@ -4233,8 +4233,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents a reference to a function parameter pack that has been
|
/// Represents a reference to a function parameter pack or init-capture pack
|
||||||
/// substituted but not yet expanded.
|
/// that has been substituted but not yet expanded.
|
||||||
///
|
///
|
||||||
/// When a pack expansion contains multiple parameter packs at different levels,
|
/// 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
|
/// this node is used to represent a function parameter pack at an outer level
|
||||||
|
@ -4249,13 +4249,13 @@ public:
|
||||||
/// \endcode
|
/// \endcode
|
||||||
class FunctionParmPackExpr final
|
class FunctionParmPackExpr final
|
||||||
: public Expr,
|
: public Expr,
|
||||||
private llvm::TrailingObjects<FunctionParmPackExpr, ParmVarDecl *> {
|
private llvm::TrailingObjects<FunctionParmPackExpr, VarDecl *> {
|
||||||
friend class ASTReader;
|
friend class ASTReader;
|
||||||
friend class ASTStmtReader;
|
friend class ASTStmtReader;
|
||||||
friend TrailingObjects;
|
friend TrailingObjects;
|
||||||
|
|
||||||
/// The function parameter pack which was referenced.
|
/// The function parameter pack which was referenced.
|
||||||
ParmVarDecl *ParamPack;
|
VarDecl *ParamPack;
|
||||||
|
|
||||||
/// The location of the function parameter pack reference.
|
/// The location of the function parameter pack reference.
|
||||||
SourceLocation NameLoc;
|
SourceLocation NameLoc;
|
||||||
|
@ -4263,35 +4263,35 @@ class FunctionParmPackExpr final
|
||||||
/// The number of expansions of this pack.
|
/// The number of expansions of this pack.
|
||||||
unsigned NumParameters;
|
unsigned NumParameters;
|
||||||
|
|
||||||
FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
|
FunctionParmPackExpr(QualType T, VarDecl *ParamPack,
|
||||||
SourceLocation NameLoc, unsigned NumParams,
|
SourceLocation NameLoc, unsigned NumParams,
|
||||||
ParmVarDecl *const *Params);
|
VarDecl *const *Params);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static FunctionParmPackExpr *Create(const ASTContext &Context, QualType T,
|
static FunctionParmPackExpr *Create(const ASTContext &Context, QualType T,
|
||||||
ParmVarDecl *ParamPack,
|
VarDecl *ParamPack,
|
||||||
SourceLocation NameLoc,
|
SourceLocation NameLoc,
|
||||||
ArrayRef<ParmVarDecl *> Params);
|
ArrayRef<VarDecl *> Params);
|
||||||
static FunctionParmPackExpr *CreateEmpty(const ASTContext &Context,
|
static FunctionParmPackExpr *CreateEmpty(const ASTContext &Context,
|
||||||
unsigned NumParams);
|
unsigned NumParams);
|
||||||
|
|
||||||
/// Get the parameter pack which this expression refers to.
|
/// 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.
|
/// Get the location of the parameter pack.
|
||||||
SourceLocation getParameterPackLocation() const { return NameLoc; }
|
SourceLocation getParameterPackLocation() const { return NameLoc; }
|
||||||
|
|
||||||
/// Iterators over the parameters which the parameter pack expanded
|
/// Iterators over the parameters which the parameter pack expanded
|
||||||
/// into.
|
/// into.
|
||||||
using iterator = ParmVarDecl * const *;
|
using iterator = VarDecl * const *;
|
||||||
iterator begin() const { return getTrailingObjects<ParmVarDecl *>(); }
|
iterator begin() const { return getTrailingObjects<VarDecl *>(); }
|
||||||
iterator end() const { return begin() + NumParameters; }
|
iterator end() const { return begin() + NumParameters; }
|
||||||
|
|
||||||
/// Get the number of parameters in this parameter pack.
|
/// Get the number of parameters in this parameter pack.
|
||||||
unsigned getNumExpansions() const { return NumParameters; }
|
unsigned getNumExpansions() const { return NumParameters; }
|
||||||
|
|
||||||
/// Get an expansion of the parameter pack by index.
|
/// 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 getBeginLoc() const LLVM_READONLY { return NameLoc; }
|
||||||
SourceLocation getEndLoc() const LLVM_READONLY { return NameLoc; }
|
SourceLocation getEndLoc() const LLVM_READONLY { return NameLoc; }
|
||||||
|
|
|
@ -4797,9 +4797,9 @@ class AutoType : public DeducedType, public llvm::FoldingSetNode {
|
||||||
friend class ASTContext; // ASTContext creates these
|
friend class ASTContext; // ASTContext creates these
|
||||||
|
|
||||||
AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
|
AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
|
||||||
bool IsDeducedAsDependent)
|
bool IsDeducedAsDependent, bool IsDeducedAsPack)
|
||||||
: DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
|
: DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
|
||||||
IsDeducedAsDependent, /*ContainsPack=*/false) {
|
IsDeducedAsDependent, IsDeducedAsPack) {
|
||||||
AutoTypeBits.Keyword = (unsigned)Keyword;
|
AutoTypeBits.Keyword = (unsigned)Keyword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4813,14 +4813,16 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||||
Profile(ID, getDeducedType(), getKeyword(), isDependentType());
|
Profile(ID, getDeducedType(), getKeyword(), isDependentType(),
|
||||||
|
containsUnexpandedParameterPack());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
|
static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
|
||||||
AutoTypeKeyword Keyword, bool IsDependent) {
|
AutoTypeKeyword Keyword, bool IsDependent, bool IsPack) {
|
||||||
ID.AddPointer(Deduced.getAsOpaquePtr());
|
ID.AddPointer(Deduced.getAsOpaquePtr());
|
||||||
ID.AddInteger((unsigned)Keyword);
|
ID.AddInteger((unsigned)Keyword);
|
||||||
ID.AddBoolean(IsDependent);
|
ID.AddBoolean(IsDependent);
|
||||||
|
ID.AddBoolean(IsPack);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool classof(const Type *T) {
|
static bool classof(const Type *T) {
|
||||||
|
|
|
@ -878,6 +878,11 @@ def err_lambda_missing_parens : Error<
|
||||||
"attribute specifier|'constexpr'}0">;
|
"attribute specifier|'constexpr'}0">;
|
||||||
def err_lambda_decl_specifier_repeated : Error<
|
def err_lambda_decl_specifier_repeated : Error<
|
||||||
"%select{'mutable'|'constexpr'}0 cannot appear multiple times in a lambda declarator">;
|
"%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
|
// C++17 lambda expressions
|
||||||
def err_expected_star_this_capture : Error<
|
def err_expected_star_this_capture : Error<
|
||||||
"expected 'this' following '*' in lambda capture list">;
|
"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<
|
def ext_constexpr_on_lambda_cxx17 : ExtWarn<
|
||||||
"'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>;
|
"'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>;
|
||||||
|
|
||||||
// C++2a template lambdas
|
// C++2a template lambdas
|
||||||
def ext_lambda_template_parameter_list: ExtWarn<
|
def ext_lambda_template_parameter_list: ExtWarn<
|
||||||
"explicit template parameter list for lambdas is a C++2a extension">,
|
"explicit template parameter list for lambdas is a C++2a extension">,
|
||||||
InGroup<CXX2a>;
|
InGroup<CXX2a>;
|
||||||
def warn_cxx17_compat_lambda_template_parameter_list: Warning<
|
def warn_cxx17_compat_lambda_template_parameter_list: Warning<
|
||||||
"explicit template parameter list for lambdas is incompatible with "
|
"explicit template parameter list for lambdas is incompatible with "
|
||||||
"C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
|
"C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
|
||||||
def err_lambda_template_parameter_list_empty : Error<
|
def err_lambda_template_parameter_list_empty : Error<
|
||||||
"lambda template parameter list cannot be empty">;
|
"lambda template parameter list cannot be empty">;
|
||||||
|
|
||||||
// Availability attribute
|
// Availability attribute
|
||||||
def err_expected_version : Error<
|
def err_expected_version : Error<
|
||||||
|
|
|
@ -6663,6 +6663,11 @@ let CategoryName = "Lambda Issue" in {
|
||||||
"cannot deduce type for lambda capture %0 from initializer of type %2">;
|
"cannot deduce type for lambda capture %0 from initializer of type %2">;
|
||||||
def err_init_capture_deduction_failure_from_init_list : Error<
|
def err_init_capture_deduction_failure_from_init_list : Error<
|
||||||
"cannot deduce type for lambda capture %0 from initializer list">;
|
"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.
|
// C++14 generic lambdas.
|
||||||
def warn_cxx11_compat_generic_lambda : Warning<
|
def warn_cxx11_compat_generic_lambda : Warning<
|
||||||
|
|
|
@ -5711,14 +5711,16 @@ public:
|
||||||
/// any implicit conversions such as an lvalue-to-rvalue conversion if
|
/// any implicit conversions such as an lvalue-to-rvalue conversion if
|
||||||
/// not being used to initialize a reference.
|
/// not being used to initialize a reference.
|
||||||
ParsedType actOnLambdaInitCaptureInitialization(
|
ParsedType actOnLambdaInitCaptureInitialization(
|
||||||
SourceLocation Loc, bool ByRef, IdentifierInfo *Id,
|
SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc,
|
||||||
LambdaCaptureInitKind InitKind, Expr *&Init) {
|
IdentifierInfo *Id, LambdaCaptureInitKind InitKind, Expr *&Init) {
|
||||||
return ParsedType::make(buildLambdaInitCaptureInitialization(
|
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,
|
QualType buildLambdaInitCaptureInitialization(
|
||||||
IdentifierInfo *Id,
|
SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc,
|
||||||
bool DirectInit, Expr *&Init);
|
Optional<unsigned> NumExpansions, IdentifierInfo *Id, bool DirectInit,
|
||||||
|
Expr *&Init);
|
||||||
|
|
||||||
/// Create a dummy variable within the declcontext of the lambda's
|
/// Create a dummy variable within the declcontext of the lambda's
|
||||||
/// call operator, for name lookup purposes for a lambda init capture.
|
/// call operator, for name lookup purposes for a lambda init capture.
|
||||||
|
@ -5727,6 +5729,7 @@ public:
|
||||||
/// variables appropriately.
|
/// variables appropriately.
|
||||||
VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
|
VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc,
|
||||||
QualType InitCaptureType,
|
QualType InitCaptureType,
|
||||||
|
SourceLocation EllipsisLoc,
|
||||||
IdentifierInfo *Id,
|
IdentifierInfo *Id,
|
||||||
unsigned InitStyle, Expr *Init);
|
unsigned InitStyle, Expr *Init);
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,7 @@ class VarDecl;
|
||||||
class LocalInstantiationScope {
|
class LocalInstantiationScope {
|
||||||
public:
|
public:
|
||||||
/// A set of declarations.
|
/// A set of declarations.
|
||||||
using DeclArgumentPack = SmallVector<ParmVarDecl *, 4>;
|
using DeclArgumentPack = SmallVector<VarDecl *, 4>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Reference to the semantic analysis that is performing
|
/// Reference to the semantic analysis that is performing
|
||||||
|
@ -378,7 +378,7 @@ class VarDecl;
|
||||||
findInstantiationOf(const Decl *D);
|
findInstantiationOf(const Decl *D);
|
||||||
|
|
||||||
void InstantiatedLocal(const Decl *D, Decl *Inst);
|
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);
|
void MakeInstantiatedLocalArgPack(const Decl *D);
|
||||||
|
|
||||||
/// Note that the given parameter pack has been partially substituted
|
/// Note that the given parameter pack has been partially substituted
|
||||||
|
|
|
@ -4372,7 +4372,13 @@ QualType ASTContext::getPackExpansionType(QualType Pattern,
|
||||||
llvm::FoldingSetNodeID ID;
|
llvm::FoldingSetNodeID ID;
|
||||||
PackExpansionType::Profile(ID, Pattern, NumExpansions);
|
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");
|
"Pack expansions must expand one or more parameter packs");
|
||||||
void *InsertPos = nullptr;
|
void *InsertPos = nullptr;
|
||||||
PackExpansionType *T
|
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
|
/// deduced to the given type, or to the canonical undeduced 'auto' type, or the
|
||||||
/// canonical deduced-but-dependent 'auto' type.
|
/// canonical deduced-but-dependent 'auto' type.
|
||||||
QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
|
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)
|
if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent)
|
||||||
return getAutoDeductType();
|
return getAutoDeductType();
|
||||||
|
|
||||||
// Look in the folding set for an existing type.
|
// Look in the folding set for an existing type.
|
||||||
void *InsertPos = nullptr;
|
void *InsertPos = nullptr;
|
||||||
llvm::FoldingSetNodeID ID;
|
llvm::FoldingSetNodeID ID;
|
||||||
AutoType::Profile(ID, DeducedType, Keyword, IsDependent);
|
AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack);
|
||||||
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
|
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||||
return QualType(AT, 0);
|
return QualType(AT, 0);
|
||||||
|
|
||||||
auto *AT = new (*this, TypeAlignment)
|
auto *AT = new (*this, TypeAlignment)
|
||||||
AutoType(DeducedType, Keyword, IsDependent);
|
AutoType(DeducedType, Keyword, IsDependent, IsPack);
|
||||||
Types.push_back(AT);
|
Types.push_back(AT);
|
||||||
if (InsertPos)
|
if (InsertPos)
|
||||||
AutoTypes.InsertNode(AT, InsertPos);
|
AutoTypes.InsertNode(AT, InsertPos);
|
||||||
|
@ -4946,7 +4953,7 @@ QualType ASTContext::getAutoDeductType() const {
|
||||||
if (AutoDeductTy.isNull())
|
if (AutoDeductTy.isNull())
|
||||||
AutoDeductTy = QualType(
|
AutoDeductTy = QualType(
|
||||||
new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
|
new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
|
||||||
/*dependent*/false),
|
/*dependent*/false, /*pack*/false),
|
||||||
0);
|
0);
|
||||||
return AutoDeductTy;
|
return AutoDeductTy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2397,6 +2397,10 @@ bool VarDecl::checkInitIsICE() const {
|
||||||
return Eval->IsICE;
|
return Eval->IsICE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VarDecl::isParameterPack() const {
|
||||||
|
return isa<PackExpansionType>(getType());
|
||||||
|
}
|
||||||
|
|
||||||
template<typename DeclT>
|
template<typename DeclT>
|
||||||
static DeclT *getDefinitionOrSelf(DeclT *D) {
|
static DeclT *getDefinitionOrSelf(DeclT *D) {
|
||||||
assert(D);
|
assert(D);
|
||||||
|
@ -2683,10 +2687,6 @@ bool ParmVarDecl::hasDefaultArg() const {
|
||||||
!Init.isNull();
|
!Init.isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParmVarDecl::isParameterPack() const {
|
|
||||||
return isa<PackExpansionType>(getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ParmVarDecl::setParameterIndexLarge(unsigned parameterIndex) {
|
void ParmVarDecl::setParameterIndexLarge(unsigned parameterIndex) {
|
||||||
getASTContext().setParameterIndex(this, parameterIndex);
|
getASTContext().setParameterIndex(this, parameterIndex);
|
||||||
ParmVarDeclBits.ParameterIndex = ParameterIndexSentinel;
|
ParmVarDeclBits.ParameterIndex = ParameterIndexSentinel;
|
||||||
|
|
|
@ -208,8 +208,8 @@ bool Decl::isTemplateParameterPack() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Decl::isParameterPack() const {
|
bool Decl::isParameterPack() const {
|
||||||
if (const auto *Parm = dyn_cast<ParmVarDecl>(this))
|
if (const auto *Var = dyn_cast<VarDecl>(this))
|
||||||
return Parm->isParameterPack();
|
return Var->isParameterPack();
|
||||||
|
|
||||||
return isTemplateParameterPack();
|
return isTemplateParameterPack();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1541,30 +1541,30 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
|
||||||
return TemplateArgument(llvm::makeArrayRef(Arguments, NumArguments));
|
return TemplateArgument(llvm::makeArrayRef(Arguments, NumArguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
|
FunctionParmPackExpr::FunctionParmPackExpr(QualType T, VarDecl *ParamPack,
|
||||||
SourceLocation NameLoc,
|
SourceLocation NameLoc,
|
||||||
unsigned NumParams,
|
unsigned NumParams,
|
||||||
ParmVarDecl *const *Params)
|
VarDecl *const *Params)
|
||||||
: Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary, true, true,
|
: Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary, true, true,
|
||||||
true, true),
|
true, true),
|
||||||
ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) {
|
ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) {
|
||||||
if (Params)
|
if (Params)
|
||||||
std::uninitialized_copy(Params, Params + NumParams,
|
std::uninitialized_copy(Params, Params + NumParams,
|
||||||
getTrailingObjects<ParmVarDecl *>());
|
getTrailingObjects<VarDecl *>());
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionParmPackExpr *
|
FunctionParmPackExpr *
|
||||||
FunctionParmPackExpr::Create(const ASTContext &Context, QualType T,
|
FunctionParmPackExpr::Create(const ASTContext &Context, QualType T,
|
||||||
ParmVarDecl *ParamPack, SourceLocation NameLoc,
|
VarDecl *ParamPack, SourceLocation NameLoc,
|
||||||
ArrayRef<ParmVarDecl *> Params) {
|
ArrayRef<VarDecl *> Params) {
|
||||||
return new (Context.Allocate(totalSizeToAlloc<ParmVarDecl *>(Params.size())))
|
return new (Context.Allocate(totalSizeToAlloc<VarDecl *>(Params.size())))
|
||||||
FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data());
|
FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionParmPackExpr *
|
FunctionParmPackExpr *
|
||||||
FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
|
FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
|
||||||
unsigned NumParams) {
|
unsigned NumParams) {
|
||||||
return new (Context.Allocate(totalSizeToAlloc<ParmVarDecl *>(NumParams)))
|
return new (Context.Allocate(totalSizeToAlloc<VarDecl *>(NumParams)))
|
||||||
FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr);
|
FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -538,6 +538,7 @@ private:
|
||||||
unsigned knownArity);
|
unsigned knownArity);
|
||||||
void mangleCastExpression(const Expr *E, StringRef CastEncoding);
|
void mangleCastExpression(const Expr *E, StringRef CastEncoding);
|
||||||
void mangleInitListElements(const InitListExpr *InitList);
|
void mangleInitListElements(const InitListExpr *InitList);
|
||||||
|
void mangleDeclRefExpr(const NamedDecl *D);
|
||||||
void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
|
void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
|
||||||
void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom);
|
void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom);
|
||||||
void mangleCXXDtorType(CXXDtorType T);
|
void mangleCXXDtorType(CXXDtorType T);
|
||||||
|
@ -3499,6 +3500,32 @@ void CXXNameMangler::mangleInitListElements(const InitListExpr *InitList) {
|
||||||
mangleExpression(InitList->getInit(i));
|
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) {
|
void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
|
||||||
// <expression> ::= <unary operator-name> <expression>
|
// <expression> ::= <unary operator-name> <expression>
|
||||||
// ::= <binary operator-name> <expression> <expression>
|
// ::= <binary operator-name> <expression> <expression>
|
||||||
|
@ -4089,37 +4116,9 @@ recurse:
|
||||||
mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity);
|
mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Expr::DeclRefExprClass: {
|
case Expr::DeclRefExprClass:
|
||||||
const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
|
mangleDeclRefExpr(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case Expr::SubstNonTypeTemplateParmPackExprClass:
|
case Expr::SubstNonTypeTemplateParmPackExprClass:
|
||||||
// FIXME: not clear how to mangle this!
|
// FIXME: not clear how to mangle this!
|
||||||
|
@ -4133,7 +4132,7 @@ recurse:
|
||||||
// FIXME: not clear how to mangle this!
|
// FIXME: not clear how to mangle this!
|
||||||
const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E);
|
const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E);
|
||||||
Out << "v110_SUBSTPACK";
|
Out << "v110_SUBSTPACK";
|
||||||
mangleFunctionParam(FPPE->getParameterPack());
|
mangleDeclRefExpr(FPPE->getParameterPack());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -539,6 +539,7 @@ void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) {
|
||||||
case VarDecl::ListInit: JOS.attribute("init", "list"); break;
|
case VarDecl::ListInit: JOS.attribute("init", "list"); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
attributeOnlyIfTrue("isParameterPack", VD->isParameterPack());
|
||||||
}
|
}
|
||||||
|
|
||||||
void JSONNodeDumper::VisitFieldDecl(const FieldDecl *FD) {
|
void JSONNodeDumper::VisitFieldDecl(const FieldDecl *FD) {
|
||||||
|
|
|
@ -1366,6 +1366,8 @@ void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (D->isParameterPack())
|
||||||
|
OS << " pack";
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextNodeDumper::VisitBindingDecl(const BindingDecl *D) {
|
void TextNodeDumper::VisitBindingDecl(const BindingDecl *D) {
|
||||||
|
|
|
@ -1743,6 +1743,10 @@ namespace {
|
||||||
Type *VisitAdjustedType(const AdjustedType *T) {
|
Type *VisitAdjustedType(const AdjustedType *T) {
|
||||||
return Visit(T->getOriginalType());
|
return Visit(T->getOriginalType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type *VisitPackExpansionType(const PackExpansionType *T) {
|
||||||
|
return Visit(T->getPattern());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "clang/Sema/ParsedTemplate.h"
|
#include "clang/Sema/ParsedTemplate.h"
|
||||||
#include "clang/Sema/Scope.h"
|
#include "clang/Sema/Scope.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
|
@ -714,10 +714,10 @@ ExprResult Parser::TryParseLambdaExpression() {
|
||||||
if (Next.is(tok::r_square) || // []
|
if (Next.is(tok::r_square) || // []
|
||||||
Next.is(tok::equal) || // [=
|
Next.is(tok::equal) || // [=
|
||||||
(Next.is(tok::amp) && // [&] or [&,
|
(Next.is(tok::amp) && // [&] or [&,
|
||||||
(After.is(tok::r_square) ||
|
After.isOneOf(tok::r_square, tok::comma)) ||
|
||||||
After.is(tok::comma))) ||
|
|
||||||
(Next.is(tok::identifier) && // [identifier]
|
(Next.is(tok::identifier) && // [identifier]
|
||||||
After.is(tok::r_square))) {
|
After.is(tok::r_square)) ||
|
||||||
|
Next.is(tok::ellipsis)) { // [...
|
||||||
return ParseLambdaExpression();
|
return ParseLambdaExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -798,6 +798,15 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
|
||||||
return true;
|
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.
|
// Parse capture-default.
|
||||||
if (Tok.is(tok::amp) &&
|
if (Tok.is(tok::amp) &&
|
||||||
(NextToken().is(tok::comma) || NextToken().is(tok::r_square))) {
|
(NextToken().is(tok::comma) || NextToken().is(tok::r_square))) {
|
||||||
|
@ -857,7 +866,7 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
|
||||||
LambdaCaptureInitKind InitKind = LambdaCaptureInitKind::NoInit;
|
LambdaCaptureInitKind InitKind = LambdaCaptureInitKind::NoInit;
|
||||||
SourceLocation Loc;
|
SourceLocation Loc;
|
||||||
IdentifierInfo *Id = nullptr;
|
IdentifierInfo *Id = nullptr;
|
||||||
SourceLocation EllipsisLoc;
|
SourceLocation EllipsisLocs[4];
|
||||||
ExprResult Init;
|
ExprResult Init;
|
||||||
SourceLocation LocStart = Tok.getLocation();
|
SourceLocation LocStart = Tok.getLocation();
|
||||||
|
|
||||||
|
@ -875,6 +884,8 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
|
||||||
Kind = LCK_This;
|
Kind = LCK_This;
|
||||||
Loc = ConsumeToken();
|
Loc = ConsumeToken();
|
||||||
} else {
|
} else {
|
||||||
|
TryConsumeToken(tok::ellipsis, EllipsisLocs[0]);
|
||||||
|
|
||||||
if (Tok.is(tok::amp)) {
|
if (Tok.is(tok::amp)) {
|
||||||
Kind = LCK_ByRef;
|
Kind = LCK_ByRef;
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
|
@ -887,6 +898,8 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TryConsumeToken(tok::ellipsis, EllipsisLocs[1]);
|
||||||
|
|
||||||
if (Tok.is(tok::identifier)) {
|
if (Tok.is(tok::identifier)) {
|
||||||
Id = Tok.getIdentifierInfo();
|
Id = Tok.getIdentifierInfo();
|
||||||
Loc = ConsumeToken();
|
Loc = ConsumeToken();
|
||||||
|
@ -901,6 +914,8 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TryConsumeToken(tok::ellipsis, EllipsisLocs[2]);
|
||||||
|
|
||||||
if (Tok.is(tok::l_paren)) {
|
if (Tok.is(tok::l_paren)) {
|
||||||
BalancedDelimiterTracker Parens(*this, tok::l_paren);
|
BalancedDelimiterTracker Parens(*this, tok::l_paren);
|
||||||
Parens.consumeOpen();
|
Parens.consumeOpen();
|
||||||
|
@ -982,9 +997,9 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
|
||||||
ConsumeAnnotationToken();
|
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.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is an init capture, process the initialization expression
|
// Ensure that any ellipsis was in the right place.
|
||||||
// right away. For lambda init-captures such as the following:
|
SourceLocation EllipsisLoc;
|
||||||
// const int x = 10;
|
if (std::any_of(std::begin(EllipsisLocs), std::end(EllipsisLocs),
|
||||||
// auto L = [i = x+1](int a) {
|
[](SourceLocation Loc) { return Loc.isValid(); })) {
|
||||||
// return [j = x+2,
|
// The '...' should appear before the identifier in an init-capture, and
|
||||||
// &k = x](char b) { };
|
// after the identifier otherwise.
|
||||||
// };
|
bool InitCapture = InitKind != LambdaCaptureInitKind::NoInit;
|
||||||
// keep in mind that each lambda init-capture has to have:
|
SourceLocation *ExpectedEllipsisLoc =
|
||||||
// - its initialization expression executed in the context
|
!InitCapture ? &EllipsisLocs[2] :
|
||||||
// of the enclosing/parent decl-context.
|
Kind == LCK_ByRef ? &EllipsisLocs[1] :
|
||||||
// - but the variable itself has to be 'injected' into the
|
&EllipsisLocs[0];
|
||||||
// decl-context of its lambda's call-operator (which has
|
EllipsisLoc = *ExpectedEllipsisLoc;
|
||||||
// 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
|
unsigned DiagID = 0;
|
||||||
// context of the enclosing function or lambda, therefore we can not wait
|
if (EllipsisLoc.isInvalid()) {
|
||||||
// till a lambda scope has been pushed on before deciding whether the
|
DiagID = diag::err_lambda_capture_misplaced_ellipsis;
|
||||||
// variable needs to be captured. We also need to process all
|
for (SourceLocation Loc : EllipsisLocs) {
|
||||||
// lvalue-to-rvalue conversions and discarded-value conversions,
|
if (Loc.isValid())
|
||||||
// so that we can avoid capturing certain constant variables.
|
EllipsisLoc = Loc;
|
||||||
// For e.g.,
|
}
|
||||||
// void test() {
|
} else {
|
||||||
// const int x = 10;
|
unsigned NumEllipses = std::accumulate(
|
||||||
// auto L = [&z = x](char a) { <-- don't capture by the current lambda
|
std::begin(EllipsisLocs), std::end(EllipsisLocs), 0,
|
||||||
// return [y = x](int i) { <-- don't capture by enclosing lambda
|
[](int N, SourceLocation Loc) { return N + Loc.isValid(); });
|
||||||
// return y;
|
if (NumEllipses > 1)
|
||||||
// }
|
DiagID = diag::err_lambda_capture_multiple_ellipses;
|
||||||
// };
|
}
|
||||||
// }
|
if (DiagID) {
|
||||||
// If x was not const, the second use would require 'L' to capture, and
|
NonTentativeAction([&] {
|
||||||
// that would be an error.
|
// 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;
|
ParsedType InitCaptureType;
|
||||||
if (Tentative && Init.isUsable())
|
if (Init.isUsable())
|
||||||
*Tentative = LambdaIntroducerTentativeParse::Incomplete;
|
|
||||||
else if (Init.isUsable()) {
|
|
||||||
Init = Actions.CorrectDelayedTyposInExpr(Init.get());
|
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
|
// Get the pointer and store it in an lvalue, so we can use it as an
|
||||||
// out argument.
|
// out argument.
|
||||||
Expr *InitExpr = Init.get();
|
Expr *InitExpr = Init.get();
|
||||||
// This performs any lvalue-to-rvalue conversions if necessary, which
|
// This performs any lvalue-to-rvalue conversions if necessary, which
|
||||||
// can affect what gets captured in the containing decl-context.
|
// can affect what gets captured in the containing decl-context.
|
||||||
InitCaptureType = Actions.actOnLambdaInitCaptureInitialization(
|
InitCaptureType = Actions.actOnLambdaInitCaptureInitialization(
|
||||||
Loc, Kind == LCK_ByRef, Id, InitKind, InitExpr);
|
Loc, Kind == LCK_ByRef, EllipsisLoc, Id, InitKind, InitExpr);
|
||||||
Init = InitExpr;
|
Init = InitExpr;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceLocation LocEnd = PrevTokLocation;
|
SourceLocation LocEnd = PrevTokLocation;
|
||||||
|
|
|
@ -753,11 +753,10 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc,
|
QualType Sema::buildLambdaInitCaptureInitialization(
|
||||||
bool ByRef,
|
SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc,
|
||||||
IdentifierInfo *Id,
|
Optional<unsigned> NumExpansions, IdentifierInfo *Id, bool IsDirectInit,
|
||||||
bool IsDirectInit,
|
Expr *&Init) {
|
||||||
Expr *&Init) {
|
|
||||||
// Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
|
// Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
|
||||||
// deduce against.
|
// deduce against.
|
||||||
QualType DeductType = Context.getAutoDeductType();
|
QualType DeductType = Context.getAutoDeductType();
|
||||||
|
@ -768,6 +767,18 @@ QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc,
|
||||||
assert(!DeductType.isNull() && "can't build reference to auto");
|
assert(!DeductType.isNull() && "can't build reference to auto");
|
||||||
TLB.push<ReferenceTypeLoc>(DeductType).setSigilLoc(Loc);
|
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);
|
TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType);
|
||||||
|
|
||||||
// Deduce the type of the init capture.
|
// Deduce the type of the init capture.
|
||||||
|
@ -808,10 +819,15 @@ QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc,
|
||||||
|
|
||||||
VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
|
VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
|
||||||
QualType InitCaptureType,
|
QualType InitCaptureType,
|
||||||
|
SourceLocation EllipsisLoc,
|
||||||
IdentifierInfo *Id,
|
IdentifierInfo *Id,
|
||||||
unsigned InitStyle, Expr *Init) {
|
unsigned InitStyle, Expr *Init) {
|
||||||
TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType,
|
// FIXME: Retain the TypeSourceInfo from buildLambdaInitCaptureInitialization
|
||||||
Loc);
|
// 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
|
// 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
|
// used as a variable, and only exists as a way to name and refer to the
|
||||||
// init-capture.
|
// init-capture.
|
||||||
|
@ -1036,8 +1052,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||||
? diag::warn_cxx11_compat_init_capture
|
? diag::warn_cxx11_compat_init_capture
|
||||||
: diag::ext_init_capture);
|
: diag::ext_init_capture);
|
||||||
|
|
||||||
if (C->Init.get()->containsUnexpandedParameterPack())
|
|
||||||
ContainsUnexpandedParameterPack = true;
|
|
||||||
// If the initializer expression is usable, but the InitCaptureType
|
// If the initializer expression is usable, but the InitCaptureType
|
||||||
// is not, then an error has occurred - so ignore the capture for now.
|
// is not, then an error has occurred - so ignore the capture for now.
|
||||||
// for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
|
// 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())
|
if (C->InitCaptureType.get().isNull())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (C->Init.get()->containsUnexpandedParameterPack() &&
|
||||||
|
!C->InitCaptureType.get()->getAs<PackExpansionType>())
|
||||||
|
ContainsUnexpandedParameterPack = true;
|
||||||
|
|
||||||
unsigned InitStyle;
|
unsigned InitStyle;
|
||||||
switch (C->InitKind) {
|
switch (C->InitKind) {
|
||||||
case LambdaCaptureInitKind::NoInit:
|
case LambdaCaptureInitKind::NoInit:
|
||||||
|
@ -1061,7 +1079,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
|
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:
|
// C++1y [expr.prim.lambda]p11:
|
||||||
// An init-capture behaves as if it declares and explicitly
|
// An init-capture behaves as if it declares and explicitly
|
||||||
// captures a variable [...] whose declarative region is the
|
// captures a variable [...] whose declarative region is the
|
||||||
|
@ -1153,7 +1172,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
||||||
EllipsisLoc = C->EllipsisLoc;
|
EllipsisLoc = C->EllipsisLoc;
|
||||||
} else {
|
} else {
|
||||||
Diag(C->EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
|
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.
|
// Just ignore the ellipsis.
|
||||||
}
|
}
|
||||||
|
|
|
@ -4280,19 +4280,26 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
struct DependentAuto { bool IsPack; };
|
||||||
|
|
||||||
/// Substitute the 'auto' specifier or deduced template specialization type
|
/// Substitute the 'auto' specifier or deduced template specialization type
|
||||||
/// specifier within a type for a given replacement type.
|
/// specifier within a type for a given replacement type.
|
||||||
class SubstituteDeducedTypeTransform :
|
class SubstituteDeducedTypeTransform :
|
||||||
public TreeTransform<SubstituteDeducedTypeTransform> {
|
public TreeTransform<SubstituteDeducedTypeTransform> {
|
||||||
QualType Replacement;
|
QualType Replacement;
|
||||||
|
bool ReplacementIsPack;
|
||||||
bool UseTypeSugar;
|
bool UseTypeSugar;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
SubstituteDeducedTypeTransform(Sema &SemaRef, DependentAuto DA)
|
||||||
|
: TreeTransform<SubstituteDeducedTypeTransform>(SemaRef), Replacement(),
|
||||||
|
ReplacementIsPack(DA.IsPack), UseTypeSugar(true) {}
|
||||||
|
|
||||||
SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement,
|
SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement,
|
||||||
bool UseTypeSugar = true)
|
bool UseTypeSugar = true)
|
||||||
: TreeTransform<SubstituteDeducedTypeTransform>(SemaRef),
|
: TreeTransform<SubstituteDeducedTypeTransform>(SemaRef),
|
||||||
Replacement(Replacement), UseTypeSugar(UseTypeSugar) {}
|
Replacement(Replacement), ReplacementIsPack(false),
|
||||||
|
UseTypeSugar(UseTypeSugar) {}
|
||||||
|
|
||||||
QualType TransformDesugared(TypeLocBuilder &TLB, DeducedTypeLoc TL) {
|
QualType TransformDesugared(TypeLocBuilder &TLB, DeducedTypeLoc TL) {
|
||||||
assert(isa<TemplateTypeParmType>(Replacement) &&
|
assert(isa<TemplateTypeParmType>(Replacement) &&
|
||||||
|
@ -4317,7 +4324,8 @@ namespace {
|
||||||
return TransformDesugared(TLB, TL);
|
return TransformDesugared(TLB, TL);
|
||||||
|
|
||||||
QualType Result = SemaRef.Context.getAutoType(
|
QualType Result = SemaRef.Context.getAutoType(
|
||||||
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
|
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(),
|
||||||
|
ReplacementIsPack);
|
||||||
auto NewTL = TLB.push<AutoTypeLoc>(Result);
|
auto NewTL = TLB.push<AutoTypeLoc>(Result);
|
||||||
NewTL.setNameLoc(TL.getNameLoc());
|
NewTL.setNameLoc(TL.getNameLoc());
|
||||||
return Result;
|
return Result;
|
||||||
|
@ -4408,9 +4416,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
||||||
Init = NonPlaceholder.get();
|
Init = NonPlaceholder.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DependentAuto DependentResult = {
|
||||||
|
/*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()};
|
||||||
|
|
||||||
if (!DependentDeductionDepth &&
|
if (!DependentDeductionDepth &&
|
||||||
(Type.getType()->isDependentType() || Init->isTypeDependent())) {
|
(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");
|
assert(!Result.isNull() && "substituting DependentTy can't fail");
|
||||||
return DAR_Succeeded;
|
return DAR_Succeeded;
|
||||||
}
|
}
|
||||||
|
@ -4478,7 +4489,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
||||||
auto DeductionFailed = [&](TemplateDeductionResult TDK,
|
auto DeductionFailed = [&](TemplateDeductionResult TDK,
|
||||||
ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
|
ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
|
||||||
if (Init->isTypeDependent()) {
|
if (Init->isTypeDependent()) {
|
||||||
Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
|
Result =
|
||||||
|
SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
|
||||||
assert(!Result.isNull() && "substituting DependentTy can't fail");
|
assert(!Result.isNull() && "substituting DependentTy can't fail");
|
||||||
return DAR_Succeeded;
|
return DAR_Succeeded;
|
||||||
}
|
}
|
||||||
|
@ -4559,7 +4571,10 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
||||||
QualType Sema::SubstAutoType(QualType TypeWithAuto,
|
QualType Sema::SubstAutoType(QualType TypeWithAuto,
|
||||||
QualType TypeToReplaceAuto) {
|
QualType TypeToReplaceAuto) {
|
||||||
if (TypeToReplaceAuto->isDependentType())
|
if (TypeToReplaceAuto->isDependentType())
|
||||||
TypeToReplaceAuto = QualType();
|
return SubstituteDeducedTypeTransform(
|
||||||
|
*this, DependentAuto{
|
||||||
|
TypeToReplaceAuto->containsUnexpandedParameterPack()})
|
||||||
|
.TransformType(TypeWithAuto);
|
||||||
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
|
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
|
||||||
.TransformType(TypeWithAuto);
|
.TransformType(TypeWithAuto);
|
||||||
}
|
}
|
||||||
|
@ -4567,7 +4582,11 @@ QualType Sema::SubstAutoType(QualType TypeWithAuto,
|
||||||
TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
|
TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
|
||||||
QualType TypeToReplaceAuto) {
|
QualType TypeToReplaceAuto) {
|
||||||
if (TypeToReplaceAuto->isDependentType())
|
if (TypeToReplaceAuto->isDependentType())
|
||||||
TypeToReplaceAuto = QualType();
|
return SubstituteDeducedTypeTransform(
|
||||||
|
*this,
|
||||||
|
DependentAuto{
|
||||||
|
TypeToReplaceAuto->containsUnexpandedParameterPack()})
|
||||||
|
.TransformType(TypeWithAuto);
|
||||||
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
|
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
|
||||||
.TransformType(TypeWithAuto);
|
.TransformType(TypeWithAuto);
|
||||||
}
|
}
|
||||||
|
|
|
@ -819,7 +819,19 @@ namespace {
|
||||||
SemaRef.InstantiateAttrs(TemplateArgs, Old, New);
|
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
|
// If we've instantiated the call operator of a lambda or the call
|
||||||
// operator template of a generic lambda, update the "instantiation of"
|
// operator template of a generic lambda, update the "instantiation of"
|
||||||
// information.
|
// information.
|
||||||
|
@ -888,12 +900,11 @@ namespace {
|
||||||
ExprResult TransformSubstNonTypeTemplateParmPackExpr(
|
ExprResult TransformSubstNonTypeTemplateParmPackExpr(
|
||||||
SubstNonTypeTemplateParmPackExpr *E);
|
SubstNonTypeTemplateParmPackExpr *E);
|
||||||
|
|
||||||
/// Rebuild a DeclRefExpr for a ParmVarDecl reference.
|
/// Rebuild a DeclRefExpr for a VarDecl reference.
|
||||||
ExprResult RebuildParmVarDeclRefExpr(ParmVarDecl *PD, SourceLocation Loc);
|
ExprResult RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc);
|
||||||
|
|
||||||
/// Transform a reference to a function parameter pack.
|
/// Transform a reference to a function or init-capture parameter pack.
|
||||||
ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E,
|
ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, VarDecl *PD);
|
||||||
ParmVarDecl *PD);
|
|
||||||
|
|
||||||
/// Transform a FunctionParmPackExpr which was built when we couldn't
|
/// Transform a FunctionParmPackExpr which was built when we couldn't
|
||||||
/// expand a function parameter pack reference which refers to an expanded
|
/// expand a function parameter pack reference which refers to an expanded
|
||||||
|
@ -1324,9 +1335,8 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
|
||||||
Arg);
|
Arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult
|
ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD,
|
||||||
TemplateInstantiator::RebuildParmVarDeclRefExpr(ParmVarDecl *PD,
|
SourceLocation Loc) {
|
||||||
SourceLocation Loc) {
|
|
||||||
DeclarationNameInfo NameInfo(PD->getDeclName(), Loc);
|
DeclarationNameInfo NameInfo(PD->getDeclName(), Loc);
|
||||||
return getSema().BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, PD);
|
return getSema().BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, PD);
|
||||||
}
|
}
|
||||||
|
@ -1335,11 +1345,11 @@ ExprResult
|
||||||
TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
|
TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
|
||||||
if (getSema().ArgumentPackSubstitutionIndex != -1) {
|
if (getSema().ArgumentPackSubstitutionIndex != -1) {
|
||||||
// We can expand this parameter pack now.
|
// We can expand this parameter pack now.
|
||||||
ParmVarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex);
|
VarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex);
|
||||||
ValueDecl *VD = cast_or_null<ValueDecl>(TransformDecl(E->getExprLoc(), D));
|
VarDecl *VD = cast_or_null<VarDecl>(TransformDecl(E->getExprLoc(), D));
|
||||||
if (!VD)
|
if (!VD)
|
||||||
return ExprError();
|
return ExprError();
|
||||||
return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(VD), E->getExprLoc());
|
return RebuildVarDeclRefExpr(VD, E->getExprLoc());
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType T = TransformType(E->getType());
|
QualType T = TransformType(E->getType());
|
||||||
|
@ -1348,25 +1358,24 @@ TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
|
||||||
|
|
||||||
// Transform each of the parameter expansions into the corresponding
|
// Transform each of the parameter expansions into the corresponding
|
||||||
// parameters in the instantiation of the function decl.
|
// parameters in the instantiation of the function decl.
|
||||||
SmallVector<ParmVarDecl *, 8> Parms;
|
SmallVector<VarDecl *, 8> Vars;
|
||||||
Parms.reserve(E->getNumExpansions());
|
Vars.reserve(E->getNumExpansions());
|
||||||
for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
|
for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
|
||||||
I != End; ++I) {
|
I != End; ++I) {
|
||||||
ParmVarDecl *D =
|
VarDecl *D = cast_or_null<VarDecl>(TransformDecl(E->getExprLoc(), *I));
|
||||||
cast_or_null<ParmVarDecl>(TransformDecl(E->getExprLoc(), *I));
|
|
||||||
if (!D)
|
if (!D)
|
||||||
return ExprError();
|
return ExprError();
|
||||||
Parms.push_back(D);
|
Vars.push_back(D);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FunctionParmPackExpr::Create(getSema().Context, T,
|
return FunctionParmPackExpr::Create(getSema().Context, T,
|
||||||
E->getParameterPack(),
|
E->getParameterPack(),
|
||||||
E->getParameterPackLocation(), Parms);
|
E->getParameterPackLocation(), Vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult
|
ExprResult
|
||||||
TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
|
TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
|
||||||
ParmVarDecl *PD) {
|
VarDecl *PD) {
|
||||||
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
|
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
|
||||||
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found
|
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found
|
||||||
= getSema().CurrentInstantiationScope->findInstantiationOf(PD);
|
= getSema().CurrentInstantiationScope->findInstantiationOf(PD);
|
||||||
|
@ -1390,8 +1399,7 @@ TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have either an unexpanded pack or a specific expansion.
|
// We have either an unexpanded pack or a specific expansion.
|
||||||
return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(TransformedDecl),
|
return RebuildVarDeclRefExpr(cast<VarDecl>(TransformedDecl), E->getExprLoc());
|
||||||
E->getExprLoc());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult
|
ExprResult
|
||||||
|
@ -1409,7 +1417,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle references to function parameter packs.
|
// Handle references to function parameter packs.
|
||||||
if (ParmVarDecl *PD = dyn_cast<ParmVarDecl>(D))
|
if (VarDecl *PD = dyn_cast<VarDecl>(D))
|
||||||
if (PD->isParameterPack())
|
if (PD->isParameterPack())
|
||||||
return TransformFunctionParmPackRefExpr(E, PD);
|
return TransformFunctionParmPackRefExpr(E, PD);
|
||||||
|
|
||||||
|
@ -2984,14 +2992,14 @@ void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
|
||||||
#endif
|
#endif
|
||||||
Stored = Inst;
|
Stored = Inst;
|
||||||
} else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) {
|
} else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) {
|
||||||
Pack->push_back(cast<ParmVarDecl>(Inst));
|
Pack->push_back(cast<VarDecl>(Inst));
|
||||||
} else {
|
} else {
|
||||||
assert(Stored.get<Decl *>() == Inst && "Already instantiated this local");
|
assert(Stored.get<Decl *>() == Inst && "Already instantiated this local");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D,
|
void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D,
|
||||||
ParmVarDecl *Inst) {
|
VarDecl *Inst) {
|
||||||
D = getCanonicalParmVarDecl(D);
|
D = getCanonicalParmVarDecl(D);
|
||||||
DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>();
|
DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>();
|
||||||
Pack->push_back(Inst);
|
Pack->push_back(Inst);
|
||||||
|
|
|
@ -39,11 +39,11 @@ namespace {
|
||||||
unsigned DepthLimit = (unsigned)-1;
|
unsigned DepthLimit = (unsigned)-1;
|
||||||
|
|
||||||
void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) {
|
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
|
// 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
|
// call operator, so we don't need to look for all the other ways we
|
||||||
// could have reached a dependent parameter pack.
|
// 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;
|
auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr;
|
||||||
if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit)
|
if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit)
|
||||||
return;
|
return;
|
||||||
|
@ -313,11 +313,11 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
|
||||||
|
|
||||||
if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) {
|
if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) {
|
||||||
if (N == FunctionScopes.size()) {
|
if (N == FunctionScopes.size()) {
|
||||||
for (auto &Param : Unexpanded) {
|
for (auto &Pack : Unexpanded) {
|
||||||
auto *PD = dyn_cast_or_null<ParmVarDecl>(
|
auto *VD = dyn_cast_or_null<VarDecl>(
|
||||||
Param.first.dyn_cast<NamedDecl *>());
|
Pack.first.dyn_cast<NamedDecl *>());
|
||||||
if (PD && PD->getDeclContext() == LSI->CallOperator)
|
if (VD && VD->getDeclContext() == LSI->CallOperator)
|
||||||
LambdaParamPackReferences.push_back(Param);
|
LambdaParamPackReferences.push_back(Pack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,11 +586,15 @@ Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
|
||||||
QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
|
QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
|
||||||
SourceLocation EllipsisLoc,
|
SourceLocation EllipsisLoc,
|
||||||
Optional<unsigned> NumExpansions) {
|
Optional<unsigned> NumExpansions) {
|
||||||
// C++0x [temp.variadic]p5:
|
// C++11 [temp.variadic]p5:
|
||||||
// The pattern of a pack expansion shall name one or more
|
// The pattern of a pack expansion shall name one or more
|
||||||
// parameter packs that are not expanded by a nested pack
|
// parameter packs that are not expanded by a nested pack
|
||||||
// expansion.
|
// 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)
|
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
|
||||||
<< PatternRange;
|
<< PatternRange;
|
||||||
return QualType();
|
return QualType();
|
||||||
|
@ -641,7 +645,7 @@ bool Sema::CheckParameterPacksForExpansion(
|
||||||
// Compute the depth and index for this parameter pack.
|
// Compute the depth and index for this parameter pack.
|
||||||
unsigned Depth = 0, Index = 0;
|
unsigned Depth = 0, Index = 0;
|
||||||
IdentifierInfo *Name;
|
IdentifierInfo *Name;
|
||||||
bool IsFunctionParameterPack = false;
|
bool IsVarDeclPack = false;
|
||||||
|
|
||||||
if (const TemplateTypeParmType *TTP
|
if (const TemplateTypeParmType *TTP
|
||||||
= i->first.dyn_cast<const TemplateTypeParmType *>()) {
|
= i->first.dyn_cast<const TemplateTypeParmType *>()) {
|
||||||
|
@ -650,8 +654,8 @@ bool Sema::CheckParameterPacksForExpansion(
|
||||||
Name = TTP->getIdentifier();
|
Name = TTP->getIdentifier();
|
||||||
} else {
|
} else {
|
||||||
NamedDecl *ND = i->first.get<NamedDecl *>();
|
NamedDecl *ND = i->first.get<NamedDecl *>();
|
||||||
if (isa<ParmVarDecl>(ND))
|
if (isa<VarDecl>(ND))
|
||||||
IsFunctionParameterPack = true;
|
IsVarDeclPack = true;
|
||||||
else
|
else
|
||||||
std::tie(Depth, Index) = getDepthAndIndex(ND);
|
std::tie(Depth, Index) = getDepthAndIndex(ND);
|
||||||
|
|
||||||
|
@ -660,7 +664,7 @@ bool Sema::CheckParameterPacksForExpansion(
|
||||||
|
|
||||||
// Determine the size of this argument pack.
|
// Determine the size of this argument pack.
|
||||||
unsigned NewPackSize;
|
unsigned NewPackSize;
|
||||||
if (IsFunctionParameterPack) {
|
if (IsVarDeclPack) {
|
||||||
// Figure out whether we're instantiating to an argument pack or not.
|
// Figure out whether we're instantiating to an argument pack or not.
|
||||||
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
|
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
|
||||||
|
|
||||||
|
@ -694,7 +698,7 @@ bool Sema::CheckParameterPacksForExpansion(
|
||||||
// Template argument deduction can extend the sequence of template
|
// Template argument deduction can extend the sequence of template
|
||||||
// arguments corresponding to a template parameter pack, even when the
|
// arguments corresponding to a template parameter pack, even when the
|
||||||
// sequence contains explicitly specified template arguments.
|
// sequence contains explicitly specified template arguments.
|
||||||
if (!IsFunctionParameterPack && CurrentInstantiationScope) {
|
if (!IsVarDeclPack && CurrentInstantiationScope) {
|
||||||
if (NamedDecl *PartialPack
|
if (NamedDecl *PartialPack
|
||||||
= CurrentInstantiationScope->getPartiallySubstitutedPack()){
|
= CurrentInstantiationScope->getPartiallySubstitutedPack()){
|
||||||
unsigned PartialDepth, PartialIndex;
|
unsigned PartialDepth, PartialIndex;
|
||||||
|
@ -778,8 +782,8 @@ Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
|
||||||
Index = TTP->getIndex();
|
Index = TTP->getIndex();
|
||||||
} else {
|
} else {
|
||||||
NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
|
NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
|
||||||
if (isa<ParmVarDecl>(ND)) {
|
if (isa<VarDecl>(ND)) {
|
||||||
// Function parameter pack.
|
// Function parameter pack or init-capture pack.
|
||||||
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
|
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
|
||||||
|
|
||||||
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
|
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
|
||||||
|
@ -1084,7 +1088,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
|
||||||
dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr()))
|
dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr()))
|
||||||
Pack = Subst->getArgumentPack();
|
Pack = Subst->getArgumentPack();
|
||||||
else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) {
|
else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) {
|
||||||
for (ParmVarDecl *PD : *Subst)
|
for (VarDecl *PD : *Subst)
|
||||||
if (PD->isParameterPack())
|
if (PD->isParameterPack())
|
||||||
return None;
|
return None;
|
||||||
return Subst->getNumExpansions();
|
return Subst->getNumExpansions();
|
||||||
|
|
|
@ -450,8 +450,10 @@ public:
|
||||||
/// TransformDefinition. However, in some cases (e.g., lambda expressions),
|
/// TransformDefinition. However, in some cases (e.g., lambda expressions),
|
||||||
/// the transformer itself has to transform the declarations. This routine
|
/// the transformer itself has to transform the declarations. This routine
|
||||||
/// can be overridden by a subclass that keeps track of such mappings.
|
/// can be overridden by a subclass that keeps track of such mappings.
|
||||||
void transformedLocalDecl(Decl *Old, Decl *New) {
|
void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> New) {
|
||||||
TransformedLocalDecls[Old] = New;
|
assert(New.size() == 1 &&
|
||||||
|
"must override transformedLocalDecl if performing pack expansion");
|
||||||
|
TransformedLocalDecls[Old] = New.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transform the definition of the given declaration.
|
/// Transform the definition of the given declaration.
|
||||||
|
@ -7122,7 +7124,7 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
|
||||||
auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation());
|
auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation());
|
||||||
if (!Promise)
|
if (!Promise)
|
||||||
return StmtError();
|
return StmtError();
|
||||||
getDerived().transformedLocalDecl(S->getPromiseDecl(), Promise);
|
getDerived().transformedLocalDecl(S->getPromiseDecl(), {Promise});
|
||||||
ScopeInfo->CoroutinePromise = Promise;
|
ScopeInfo->CoroutinePromise = Promise;
|
||||||
|
|
||||||
// Transform the implicit coroutine statements we built during the initial
|
// 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
|
// Transform any init-capture expressions before entering the scope of the
|
||||||
// lambda body, because they are not semantically within that scope.
|
// lambda body, because they are not semantically within that scope.
|
||||||
typedef std::pair<ExprResult, QualType> InitCaptureInfoTy;
|
typedef std::pair<ExprResult, QualType> InitCaptureInfoTy;
|
||||||
SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes;
|
struct TransformedInitCapture {
|
||||||
InitCaptureExprsAndTypes.resize(E->explicit_capture_end() -
|
// The location of the ... if the result is retaining a pack expansion.
|
||||||
E->explicit_capture_begin());
|
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(),
|
for (LambdaExpr::capture_iterator C = E->capture_begin(),
|
||||||
CEnd = E->capture_end();
|
CEnd = E->capture_end();
|
||||||
C != CEnd; ++C) {
|
C != CEnd; ++C) {
|
||||||
if (!E->isInitCapture(C))
|
if (!E->isInitCapture(C))
|
||||||
continue;
|
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();
|
VarDecl *OldVD = C->getCapturedVar();
|
||||||
QualType NewInitCaptureType =
|
|
||||||
getSema().buildLambdaInitCaptureInitialization(
|
auto SubstInitCapture = [&](SourceLocation EllipsisLoc,
|
||||||
C->getLocation(), OldVD->getType()->isReferenceType(),
|
Optional<unsigned> NumExpansions) {
|
||||||
OldVD->getIdentifier(),
|
EnterExpressionEvaluationContext EEEC(
|
||||||
C->getCapturedVar()->getInitStyle() != VarDecl::CInit, NewExprInit);
|
getSema(), Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
|
||||||
NewExprInitResult = NewExprInit;
|
ExprResult NewExprInitResult = getDerived().TransformInitializer(
|
||||||
InitCaptureExprsAndTypes[C - E->capture_begin()] =
|
OldVD->getInit(), OldVD->getInitStyle() == VarDecl::CallInit);
|
||||||
std::make_pair(NewExprInitResult, NewInitCaptureType);
|
|
||||||
|
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
|
// Transform the template parameters, and add them to the current
|
||||||
|
@ -11245,7 +11294,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||||
NewCallOpTSI,
|
NewCallOpTSI,
|
||||||
/*KnownDependent=*/false,
|
/*KnownDependent=*/false,
|
||||||
E->getCaptureDefault());
|
E->getCaptureDefault());
|
||||||
getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
|
getDerived().transformedLocalDecl(E->getLambdaClass(), {Class});
|
||||||
|
|
||||||
// Build the call operator.
|
// Build the call operator.
|
||||||
CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
|
CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
|
||||||
|
@ -11270,7 +11319,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||||
}
|
}
|
||||||
|
|
||||||
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
|
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
|
||||||
getDerived().transformedLocalDecl(E->getCallOperator(), NewCallOperator);
|
getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
|
||||||
|
|
||||||
// Introduce the context of the call operator.
|
// Introduce the context of the call operator.
|
||||||
Sema::ContextRAII SavedContext(getSema(), NewCallOperator,
|
Sema::ContextRAII SavedContext(getSema(), NewCallOperator,
|
||||||
|
@ -11313,24 +11362,33 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||||
|
|
||||||
// Rebuild init-captures, including the implied field declaration.
|
// Rebuild init-captures, including the implied field declaration.
|
||||||
if (E->isInitCapture(C)) {
|
if (E->isInitCapture(C)) {
|
||||||
InitCaptureInfoTy InitExprTypePair =
|
TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()];
|
||||||
InitCaptureExprsAndTypes[C - E->capture_begin()];
|
|
||||||
ExprResult Init = InitExprTypePair.first;
|
|
||||||
QualType InitQualType = InitExprTypePair.second;
|
|
||||||
if (Init.isInvalid() || InitQualType.isNull()) {
|
|
||||||
Invalid = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
VarDecl *OldVD = C->getCapturedVar();
|
VarDecl *OldVD = C->getCapturedVar();
|
||||||
VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
|
llvm::SmallVector<Decl*, 4> NewVDs;
|
||||||
OldVD->getLocation(), InitExprTypePair.second, OldVD->getIdentifier(),
|
|
||||||
OldVD->getInitStyle(), Init.get());
|
for (InitCaptureInfoTy &Info : NewC.Expansions) {
|
||||||
if (!NewVD)
|
ExprResult Init = Info.first;
|
||||||
Invalid = true;
|
QualType InitQualType = Info.second;
|
||||||
else {
|
if (Init.isInvalid() || InitQualType.isNull()) {
|
||||||
getDerived().transformedLocalDecl(OldVD, NewVD);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12471,8 +12529,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
|
||||||
VarDecl *oldCapture = I.getVariable();
|
VarDecl *oldCapture = I.getVariable();
|
||||||
|
|
||||||
// Ignore parameter packs.
|
// Ignore parameter packs.
|
||||||
if (isa<ParmVarDecl>(oldCapture) &&
|
if (oldCapture->isParameterPack())
|
||||||
cast<ParmVarDecl>(oldCapture)->isParameterPack())
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
VarDecl *newCapture =
|
VarDecl *newCapture =
|
||||||
|
|
|
@ -6141,8 +6141,13 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
|
||||||
case TYPE_AUTO: {
|
case TYPE_AUTO: {
|
||||||
QualType Deduced = readType(*Loc.F, Record, Idx);
|
QualType Deduced = readType(*Loc.F, Record, Idx);
|
||||||
AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++];
|
AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++];
|
||||||
bool IsDependent = Deduced.isNull() ? Record[Idx++] : false;
|
bool IsDependent = false, IsPack = false;
|
||||||
return Context.getAutoType(Deduced, Keyword, IsDependent);
|
if (Deduced.isNull()) {
|
||||||
|
IsDependent = Record[Idx] > 0;
|
||||||
|
IsPack = Record[Idx] > 1;
|
||||||
|
++Idx;
|
||||||
|
}
|
||||||
|
return Context.getAutoType(Deduced, Keyword, IsDependent, IsPack);
|
||||||
}
|
}
|
||||||
|
|
||||||
case TYPE_DEDUCED_TEMPLATE_SPECIALIZATION: {
|
case TYPE_DEDUCED_TEMPLATE_SPECIALIZATION: {
|
||||||
|
|
|
@ -1803,9 +1803,9 @@ void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
|
||||||
E->NumParameters = Record.readInt();
|
E->NumParameters = Record.readInt();
|
||||||
E->ParamPack = ReadDeclAs<ParmVarDecl>();
|
E->ParamPack = ReadDeclAs<ParmVarDecl>();
|
||||||
E->NameLoc = ReadSourceLocation();
|
E->NameLoc = ReadSourceLocation();
|
||||||
auto **Parms = E->getTrailingObjects<ParmVarDecl *>();
|
auto **Parms = E->getTrailingObjects<VarDecl *>();
|
||||||
for (unsigned i = 0, n = E->NumParameters; i != n; ++i)
|
for (unsigned i = 0, n = E->NumParameters; i != n; ++i)
|
||||||
Parms[i] = ReadDeclAs<ParmVarDecl>();
|
Parms[i] = ReadDeclAs<VarDecl>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
|
void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
|
||||||
|
|
|
@ -369,7 +369,8 @@ void ASTTypeWriter::VisitAutoType(const AutoType *T) {
|
||||||
Record.AddTypeRef(T->getDeducedType());
|
Record.AddTypeRef(T->getDeducedType());
|
||||||
Record.push_back((unsigned)T->getKeyword());
|
Record.push_back((unsigned)T->getKeyword());
|
||||||
if (T->getDeducedType().isNull())
|
if (T->getDeducedType().isNull())
|
||||||
Record.push_back(T->isDependentType());
|
Record.push_back(T->containsUnexpandedParameterPack() ? 2 :
|
||||||
|
T->isDependentType() ? 1 : 0);
|
||||||
Code = TYPE_AUTO;
|
Code = TYPE_AUTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
@ -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++11 %s -verify -Wno-c++1y-extensions -Wno-c++2a-extensions
|
||||||
// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
|
// 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();
|
void print();
|
||||||
|
|
||||||
|
@ -60,8 +61,25 @@ template void variadic_lambda(int*, float*, double*);
|
||||||
|
|
||||||
template<typename ...Args>
|
template<typename ...Args>
|
||||||
void init_capture_pack_err(Args ...args) {
|
void init_capture_pack_err(Args ...args) {
|
||||||
[as(args)...] {} (); // expected-error {{expected ','}}
|
[...as(args)]{} ();
|
||||||
[as...(args)]{} (); // expected-error {{expected ','}}
|
[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>
|
template<typename ...Args>
|
||||||
|
|
|
@ -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}}
|
||||||
|
);
|
||||||
|
}
|
|
@ -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}}
|
||||||
|
}
|
|
@ -1,7 +1,13 @@
|
||||||
// RUN: %clang_cc1 -std=c++11 -verify %s
|
// RUN: %clang_cc1 -std=c++11 -verify %s
|
||||||
// expected-no-diagnostics
|
|
||||||
|
|
||||||
template<int &...Ns> int f() {
|
template<int &...Ns> int f() {
|
||||||
return sizeof...(Ns);
|
return sizeof...(Ns);
|
||||||
}
|
}
|
||||||
template int f<>();
|
template int f<>();
|
||||||
|
|
||||||
|
template<typename ...T> int g() {
|
||||||
|
return [...x = T()] { // expected-warning 2{{extension}}
|
||||||
|
return sizeof...(x);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
template int g<>();
|
||||||
|
|
|
@ -949,7 +949,7 @@ as the draft C++2a standard evolves.
|
||||||
<tr>
|
<tr>
|
||||||
<td>Pack expansion in lambda <i>init-capture</i></td>
|
<td>Pack expansion in lambda <i>init-capture</i></td>
|
||||||
<td><a href="http://wg21.link/p0780r2">P0780R2</a></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>
|
</tr>
|
||||||
<!-- Rapperswil papers -->
|
<!-- Rapperswil papers -->
|
||||||
<tr>
|
<tr>
|
||||||
|
|
Loading…
Reference in New Issue