mirror of https://github.com/microsoft/clang.git
PR14858: Initial support for proper sizeof... handling within alias templates.
This doesn't quite get alias template equivalence right yet, but handles the egregious cases where we would silently give the wrong answers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@248431 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
db9d74b8a3
commit
1878f91a0a
|
@ -3558,43 +3558,51 @@ class SizeOfPackExpr : public Expr {
|
||||||
|
|
||||||
/// \brief The length of the parameter pack, if known.
|
/// \brief The length of the parameter pack, if known.
|
||||||
///
|
///
|
||||||
/// When this expression is value-dependent, the length of the parameter pack
|
/// When this expression is not value-dependent, this is the length of
|
||||||
/// is unknown. When this expression is not value-dependent, the length is
|
/// the pack. When the expression was parsed rather than instantiated
|
||||||
/// known.
|
/// (and thus is value-dependent), this is zero.
|
||||||
|
///
|
||||||
|
/// After partial substitution into a sizeof...(X) expression (for instance,
|
||||||
|
/// within an alias template or during function template argument deduction),
|
||||||
|
/// we store a trailing array of partially-substituted TemplateArguments,
|
||||||
|
/// and this is the length of that array.
|
||||||
unsigned Length;
|
unsigned Length;
|
||||||
|
|
||||||
/// \brief The parameter pack itself.
|
/// \brief The parameter pack.
|
||||||
NamedDecl *Pack;
|
NamedDecl *Pack;
|
||||||
|
|
||||||
friend class ASTStmtReader;
|
friend class ASTStmtReader;
|
||||||
friend class ASTStmtWriter;
|
friend class ASTStmtWriter;
|
||||||
|
|
||||||
public:
|
/// \brief Create an expression that computes the length of
|
||||||
/// \brief Create a value-dependent expression that computes the length of
|
|
||||||
/// the given parameter pack.
|
/// the given parameter pack.
|
||||||
SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
|
|
||||||
SourceLocation PackLoc, SourceLocation RParenLoc)
|
|
||||||
: Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary,
|
|
||||||
/*TypeDependent=*/false, /*ValueDependent=*/true,
|
|
||||||
/*InstantiationDependent=*/true,
|
|
||||||
/*ContainsUnexpandedParameterPack=*/false),
|
|
||||||
OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc),
|
|
||||||
Length(0), Pack(Pack) { }
|
|
||||||
|
|
||||||
/// \brief Create an expression that computes the length of
|
|
||||||
/// the given parameter pack, which is already known.
|
|
||||||
SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
|
SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
|
||||||
SourceLocation PackLoc, SourceLocation RParenLoc,
|
SourceLocation PackLoc, SourceLocation RParenLoc,
|
||||||
unsigned Length)
|
Optional<unsigned> Length, ArrayRef<TemplateArgument> PartialArgs)
|
||||||
: Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary,
|
: Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary,
|
||||||
/*TypeDependent=*/false, /*ValueDependent=*/false,
|
/*TypeDependent=*/false, /*ValueDependent=*/!Length,
|
||||||
/*InstantiationDependent=*/false,
|
/*InstantiationDependent=*/!Length,
|
||||||
/*ContainsUnexpandedParameterPack=*/false),
|
/*ContainsUnexpandedParameterPack=*/false),
|
||||||
OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc),
|
OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc),
|
||||||
Length(Length), Pack(Pack) { }
|
Length(Length ? *Length : PartialArgs.size()), Pack(Pack) {
|
||||||
|
assert((!Length || PartialArgs.empty()) &&
|
||||||
|
"have partial args for non-dependent sizeof... expression");
|
||||||
|
TemplateArgument *Args = reinterpret_cast<TemplateArgument *>(this + 1);
|
||||||
|
std::uninitialized_copy(PartialArgs.begin(), PartialArgs.end(), Args);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Create an empty expression.
|
/// \brief Create an empty expression.
|
||||||
SizeOfPackExpr(EmptyShell Empty) : Expr(SizeOfPackExprClass, Empty) { }
|
SizeOfPackExpr(EmptyShell Empty, unsigned NumPartialArgs)
|
||||||
|
: Expr(SizeOfPackExprClass, Empty), Length(NumPartialArgs), Pack() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static SizeOfPackExpr *Create(ASTContext &Context, SourceLocation OperatorLoc,
|
||||||
|
NamedDecl *Pack, SourceLocation PackLoc,
|
||||||
|
SourceLocation RParenLoc,
|
||||||
|
Optional<unsigned> Length = None,
|
||||||
|
ArrayRef<TemplateArgument> PartialArgs = None);
|
||||||
|
static SizeOfPackExpr *CreateDeserialized(ASTContext &Context,
|
||||||
|
unsigned NumPartialArgs);
|
||||||
|
|
||||||
/// \brief Determine the location of the 'sizeof' keyword.
|
/// \brief Determine the location of the 'sizeof' keyword.
|
||||||
SourceLocation getOperatorLoc() const { return OperatorLoc; }
|
SourceLocation getOperatorLoc() const { return OperatorLoc; }
|
||||||
|
@ -3618,6 +3626,23 @@ public:
|
||||||
return Length;
|
return Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Determine whether this represents a partially-substituted sizeof...
|
||||||
|
/// expression, such as is produced for:
|
||||||
|
///
|
||||||
|
/// template<typename ...Ts> using X = int[sizeof...(Ts)];
|
||||||
|
/// template<typename ...Us> void f(X<Us..., 1, 2, 3, Us...>);
|
||||||
|
bool isPartiallySubstituted() const {
|
||||||
|
return isValueDependent() && Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Get
|
||||||
|
ArrayRef<TemplateArgument> getPartialArguments() const {
|
||||||
|
assert(isPartiallySubstituted());
|
||||||
|
const TemplateArgument *Args =
|
||||||
|
reinterpret_cast<const TemplateArgument *>(this + 1);
|
||||||
|
return llvm::makeArrayRef(Args, Args + Length);
|
||||||
|
}
|
||||||
|
|
||||||
SourceLocation getLocStart() const LLVM_READONLY { return OperatorLoc; }
|
SourceLocation getLocStart() const LLVM_READONLY { return OperatorLoc; }
|
||||||
SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
|
SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
|
||||||
|
|
||||||
|
|
|
@ -541,6 +541,10 @@ public:
|
||||||
return Arguments.data();
|
return Arguments.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
|
||||||
|
return Arguments;
|
||||||
|
}
|
||||||
|
|
||||||
const TemplateArgumentLoc &operator[](unsigned I) const {
|
const TemplateArgumentLoc &operator[](unsigned I) const {
|
||||||
return Arguments[I];
|
return Arguments[I];
|
||||||
}
|
}
|
||||||
|
|
|
@ -2017,6 +2017,9 @@ void ASTDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {
|
||||||
VisitExpr(Node);
|
VisitExpr(Node);
|
||||||
dumpPointer(Node->getPack());
|
dumpPointer(Node->getPack());
|
||||||
dumpName(Node->getPack());
|
dumpName(Node->getPack());
|
||||||
|
if (Node->isPartiallySubstituted())
|
||||||
|
for (const auto &A : Node->getPartialArguments())
|
||||||
|
dumpTemplateArgument(A);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1432,6 +1432,25 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
|
||||||
return Record;
|
return Record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SizeOfPackExpr *
|
||||||
|
SizeOfPackExpr::Create(ASTContext &Context, SourceLocation OperatorLoc,
|
||||||
|
NamedDecl *Pack, SourceLocation PackLoc,
|
||||||
|
SourceLocation RParenLoc,
|
||||||
|
Optional<unsigned> Length,
|
||||||
|
ArrayRef<TemplateArgument> PartialArgs) {
|
||||||
|
void *Storage = Context.Allocate(
|
||||||
|
sizeof(SizeOfPackExpr) + sizeof(TemplateArgument) * PartialArgs.size());
|
||||||
|
return new (Storage) SizeOfPackExpr(Context.getSizeType(), OperatorLoc, Pack,
|
||||||
|
PackLoc, RParenLoc, Length, PartialArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeOfPackExpr *SizeOfPackExpr::CreateDeserialized(ASTContext &Context,
|
||||||
|
unsigned NumPartialArgs) {
|
||||||
|
void *Storage = Context.Allocate(
|
||||||
|
sizeof(SizeOfPackExpr) + sizeof(TemplateArgument) * NumPartialArgs);
|
||||||
|
return new (Storage) SizeOfPackExpr(EmptyShell(), NumPartialArgs);
|
||||||
|
}
|
||||||
|
|
||||||
SubstNonTypeTemplateParmPackExpr::
|
SubstNonTypeTemplateParmPackExpr::
|
||||||
SubstNonTypeTemplateParmPackExpr(QualType T,
|
SubstNonTypeTemplateParmPackExpr(QualType T,
|
||||||
NonTypeTemplateParmDecl *Param,
|
NonTypeTemplateParmDecl *Param,
|
||||||
|
|
|
@ -3458,8 +3458,17 @@ recurse:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Expr::SizeOfPackExprClass: {
|
case Expr::SizeOfPackExprClass: {
|
||||||
|
auto *SPE = cast<SizeOfPackExpr>(E);
|
||||||
|
if (SPE->isPartiallySubstituted()) {
|
||||||
|
Out << "sP";
|
||||||
|
for (const auto &A : SPE->getPartialArguments())
|
||||||
|
mangleTemplateArg(A);
|
||||||
|
Out << "E";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
Out << "sZ";
|
Out << "sZ";
|
||||||
const NamedDecl *Pack = cast<SizeOfPackExpr>(E)->getPack();
|
const NamedDecl *Pack = SPE->getPack();
|
||||||
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
|
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
|
||||||
mangleTemplateParameter(TTP->getIndex());
|
mangleTemplateParameter(TTP->getIndex());
|
||||||
else if (const NonTypeTemplateParmDecl *NTTP
|
else if (const NonTypeTemplateParmDecl *NTTP
|
||||||
|
|
|
@ -1313,6 +1313,14 @@ void StmtProfiler::VisitPackExpansionExpr(const PackExpansionExpr *S) {
|
||||||
void StmtProfiler::VisitSizeOfPackExpr(const SizeOfPackExpr *S) {
|
void StmtProfiler::VisitSizeOfPackExpr(const SizeOfPackExpr *S) {
|
||||||
VisitExpr(S);
|
VisitExpr(S);
|
||||||
VisitDecl(S->getPack());
|
VisitDecl(S->getPack());
|
||||||
|
if (S->isPartiallySubstituted()) {
|
||||||
|
auto Args = S->getPartialArguments();
|
||||||
|
ID.AddInteger(Args.size());
|
||||||
|
for (const auto &TA : Args)
|
||||||
|
VisitTemplateArgument(TA);
|
||||||
|
} else {
|
||||||
|
ID.AddInteger(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr(
|
void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr(
|
||||||
|
|
|
@ -867,8 +867,8 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
|
||||||
|
|
||||||
MarkAnyDeclReferenced(OpLoc, ParameterPack, true);
|
MarkAnyDeclReferenced(OpLoc, ParameterPack, true);
|
||||||
|
|
||||||
return new (Context) SizeOfPackExpr(Context.getSizeType(), OpLoc,
|
return SizeOfPackExpr::Create(Context, OpLoc, ParameterPack, NameLoc,
|
||||||
ParameterPack, NameLoc, RParenLoc);
|
RParenLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateArgumentLoc
|
TemplateArgumentLoc
|
||||||
|
|
|
@ -504,7 +504,8 @@ public:
|
||||||
///
|
///
|
||||||
/// Returns true if there was an error.
|
/// Returns true if there was an error.
|
||||||
bool TransformTemplateArgument(const TemplateArgumentLoc &Input,
|
bool TransformTemplateArgument(const TemplateArgumentLoc &Input,
|
||||||
TemplateArgumentLoc &Output);
|
TemplateArgumentLoc &Output,
|
||||||
|
bool Uneval = false);
|
||||||
|
|
||||||
/// \brief Transform the given set of template arguments.
|
/// \brief Transform the given set of template arguments.
|
||||||
///
|
///
|
||||||
|
@ -526,8 +527,10 @@ public:
|
||||||
/// Returns true if an error occurred.
|
/// Returns true if an error occurred.
|
||||||
bool TransformTemplateArguments(const TemplateArgumentLoc *Inputs,
|
bool TransformTemplateArguments(const TemplateArgumentLoc *Inputs,
|
||||||
unsigned NumInputs,
|
unsigned NumInputs,
|
||||||
TemplateArgumentListInfo &Outputs) {
|
TemplateArgumentListInfo &Outputs,
|
||||||
return TransformTemplateArguments(Inputs, Inputs + NumInputs, Outputs);
|
bool Uneval = false) {
|
||||||
|
return TransformTemplateArguments(Inputs, Inputs + NumInputs, Outputs,
|
||||||
|
Uneval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Transform the given set of template arguments.
|
/// \brief Transform the given set of template arguments.
|
||||||
|
@ -547,7 +550,8 @@ public:
|
||||||
template<typename InputIterator>
|
template<typename InputIterator>
|
||||||
bool TransformTemplateArguments(InputIterator First,
|
bool TransformTemplateArguments(InputIterator First,
|
||||||
InputIterator Last,
|
InputIterator Last,
|
||||||
TemplateArgumentListInfo &Outputs);
|
TemplateArgumentListInfo &Outputs,
|
||||||
|
bool Uneval = false);
|
||||||
|
|
||||||
/// \brief Fakes up a TemplateArgumentLoc for a given TemplateArgument.
|
/// \brief Fakes up a TemplateArgumentLoc for a given TemplateArgument.
|
||||||
void InventTemplateArgumentLoc(const TemplateArgument &Arg,
|
void InventTemplateArgumentLoc(const TemplateArgument &Arg,
|
||||||
|
@ -2615,18 +2619,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Build a new expression to compute the length of a parameter pack.
|
/// \brief Build a new expression to compute the length of a parameter pack.
|
||||||
ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack,
|
ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc,
|
||||||
|
NamedDecl *Pack,
|
||||||
SourceLocation PackLoc,
|
SourceLocation PackLoc,
|
||||||
SourceLocation RParenLoc,
|
SourceLocation RParenLoc,
|
||||||
Optional<unsigned> Length) {
|
Optional<unsigned> Length,
|
||||||
if (Length)
|
ArrayRef<TemplateArgument> PartialArgs) {
|
||||||
return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
|
return SizeOfPackExpr::Create(SemaRef.Context, OperatorLoc, Pack, PackLoc,
|
||||||
OperatorLoc, Pack, PackLoc,
|
RParenLoc, Length, PartialArgs);
|
||||||
RParenLoc, *Length);
|
|
||||||
|
|
||||||
return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
|
|
||||||
OperatorLoc, Pack, PackLoc,
|
|
||||||
RParenLoc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Build a new Objective-C boxed expression.
|
/// \brief Build a new Objective-C boxed expression.
|
||||||
|
@ -3511,7 +3511,7 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc(
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
bool TreeTransform<Derived>::TransformTemplateArgument(
|
bool TreeTransform<Derived>::TransformTemplateArgument(
|
||||||
const TemplateArgumentLoc &Input,
|
const TemplateArgumentLoc &Input,
|
||||||
TemplateArgumentLoc &Output) {
|
TemplateArgumentLoc &Output, bool Uneval) {
|
||||||
const TemplateArgument &Arg = Input.getArgument();
|
const TemplateArgument &Arg = Input.getArgument();
|
||||||
switch (Arg.getKind()) {
|
switch (Arg.getKind()) {
|
||||||
case TemplateArgument::Null:
|
case TemplateArgument::Null:
|
||||||
|
@ -3559,8 +3559,8 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
|
||||||
|
|
||||||
case TemplateArgument::Expression: {
|
case TemplateArgument::Expression: {
|
||||||
// Template argument expressions are constant expressions.
|
// Template argument expressions are constant expressions.
|
||||||
EnterExpressionEvaluationContext Unevaluated(getSema(),
|
EnterExpressionEvaluationContext Unevaluated(
|
||||||
Sema::ConstantEvaluated);
|
getSema(), Uneval ? Sema::Unevaluated : Sema::ConstantEvaluated);
|
||||||
|
|
||||||
Expr *InputExpr = Input.getSourceExpression();
|
Expr *InputExpr = Input.getSourceExpression();
|
||||||
if (!InputExpr) InputExpr = Input.getArgument().getAsExpr();
|
if (!InputExpr) InputExpr = Input.getArgument().getAsExpr();
|
||||||
|
@ -3638,9 +3638,9 @@ public:
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
template<typename InputIterator>
|
template<typename InputIterator>
|
||||||
bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
bool TreeTransform<Derived>::TransformTemplateArguments(
|
||||||
InputIterator Last,
|
InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs,
|
||||||
TemplateArgumentListInfo &Outputs) {
|
bool Uneval) {
|
||||||
for (; First != Last; ++First) {
|
for (; First != Last; ++First) {
|
||||||
TemplateArgumentLoc Out;
|
TemplateArgumentLoc Out;
|
||||||
TemplateArgumentLoc In = *First;
|
TemplateArgumentLoc In = *First;
|
||||||
|
@ -3658,7 +3658,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
||||||
In.getArgument().pack_begin()),
|
In.getArgument().pack_begin()),
|
||||||
PackLocIterator(*this,
|
PackLocIterator(*this,
|
||||||
In.getArgument().pack_end()),
|
In.getArgument().pack_end()),
|
||||||
Outputs))
|
Outputs, Uneval))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -3696,7 +3696,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
||||||
// expansion.
|
// expansion.
|
||||||
TemplateArgumentLoc OutPattern;
|
TemplateArgumentLoc OutPattern;
|
||||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
|
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
|
||||||
if (getDerived().TransformTemplateArgument(Pattern, OutPattern))
|
if (getDerived().TransformTemplateArgument(Pattern, OutPattern, Uneval))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis,
|
Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis,
|
||||||
|
@ -3713,7 +3713,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
||||||
for (unsigned I = 0; I != *NumExpansions; ++I) {
|
for (unsigned I = 0; I != *NumExpansions; ++I) {
|
||||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
|
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
|
||||||
|
|
||||||
if (getDerived().TransformTemplateArgument(Pattern, Out))
|
if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (Out.getArgument().containsUnexpandedParameterPack()) {
|
if (Out.getArgument().containsUnexpandedParameterPack()) {
|
||||||
|
@ -3731,7 +3731,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
||||||
if (RetainExpansion) {
|
if (RetainExpansion) {
|
||||||
ForgetPartiallySubstitutedPackRAII Forget(getDerived());
|
ForgetPartiallySubstitutedPackRAII Forget(getDerived());
|
||||||
|
|
||||||
if (getDerived().TransformTemplateArgument(Pattern, Out))
|
if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
|
Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
|
||||||
|
@ -3746,7 +3746,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The simple case:
|
// The simple case:
|
||||||
if (getDerived().TransformTemplateArgument(In, Out))
|
if (getDerived().TransformTemplateArgument(In, Out, Uneval))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Outputs.addArgument(Out);
|
Outputs.addArgument(Out);
|
||||||
|
@ -10005,9 +10005,15 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
|
||||||
if (!E->isValueDependent())
|
if (!E->isValueDependent())
|
||||||
return E;
|
return E;
|
||||||
|
|
||||||
// Note: None of the implementations of TryExpandParameterPacks can ever
|
EnterExpressionEvaluationContext Unevaluated(getSema(), Sema::Unevaluated);
|
||||||
// produce a diagnostic when given only a single unexpanded parameter pack,
|
|
||||||
// so
|
ArrayRef<TemplateArgument> PackArgs;
|
||||||
|
TemplateArgument ArgStorage;
|
||||||
|
|
||||||
|
// Find the argument list to transform.
|
||||||
|
if (E->isPartiallySubstituted()) {
|
||||||
|
PackArgs = E->getPartialArguments();
|
||||||
|
} else if (E->isValueDependent()) {
|
||||||
UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
|
UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
|
||||||
bool ShouldExpand = false;
|
bool ShouldExpand = false;
|
||||||
bool RetainExpansion = false;
|
bool RetainExpansion = false;
|
||||||
|
@ -10018,23 +10024,67 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
|
||||||
NumExpansions))
|
NumExpansions))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
if (RetainExpansion)
|
// If we need to expand the pack, build a template argument from it and
|
||||||
return E;
|
// expand that.
|
||||||
|
if (ShouldExpand) {
|
||||||
|
auto *Pack = E->getPack();
|
||||||
|
if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Pack)) {
|
||||||
|
ArgStorage = getSema().Context.getPackExpansionType(
|
||||||
|
getSema().Context.getTypeDeclType(TTPD), None);
|
||||||
|
} else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Pack)) {
|
||||||
|
ArgStorage = TemplateArgument(TemplateName(TTPD), None);
|
||||||
|
} else {
|
||||||
|
auto *VD = cast<ValueDecl>(Pack);
|
||||||
|
ExprResult DRE = getSema().BuildDeclRefExpr(VD, VD->getType(),
|
||||||
|
VK_RValue, E->getPackLoc());
|
||||||
|
if (DRE.isInvalid())
|
||||||
|
return ExprError();
|
||||||
|
ArgStorage = new (getSema().Context) PackExpansionExpr(
|
||||||
|
getSema().Context.DependentTy, DRE.get(), E->getPackLoc(), None);
|
||||||
|
}
|
||||||
|
PackArgs = ArgStorage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NamedDecl *Pack = E->getPack();
|
// If we're not expanding the pack, just transform the decl.
|
||||||
if (!ShouldExpand) {
|
if (!PackArgs.size()) {
|
||||||
Pack = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getPackLoc(),
|
auto *Pack = cast_or_null<NamedDecl>(
|
||||||
Pack));
|
getDerived().TransformDecl(E->getPackLoc(), E->getPack()));
|
||||||
if (!Pack)
|
if (!Pack)
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack,
|
||||||
|
E->getPackLoc(),
|
||||||
|
E->getRParenLoc(), None, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateArgumentListInfo TransformedPackArgs(E->getPackLoc(),
|
||||||
|
E->getPackLoc());
|
||||||
|
{
|
||||||
|
TemporaryBase Rebase(*this, E->getPackLoc(), getBaseEntity());
|
||||||
|
typedef TemplateArgumentLocInventIterator<
|
||||||
|
Derived, const TemplateArgument*> PackLocIterator;
|
||||||
|
if (TransformTemplateArguments(PackLocIterator(*this, PackArgs.begin()),
|
||||||
|
PackLocIterator(*this, PackArgs.end()),
|
||||||
|
TransformedPackArgs, /*Uneval*/true))
|
||||||
|
return ExprError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SmallVector<TemplateArgument, 8> Args;
|
||||||
|
bool PartialSubstitution = false;
|
||||||
|
for (auto &Loc : TransformedPackArgs.arguments()) {
|
||||||
|
Args.push_back(Loc.getArgument());
|
||||||
|
if (Loc.getArgument().isPackExpansion())
|
||||||
|
PartialSubstitution = true;
|
||||||
|
}
|
||||||
|
|
||||||
// We now know the length of the parameter pack, so build a new expression
|
if (PartialSubstitution)
|
||||||
// that stores that length.
|
return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
|
||||||
return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack,
|
E->getPackLoc(),
|
||||||
|
E->getRParenLoc(), None, Args);
|
||||||
|
|
||||||
|
return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
|
||||||
E->getPackLoc(), E->getRParenLoc(),
|
E->getPackLoc(), E->getRParenLoc(),
|
||||||
NumExpansions);
|
Args.size(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
|
|
|
@ -1554,11 +1554,20 @@ void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) {
|
||||||
|
|
||||||
void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
|
void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
|
||||||
VisitExpr(E);
|
VisitExpr(E);
|
||||||
|
unsigned NumPartialArgs = Record[Idx++];
|
||||||
E->OperatorLoc = ReadSourceLocation(Record, Idx);
|
E->OperatorLoc = ReadSourceLocation(Record, Idx);
|
||||||
E->PackLoc = ReadSourceLocation(Record, Idx);
|
E->PackLoc = ReadSourceLocation(Record, Idx);
|
||||||
E->RParenLoc = ReadSourceLocation(Record, Idx);
|
E->RParenLoc = ReadSourceLocation(Record, Idx);
|
||||||
|
E->Pack = Reader.ReadDeclAs<NamedDecl>(F, Record, Idx);
|
||||||
|
if (E->isPartiallySubstituted()) {
|
||||||
|
assert(E->Length == NumPartialArgs);
|
||||||
|
for (auto *I = reinterpret_cast<TemplateArgument *>(E + 1),
|
||||||
|
*E = I + NumPartialArgs;
|
||||||
|
I != E; ++I)
|
||||||
|
new (I) TemplateArgument(Reader.ReadTemplateArgument(F, Record, Idx));
|
||||||
|
} else if (!E->isValueDependent()) {
|
||||||
E->Length = Record[Idx++];
|
E->Length = Record[Idx++];
|
||||||
E->Pack = ReadDeclAs<NamedDecl>(Record, Idx);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
|
void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
|
||||||
|
@ -3114,7 +3123,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_SIZEOF_PACK:
|
case EXPR_SIZEOF_PACK:
|
||||||
S = new (Context) SizeOfPackExpr(Empty);
|
S = SizeOfPackExpr::CreateDeserialized(
|
||||||
|
Context,
|
||||||
|
/*NumPartialArgs=*/Record[ASTStmtReader::NumExprFields]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM:
|
case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM:
|
||||||
|
|
|
@ -1558,11 +1558,18 @@ void ASTStmtWriter::VisitPackExpansionExpr(PackExpansionExpr *E) {
|
||||||
|
|
||||||
void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
|
void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
|
||||||
VisitExpr(E);
|
VisitExpr(E);
|
||||||
|
Record.push_back(E->isPartiallySubstituted() ? E->getPartialArguments().size()
|
||||||
|
: 0);
|
||||||
Writer.AddSourceLocation(E->OperatorLoc, Record);
|
Writer.AddSourceLocation(E->OperatorLoc, Record);
|
||||||
Writer.AddSourceLocation(E->PackLoc, Record);
|
Writer.AddSourceLocation(E->PackLoc, Record);
|
||||||
Writer.AddSourceLocation(E->RParenLoc, Record);
|
Writer.AddSourceLocation(E->RParenLoc, Record);
|
||||||
Record.push_back(E->Length);
|
|
||||||
Writer.AddDeclRef(E->Pack, Record);
|
Writer.AddDeclRef(E->Pack, Record);
|
||||||
|
if (E->isPartiallySubstituted()) {
|
||||||
|
for (const auto &TA : E->getPartialArguments())
|
||||||
|
Writer.AddTemplateArgument(TA, Record);
|
||||||
|
} else if (!E->isValueDependent()) {
|
||||||
|
Record.push_back(E->getPackLength());
|
||||||
|
}
|
||||||
Code = serialization::EXPR_SIZEOF_PACK;
|
Code = serialization::EXPR_SIZEOF_PACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
template<unsigned I, typename ...Types>
|
template<unsigned I, typename ...Types>
|
||||||
struct X { };
|
struct X { };
|
||||||
|
|
||||||
template<typename T> struct identity { };
|
template<typename T> struct identity { using type = T; };
|
||||||
template<typename T> struct add_reference;
|
template<typename T> struct add_reference;
|
||||||
template<typename ...Types> struct tuple { };
|
template<typename ...Types> struct tuple { };
|
||||||
template<int ...Values> struct int_tuple { };
|
template<int ...Values> struct int_tuple { };
|
||||||
template<template<typename> class ...Templates> struct template_tuple { };
|
template<template<typename> class ...Templates> struct template_tuple { };
|
||||||
|
template<typename ...T> using ArrayOfN = int[sizeof...(T)];
|
||||||
|
|
||||||
// CHECK-LABEL: define weak_odr void @_Z2f0IJEEv1XIXsZT_EJDpRT_EE
|
// CHECK-LABEL: define weak_odr void @_Z2f0IJEEv1XIXsZT_EJDpRT_EE
|
||||||
template<typename ...Types>
|
template<typename ...Types>
|
||||||
|
@ -65,3 +66,12 @@ template<template<typename> class ...Templates>
|
||||||
template_tuple<Templates...> f7() {}
|
template_tuple<Templates...> f7() {}
|
||||||
// CHECK-LABEL: define weak_odr void @_Z2f7IJ8identity13add_referenceEE14template_tupleIJDpT_EEv
|
// CHECK-LABEL: define weak_odr void @_Z2f7IJ8identity13add_referenceEE14template_tupleIJDpT_EEv
|
||||||
template template_tuple<identity, add_reference> f7();
|
template template_tuple<identity, add_reference> f7();
|
||||||
|
|
||||||
|
template<typename T, typename ...U> void f8(ArrayOfN<int, U..., T, typename U::type...>&) {}
|
||||||
|
// CHECK-LABEL: define weak_odr void @_Z2f8IiJ8identityIiES0_IfEEEvRAsPiDpT0_T_DpNS3_4typeEE_i
|
||||||
|
template void f8<int, identity<int>, identity<float>>(int (&)[6]);
|
||||||
|
|
||||||
|
template<typename ...T> void f10(ArrayOfN<T...> &) {}
|
||||||
|
// FIXME: This is wrong; should be @_Z3f10IJifEEvRAsZT__i
|
||||||
|
// CHECK-LABEL: define weak_odr void @_Z3f10IJifEEvRAsPDpT_E_i
|
||||||
|
template void f10<int, float>(int (&)[2]);
|
||||||
|
|
|
@ -201,3 +201,23 @@ namespace PR16904 {
|
||||||
template <typename T, typename U, typename V>
|
template <typename T, typename U, typename V>
|
||||||
using derived2 = ::PR16904::base<T, U>::template derived<V>; // expected-error {{expected a type}} expected-error {{expected ';'}}
|
using derived2 = ::PR16904::base<T, U>::template derived<V>; // expected-error {{expected a type}} expected-error {{expected ';'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace PR14858 {
|
||||||
|
template<typename ...T> using X = int[sizeof...(T)];
|
||||||
|
|
||||||
|
template<typename ...U> struct Y {
|
||||||
|
using Z = X<U...>;
|
||||||
|
};
|
||||||
|
using A = Y<int, int, int, int>::Z;
|
||||||
|
using A = int[4];
|
||||||
|
|
||||||
|
// FIXME: These should be treated as being redeclarations.
|
||||||
|
template<typename ...T> void f(X<T...> &) {}
|
||||||
|
template<typename ...T> void f(int(&)[sizeof...(T)]) {}
|
||||||
|
|
||||||
|
template<typename ...T> void g(X<typename T::type...> &) {}
|
||||||
|
template<typename ...T> void g(int(&)[sizeof...(T)]) {} // ok, different
|
||||||
|
|
||||||
|
template<typename ...T, typename ...U> void h(X<T...> &) {}
|
||||||
|
template<typename ...T, typename ...U> void h(X<U...> &) {} // ok, different
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue