forked from OSchip/llvm-project
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. llvm-svn: 248431
This commit is contained in:
parent
ed9b8f0a37
commit
d784e6893c
|
@ -3558,43 +3558,51 @@ class SizeOfPackExpr : public Expr {
|
|||
|
||||
/// \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
|
||||
/// \brief Create an 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.
|
||||
SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack,
|
||||
SourceLocation PackLoc, SourceLocation RParenLoc,
|
||||
unsigned Length)
|
||||
Optional<unsigned> Length, ArrayRef<TemplateArgument> PartialArgs)
|
||||
: Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary,
|
||||
/*TypeDependent=*/false, /*ValueDependent=*/false,
|
||||
/*InstantiationDependent=*/false,
|
||||
/*TypeDependent=*/false, /*ValueDependent=*/!Length,
|
||||
/*InstantiationDependent=*/!Length,
|
||||
/*ContainsUnexpandedParameterPack=*/false),
|
||||
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.
|
||||
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; }
|
||||
|
@ -3618,6 +3626,23 @@ public:
|
|||
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; }
|
||||
|
||||
|
|
|
@ -541,6 +541,10 @@ public:
|
|||
return Arguments.data();
|
||||
}
|
||||
|
||||
llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
|
||||
return Arguments;
|
||||
}
|
||||
|
||||
const TemplateArgumentLoc &operator[](unsigned I) const {
|
||||
return Arguments[I];
|
||||
}
|
||||
|
|
|
@ -2017,6 +2017,9 @@ void ASTDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {
|
|||
VisitExpr(Node);
|
||||
dumpPointer(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;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -3458,8 +3458,17 @@ recurse:
|
|||
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
|
||||
|
|
|
@ -1313,6 +1313,14 @@ void StmtProfiler::VisitPackExpansionExpr(const PackExpansionExpr *S) {
|
|||
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(
|
||||
|
|
|
@ -867,8 +867,8 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
|
|||
|
||||
MarkAnyDeclReferenced(OpLoc, ParameterPack, true);
|
||||
|
||||
return new (Context) SizeOfPackExpr(Context.getSizeType(), OpLoc,
|
||||
ParameterPack, NameLoc, RParenLoc);
|
||||
return SizeOfPackExpr::Create(Context, OpLoc, ParameterPack, NameLoc,
|
||||
RParenLoc);
|
||||
}
|
||||
|
||||
TemplateArgumentLoc
|
||||
|
|
|
@ -504,7 +504,8 @@ public:
|
|||
///
|
||||
/// 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.
|
||||
///
|
||||
|
@ -526,8 +527,10 @@ public:
|
|||
/// 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.
|
||||
|
@ -547,7 +550,8 @@ public:
|
|||
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,
|
||||
|
@ -2615,18 +2619,14 @@ public:
|
|||
}
|
||||
|
||||
/// \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.
|
||||
|
@ -3511,7 +3511,7 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc(
|
|||
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:
|
||||
|
@ -3559,8 +3559,8 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
|
|||
|
||||
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();
|
||||
|
@ -3638,9 +3638,9 @@ public:
|
|||
|
||||
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;
|
||||
|
@ -3658,7 +3658,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
|||
In.getArgument().pack_begin()),
|
||||
PackLocIterator(*this,
|
||||
In.getArgument().pack_end()),
|
||||
Outputs))
|
||||
Outputs, Uneval))
|
||||
return true;
|
||||
|
||||
continue;
|
||||
|
@ -3696,7 +3696,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
|||
// 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,
|
||||
|
@ -3713,7 +3713,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
|||
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()) {
|
||||
|
@ -3731,7 +3731,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
|||
if (RetainExpansion) {
|
||||
ForgetPartiallySubstitutedPackRAII Forget(getDerived());
|
||||
|
||||
if (getDerived().TransformTemplateArgument(Pattern, Out))
|
||||
if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval))
|
||||
return true;
|
||||
|
||||
Out = getDerived().RebuildPackExpansion(Out, Ellipsis,
|
||||
|
@ -3746,7 +3746,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
|
|||
}
|
||||
|
||||
// The simple case:
|
||||
if (getDerived().TransformTemplateArgument(In, Out))
|
||||
if (getDerived().TransformTemplateArgument(In, Out, Uneval))
|
||||
return true;
|
||||
|
||||
Outputs.addArgument(Out);
|
||||
|
@ -10005,9 +10005,15 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
|
|||
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
|
||||
EnterExpressionEvaluationContext Unevaluated(getSema(), Sema::Unevaluated);
|
||||
|
||||
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;
|
||||
|
@ -10018,23 +10024,67 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
|
|||
NumExpansions))
|
||||
return ExprError();
|
||||
|
||||
if (RetainExpansion)
|
||||
return E;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// We now know the length of the parameter pack, so build a new expression
|
||||
// that stores that length.
|
||||
return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack,
|
||||
if (PartialSubstitution)
|
||||
return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
|
||||
E->getPackLoc(),
|
||||
E->getRParenLoc(), None, Args);
|
||||
|
||||
return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
|
||||
E->getPackLoc(), E->getRParenLoc(),
|
||||
NumExpansions);
|
||||
Args.size(), None);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
|
|
@ -1554,11 +1554,20 @@ void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) {
|
|||
|
||||
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->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->Pack = ReadDeclAs<NamedDecl>(Record, Idx);
|
||||
}
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
|
||||
|
@ -3114,7 +3123,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
|
|||
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:
|
||||
|
|
|
@ -1558,11 +1558,18 @@ void ASTStmtWriter::VisitPackExpansionExpr(PackExpansionExpr *E) {
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
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>
|
||||
|
@ -65,3 +66,12 @@ template<template<typename> class ...Templates>
|
|||
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]);
|
||||
|
|
|
@ -201,3 +201,23 @@ namespace PR16904 {
|
|||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue