/// \brief The length of the parameter pack, if known.
///
- /// When this expression is value-dependent, the length of the parameter pack
- /// is unknown. When this expression is not value-dependent, the length is
- /// known.
+ /// When this expression is not value-dependent, this is the length of
+ /// the pack. When the expression was parsed rather than instantiated
+ /// (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;
- /// \brief The parameter pack itself.
+ /// \brief The parameter pack.
NamedDecl *Pack;
friend class ASTStmtReader;
friend class ASTStmtWriter;
-public:
- /// \brief Create a value-dependent expression that computes the length of
- /// 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.
+ /// the given parameter pack.
SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
SourceLocation PackLoc, SourceLocation RParenLoc,
- unsigned Length)
- : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary,
- /*TypeDependent=*/false, /*ValueDependent=*/false,
- /*InstantiationDependent=*/false,
- /*ContainsUnexpandedParameterPack=*/false),
- OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc),
- Length(Length), Pack(Pack) { }
+ Optional<unsigned> Length, ArrayRef<TemplateArgument> PartialArgs)
+ : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary,
+ /*TypeDependent=*/false, /*ValueDependent=*/!Length,
+ /*InstantiationDependent=*/!Length,
+ /*ContainsUnexpandedParameterPack=*/false),
+ OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc),
+ 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.
- 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.
SourceLocation getOperatorLoc() const { return OperatorLoc; }
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 getLocEnd() const LLVM_READONLY { return RParenLoc; }
return Arguments.data();
}
+ llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
+ return Arguments;
+ }
+
const TemplateArgumentLoc &operator[](unsigned I) const {
return Arguments[I];
}
VisitExpr(Node);
dumpPointer(Node->getPack());
dumpName(Node->getPack());
+ if (Node->isPartiallySubstituted())
+ for (const auto &A : Node->getPartialArguments())
+ dumpTemplateArgument(A);
}
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(QualType T,
NonTypeTemplateParmDecl *Param,
break;
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";
- const NamedDecl *Pack = cast<SizeOfPackExpr>(E)->getPack();
+ const NamedDecl *Pack = SPE->getPack();
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
mangleTemplateParameter(TTP->getIndex());
else if (const NonTypeTemplateParmDecl *NTTP
void StmtProfiler::VisitSizeOfPackExpr(const SizeOfPackExpr *S) {
VisitExpr(S);
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(
MarkAnyDeclReferenced(OpLoc, ParameterPack, true);
- return new (Context) SizeOfPackExpr(Context.getSizeType(), OpLoc,
- ParameterPack, NameLoc, RParenLoc);
+ return SizeOfPackExpr::Create(Context, OpLoc, ParameterPack, NameLoc,
+ RParenLoc);
}
TemplateArgumentLoc
///
/// Returns true if there was an error.
bool TransformTemplateArgument(const TemplateArgumentLoc &Input,
- TemplateArgumentLoc &Output);
+ TemplateArgumentLoc &Output,
+ bool Uneval = false);
/// \brief Transform the given set of template arguments.
///
/// Returns true if an error occurred.
bool TransformTemplateArguments(const TemplateArgumentLoc *Inputs,
unsigned NumInputs,
- TemplateArgumentListInfo &Outputs) {
- return TransformTemplateArguments(Inputs, Inputs + NumInputs, Outputs);
+ TemplateArgumentListInfo &Outputs,
+ bool Uneval = false) {
+ return TransformTemplateArguments(Inputs, Inputs + NumInputs, Outputs,
+ Uneval);
}
/// \brief Transform the given set of template arguments.
template<typename InputIterator>
bool TransformTemplateArguments(InputIterator First,
InputIterator Last,
- TemplateArgumentListInfo &Outputs);
+ TemplateArgumentListInfo &Outputs,
+ bool Uneval = false);
/// \brief Fakes up a TemplateArgumentLoc for a given TemplateArgument.
void InventTemplateArgumentLoc(const TemplateArgument &Arg,
}
/// \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 RParenLoc,
- Optional<unsigned> Length) {
- if (Length)
- return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
- OperatorLoc, Pack, PackLoc,
- RParenLoc, *Length);
-
- return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
- OperatorLoc, Pack, PackLoc,
- RParenLoc);
+ Optional<unsigned> Length,
+ ArrayRef<TemplateArgument> PartialArgs) {
+ return SizeOfPackExpr::Create(SemaRef.Context, OperatorLoc, Pack, PackLoc,
+ RParenLoc, Length, PartialArgs);
}
/// \brief Build a new Objective-C boxed expression.
template<typename Derived>
bool TreeTransform<Derived>::TransformTemplateArgument(
const TemplateArgumentLoc &Input,
- TemplateArgumentLoc &Output) {
+ TemplateArgumentLoc &Output, bool Uneval) {
const TemplateArgument &Arg = Input.getArgument();
switch (Arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Expression: {
// Template argument expressions are constant expressions.
- EnterExpressionEvaluationContext Unevaluated(getSema(),
- Sema::ConstantEvaluated);
+ EnterExpressionEvaluationContext Unevaluated(
+ getSema(), Uneval ? Sema::Unevaluated : Sema::ConstantEvaluated);
Expr *InputExpr = Input.getSourceExpression();
if (!InputExpr) InputExpr = Input.getArgument().getAsExpr();
template<typename Derived>
template<typename InputIterator>
-bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
- InputIterator Last,
- TemplateArgumentListInfo &Outputs) {
+bool TreeTransform<Derived>::TransformTemplateArguments(
+ InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs,
+ bool Uneval) {
for (; First != Last; ++First) {
TemplateArgumentLoc Out;
TemplateArgumentLoc In = *First;
In.getArgument().pack_begin()),
PackLocIterator(*this,
In.getArgument().pack_end()),
- Outputs))
+ Outputs, Uneval))
return true;
continue;
// expansion.
TemplateArgumentLoc OutPattern;
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
- if (getDerived().TransformTemplateArgument(Pattern, OutPattern))
+ if (getDerived().TransformTemplateArgument(Pattern, OutPattern, Uneval))
return true;
Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis,
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
- if (getDerived().TransformTemplateArgument(Pattern, Out))
+ if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval))
return true;
if (Out.getArgument().containsUnexpandedParameterPack()) {
if (RetainExpansion) {
ForgetPartiallySubstitutedPackRAII Forget(getDerived());
- if (getDerived().TransformTemplateArgument(Pattern, Out))
+ if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval))
return true;
Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
}
// The simple case:
- if (getDerived().TransformTemplateArgument(In, Out))
+ if (getDerived().TransformTemplateArgument(In, Out, Uneval))
return true;
Outputs.addArgument(Out);
if (!E->isValueDependent())
return E;
- // Note: None of the implementations of TryExpandParameterPacks can ever
- // produce a diagnostic when given only a single unexpanded parameter pack,
- // so
- UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
- bool ShouldExpand = false;
- bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
- if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
- Unexpanded,
- ShouldExpand, RetainExpansion,
- NumExpansions))
- return ExprError();
+ EnterExpressionEvaluationContext Unevaluated(getSema(), Sema::Unevaluated);
- if (RetainExpansion)
- return E;
+ 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());
+ bool ShouldExpand = false;
+ bool RetainExpansion = false;
+ Optional<unsigned> NumExpansions;
+ if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
+ Unexpanded,
+ ShouldExpand, RetainExpansion,
+ NumExpansions))
+ return ExprError();
+
+ // If we need to expand the pack, build a template argument from it and
+ // 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 (!ShouldExpand) {
- Pack = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getPackLoc(),
- Pack));
+ // If we're not expanding the pack, just transform the decl.
+ if (!PackArgs.size()) {
+ auto *Pack = cast_or_null<NamedDecl>(
+ getDerived().TransformDecl(E->getPackLoc(), E->getPack()));
if (!Pack)
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;
}
+ if (PartialSubstitution)
+ return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
+ E->getPackLoc(),
+ E->getRParenLoc(), None, Args);
- // We now know the length of the parameter pack, so build a new expression
- // that stores that length.
- return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack,
+ return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
E->getPackLoc(), E->getRParenLoc(),
- NumExpansions);
+ Args.size(), None);
}
template<typename Derived>
void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
VisitExpr(E);
+ unsigned NumPartialArgs = Record[Idx++];
E->OperatorLoc = ReadSourceLocation(Record, Idx);
E->PackLoc = ReadSourceLocation(Record, Idx);
E->RParenLoc = ReadSourceLocation(Record, Idx);
- E->Length = Record[Idx++];
- E->Pack = ReadDeclAs<NamedDecl>(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++];
+ }
}
void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
break;
case EXPR_SIZEOF_PACK:
- S = new (Context) SizeOfPackExpr(Empty);
+ S = SizeOfPackExpr::CreateDeserialized(
+ Context,
+ /*NumPartialArgs=*/Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM:
void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
VisitExpr(E);
+ Record.push_back(E->isPartiallySubstituted() ? E->getPartialArguments().size()
+ : 0);
Writer.AddSourceLocation(E->OperatorLoc, Record);
Writer.AddSourceLocation(E->PackLoc, Record);
Writer.AddSourceLocation(E->RParenLoc, Record);
- Record.push_back(E->Length);
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;
}
template<unsigned I, typename ...Types>
struct X { };
-template<typename T> struct identity { };
+template<typename T> struct identity { using type = T; };
template<typename T> struct add_reference;
template<typename ...Types> struct tuple { };
template<int ...Values> struct int_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
template<typename ...Types>
template_tuple<Templates...> f7() {}
// CHECK-LABEL: define weak_odr void @_Z2f7IJ8identity13add_referenceEE14template_tupleIJDpT_EEv
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]);
template <typename T, typename U, typename V>
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
+}