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