[clang] Fixes how we represent / emulate builtin templates

We change the template specialization of builtin templates to
behave like aliases.

Though unlike real alias templates, these might still produce a canonical
TemplateSpecializationType when some important argument is dependent.

For example, we can't do anything about make_integer_seq when the
count is dependent, or a type_pack_element when the index is dependent.

We change type deduction to not try to deduce canonical TSTs of
builtin templates.

We also change those buitin templates to produce substitution sugar,
just like a real instantiation would, making the resulting type correctly
represent the template arguments used to specialize the underlying template.

And make_integer_seq will now produce a TST for the specialization
of it's first argument, which we use as the underlying type of
the builtin alias.

When performing member access on the resulting type, it's now
possible to map from a Subst* node to the template argument
as-written used in a regular fashion, without special casing.

And this fixes a bunch of bugs with relation to these builtin
templates factoring into deduction.

Fixes GH42102 and GH51928.

Depends on D133261

Signed-off-by: Matheus Izvekov <mizvekov@gmail.com>

Differential Revision: https://reviews.llvm.org/D133262
This commit is contained in:
Matheus Izvekov 2022-09-03 18:36:59 +02:00
parent a8843ec952
commit f4ea3bd4b2
No known key found for this signature in database
GPG Key ID: 22C080C6DC4E70F8
10 changed files with 230 additions and 100 deletions

View File

@ -122,6 +122,9 @@ Bug Fixes
- Clang will now no longer treat a C 'overloadable' function without a prototype as
a variadic function with the attribute. This should make further diagnostics more
clear.
- Fixes to builtin template emulation of regular templates.
`Issue 42102 <https://github.com/llvm/llvm-project/issues/42102>`_
`Issue 51928 <https://github.com/llvm/llvm-project/issues/51928>`_
Improvements to Clang's diagnostics

View File

@ -1636,7 +1636,7 @@ public:
ArrayRef<TemplateArgument> Args) const;
QualType getTemplateSpecializationType(TemplateName T,
const TemplateArgumentListInfo &Args,
ArrayRef<TemplateArgumentLoc> Args,
QualType Canon = QualType()) const;
TypeSourceInfo *

View File

@ -440,6 +440,9 @@ public:
/// Get the underlying, templated declaration.
NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
// Should a specialization behave like an alias for another type.
bool isTypeAlias() const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }

View File

@ -4848,7 +4848,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType Underlying) const {
assert(!Name.getAsDependentTemplateName() &&
"No dependent template names here!");
QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
QualType TST =
getTemplateSpecializationType(Name, Args.arguments(), Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
TemplateSpecializationTypeLoc TL =
@ -4864,14 +4865,14 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgumentListInfo &Args,
ArrayRef<TemplateArgumentLoc> Args,
QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
SmallVector<TemplateArgument, 4> ArgVec;
ArgVec.reserve(Args.size());
for (const TemplateArgumentLoc &Arg : Args.arguments())
for (const TemplateArgumentLoc &Arg : Args)
ArgVec.push_back(Arg.getArgument());
return getTemplateSpecializationType(Template, ArgVec, Underlying);
@ -4897,8 +4898,8 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = QTN->getUnderlyingTemplate();
bool IsTypeAlias =
isa_and_nonnull<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
const auto *TD = Template.getAsTemplateDecl();
bool IsTypeAlias = TD && TD->isTypeAlias();
QualType CanonType;
if (!Underlying.isNull())
CanonType = getCanonicalType(Underlying);

View File

@ -250,6 +250,16 @@ bool TemplateDecl::hasAssociatedConstraints() const {
return false;
}
bool TemplateDecl::isTypeAlias() const {
switch (getKind()) {
case TemplateDecl::TypeAliasTemplate:
case TemplateDecl::BuiltinTemplate:
return true;
default:
return false;
};
}
//===----------------------------------------------------------------------===//
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//

View File

@ -1263,10 +1263,11 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
assert(Ty->isTypeAlias());
llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit);
auto *AliasDecl =
cast<TypeAliasTemplateDecl>(Ty->getTemplateName().getAsTemplateDecl())
->getTemplatedDecl();
const TemplateDecl *TD = Ty->getTemplateName().getAsTemplateDecl();
if (isa<BuiltinTemplateDecl>(TD))
return Src;
const auto *AliasDecl = cast<TypeAliasTemplateDecl>(TD)->getTemplatedDecl();
if (AliasDecl->hasAttr<NoDebugAttr>())
return Src;

View File

@ -3501,45 +3501,70 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
ASTContext &Context = SemaRef.getASTContext();
TemplateParameterList *TPL = BTD->getTemplateParameters();
// Wrap the type in substitution sugar.
auto getSubstType = [&](unsigned IndexReplaced, QualType Replacement) {
QualType TTP = SemaRef.Context.getTemplateTypeParmType(
0, IndexReplaced, false,
cast<TemplateTypeParmDecl>(TPL->getParam(IndexReplaced)));
return SemaRef.Context.getSubstTemplateTypeParmType(
cast<TemplateTypeParmType>(TTP), Replacement.getCanonicalType());
};
switch (BTD->getBuiltinTemplateKind()) {
case BTK__make_integer_seq: {
// Specializations of __make_integer_seq<S, T, N> are treated like
// S<T, 0, ..., N-1>.
QualType OrigType = Converted[1].getAsType();
// C++14 [inteseq.intseq]p1:
// T shall be an integer type.
if (!Converted[1].getAsType()->isIntegralType(Context)) {
if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) {
SemaRef.Diag(TemplateArgs[1].getLocation(),
diag::err_integer_sequence_integral_element_type);
return QualType();
}
// C++14 [inteseq.make]p1:
// If N is negative the program is ill-formed.
TemplateArgument NumArgsArg = Converted[2];
llvm::APSInt NumArgs = NumArgsArg.getAsIntegral();
if (NumArgs < 0) {
if (NumArgsArg.isDependent())
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
Converted);
TemplateArgumentListInfo SyntheticTemplateArgs;
// The type argument, wrapped in substitution sugar, gets reused as the
// first template argument in the synthetic template argument list.
QualType SyntheticType = getSubstType(1, OrigType);
SyntheticTemplateArgs.addArgument(
TemplateArgumentLoc(TemplateArgument(SyntheticType),
SemaRef.Context.getTrivialTypeSourceInfo(
SyntheticType, TemplateArgs[1].getLocation())));
if (llvm::APSInt NumArgs = NumArgsArg.getAsIntegral(); NumArgs >= 0) {
// Expand N into 0 ... N-1.
for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
I < NumArgs; ++I) {
TemplateArgument TA(Context, I, SyntheticType);
SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
TA, SyntheticType, TemplateArgs[2].getLocation()));
}
} else {
// C++14 [inteseq.make]p1:
// If N is negative the program is ill-formed.
SemaRef.Diag(TemplateArgs[2].getLocation(),
diag::err_integer_sequence_negative_length);
return QualType();
}
QualType ArgTy = NumArgsArg.getIntegralType();
TemplateArgumentListInfo SyntheticTemplateArgs;
// The type argument gets reused as the first template argument in the
// synthetic template argument list.
SyntheticTemplateArgs.addArgument(TemplateArgs[1]);
// Expand N into 0 ... N-1.
for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
I < NumArgs; ++I) {
TemplateArgument TA(Context, I, ArgTy);
SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
TA, ArgTy, TemplateArgs[2].getLocation()));
}
// Wrap the template in substitution sugar.
TemplateName TN = SemaRef.Context.getSubstTemplateTemplateParm(
cast<TemplateTemplateParmDecl>(TPL->getParam(0)),
Converted[0].getAsTemplate());
// The first template argument will be reused as the template decl that
// our synthetic template arguments will be applied to.
return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(),
TemplateLoc, SyntheticTemplateArgs);
return SemaRef.CheckTemplateIdType(TN, TemplateLoc, SyntheticTemplateArgs);
}
case BTK__type_pack_element:
@ -3549,11 +3574,15 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
assert(Converted.size() == 2 &&
"__type_pack_element should be given an index and a parameter pack");
// If the Index is out of bounds, the program is ill-formed.
TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
if (IndexArg.isDependent() || Ts.isDependent())
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
Converted);
llvm::APSInt Index = IndexArg.getAsIntegral();
assert(Index >= 0 && "the index used with __type_pack_element should be of "
"type std::size_t, and hence be non-negative");
// If the Index is out of bounds, the program is ill-formed.
if (Index >= Ts.pack_size()) {
SemaRef.Diag(TemplateArgs[0].getLocation(),
diag::err_type_pack_element_out_of_bounds);
@ -3562,7 +3591,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
// We simply return the type at index `Index`.
auto Nth = std::next(Ts.pack_begin(), Index.getExtValue());
return Nth->getAsType();
return getSubstType(1, Nth->getAsType());
}
llvm_unreachable("unexpected BuiltinTemplateDecl!");
}
@ -3730,7 +3759,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
return Context.getTemplateSpecializationType(Name, TemplateArgs);
return Context.getTemplateSpecializationType(Name,
TemplateArgs.arguments());
Diag(TemplateLoc, diag::err_template_id_not_a_type)
<< Name;
@ -3808,6 +3838,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
return QualType();
}
} else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc,
TemplateArgs);
} else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
TemplateArgs, Converted)) {
@ -3857,8 +3890,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
break;
}
}
} else if (ClassTemplateDecl *ClassTemplate
= dyn_cast<ClassTemplateDecl>(Template)) {
} else if (ClassTemplateDecl *ClassTemplate =
dyn_cast<ClassTemplateDecl>(Template)) {
// Find the class template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
@ -3895,15 +3928,15 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
CanonType = Context.getTypeDeclType(Decl);
assert(isa<RecordType>(CanonType) &&
"type of non-dependent specialization is not a RecordType");
} else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc,
TemplateArgs);
} else {
llvm_unreachable("Unhandled template kind");
}
// Build the fully-sugared type for this class template
// specialization, which refers back to the class template
// specialization we created or found.
return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(),
CanonType);
}
void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName,

View File

@ -563,6 +563,12 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
// FIXME: Try to preserve type sugar here, which is hard
// because of the unresolved template arguments.
const auto *TP = UP.getCanonicalType()->castAs<TemplateSpecializationType>();
TemplateName TNP = TP->getTemplateName();
// If the parameter is an alias template, there is nothing to deduce.
if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias())
return Sema::TDK_Success;
ArrayRef<TemplateArgument> PResolved = TP->template_arguments();
QualType UA = A;
@ -574,10 +580,15 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
// FIXME: Should not lose sugar here.
if (const auto *SA =
dyn_cast<TemplateSpecializationType>(UA.getCanonicalType())) {
TemplateName TNA = SA->getTemplateName();
// If the argument is an alias template, there is nothing to deduce.
if (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias())
return Sema::TDK_Success;
// Perform template argument deduction for the template name.
if (auto Result =
DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(),
SA->getTemplateName(), Info, Deduced))
DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, Deduced))
return Result;
// Perform template argument deduction on each template
// argument. Ignore any missing/extra arguments, since they could be

View File

@ -4,21 +4,31 @@ template <class A1, A1... A2> struct A {};
using test1 = __make_integer_seq<A, int, 1>;
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:5:1, col:43> col:7 test1 '__make_integer_seq<A, int, 1>':'A<int, 0>'
// CHECK-NEXT: | `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, 1>' sugar
// CHECK-NEXT: | `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, 1>' sugar __make_integer_seq
// CHECK-NEXT: | |-TemplateArgument template A
// CHECK-NEXT: | |-TemplateArgument type 'int'
// CHECK-NEXT: | | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: | |-TemplateArgument expr
// CHECK-NEXT: | | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int'
// CHECK-NEXT: | | |-value: Int 1
// CHECK-NEXT: | | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
// CHECK-NEXT: | `-RecordType 0x{{[0-9A-Fa-f]+}} 'A<int, 0>'
// CHECK-NEXT: | `-ClassTemplateSpecialization 0x{{[0-9A-Fa-f]+}} 'A'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, 1>' sugar
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, 1>' sugar alias __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template A
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int'
// CHECK-NEXT: | |-value: Int 1
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} 'A<int, 0>' sugar A
// CHECK-NEXT: |-TemplateArgument type 'int':'int'
// CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'int' sugar
// CHECK-NEXT: | |-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'auto' dependent depth 0 index 1
// CHECK-NEXT: | | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} ''
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int'
// CHECK-NEXT: | |-value: Int 0
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int':'int' 0
// CHECK-NEXT: `-RecordType 0x{{[0-9A-Fa-f]+}} 'A<int, 0>'
// CHECK-NEXT: `-ClassTemplateSpecialization 0x{{[0-9A-Fa-f]+}} 'A'
template <class B1, B1 B2> using B = __make_integer_seq<A, B1, B2>;
using test2 = B<int, 1>;
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:20:1, col:23> col:7 test2 'B<int, 1>':'A<int, 0>'
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:30:1, col:23> col:7 test2 'B<int, 1>':'A<int, 0>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} 'B<int, 1>' sugar
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} 'B<int, 1>' sugar alias B
// CHECK-NEXT: |-TemplateArgument type 'int'
@ -28,7 +38,7 @@ using test2 = B<int, 1>;
// CHECK-NEXT: | |-value: Int 1
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:22> 'int' 1
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, 1>' sugar
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, 1>' sugar __make_integer_seq
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, 1>' sugar alias __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template A
// CHECK-NEXT: |-TemplateArgument type 'int':'int'
// CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'int' sugar
@ -36,61 +46,93 @@ using test2 = B<int, 1>;
// CHECK-NEXT: | | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'B1'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <line:19:64> 'int'
// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <line:29:64> 'int'
// CHECK-NEXT: | |-value: Int 1
// CHECK-NEXT: | `-SubstNonTypeTemplateParmExpr 0x{{[0-9A-Fa-f]+}} <col:64> 'int'
// CHECK-NEXT: | |-NonTypeTemplateParmDecl 0x{{[0-9A-Fa-f]+}} <col:21, col:24> col:24 referenced 'B1' depth 0 index 1 B2
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:64> 'int' 1
// CHECK-NEXT: `-RecordType 0x{{[0-9A-Fa-f]+}} 'A<int, 0>'
// CHECK-NEXT: `-ClassTemplateSpecialization 0x{{[0-9A-Fa-f]+}} 'A'
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} 'A<int, 0>' sugar A
// CHECK-NEXT: |-TemplateArgument type 'int':'int'
// CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'int' sugar
// CHECK-NEXT: | |-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'auto' dependent depth 0 index 1
// CHECK-NEXT: | | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} ''
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <col:64> 'int'
// CHECK-NEXT: | |-value: Int 0
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:64> 'int':'int' 0
// CHECK-NEXT: `-RecordType 0x{{[0-9A-Fa-f]+}} 'A<int, 0>'
// CHECK-NEXT: `-ClassTemplateSpecialization 0x{{[0-9A-Fa-f]+}} 'A'
template <template <class T, T...> class S, class T, int N> struct C {
using test3 = __make_integer_seq<S, T, N>;
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:48:3, col:43> col:9 test3 '__make_integer_seq<S, T, N>':'__make_integer_seq<S, T, N>'
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:68:3, col:43> col:9 test3 '__make_integer_seq<S, T, N>':'__make_integer_seq<type-parameter-0-1, N>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' sugar dependent
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' dependent __make_integer_seq
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<S, T, N>' sugar dependent alias __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template S
// CHECK-NEXT: |-TemplateArgument type 'T'
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T'
// CHECK-NEXT: `-TemplateArgument expr
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'type-parameter-0-1':'type-parameter-0-1' <Dependent>
// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'type-parameter-0-1':'type-parameter-0-1' <Dependent>
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<type-parameter-0-1, N>' dependent __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template
// CHECK-NEXT: |-TemplateArgument type 'type-parameter-0-1'
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent depth 0 index 1
// CHECK-NEXT: `-TemplateArgument expr
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'type-parameter-0-1':'type-parameter-0-1' <Dependent>
// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
using test4 = __make_integer_seq<A, T, 1>;
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:60:3, col:43> col:9 test4 '__make_integer_seq<A, T, 1>':'__make_integer_seq<A, T, 1>'
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:87:3, col:43> col:9 test4 '__make_integer_seq<A, T, 1>':'__make_integer_seq<A, type-parameter-0-1, 1>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' sugar dependent
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' dependent __make_integer_seq
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, T, 1>' sugar dependent alias __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template A
// CHECK-NEXT: |-TemplateArgument type 'T'
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T'
// CHECK-NEXT: `-TemplateArgument expr
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'type-parameter-0-1':'type-parameter-0-1' <Dependent>
// CHECK-NEXT: `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'type-parameter-0-1':'type-parameter-0-1' <Dependent>
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, type-parameter-0-1, 1>' dependent __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template A
// CHECK-NEXT: |-TemplateArgument type 'type-parameter-0-1'
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent depth 0 index 1
// CHECK-NEXT: `-TemplateArgument expr
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'type-parameter-0-1':'type-parameter-0-1' <Dependent>
// CHECK-NEXT: `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
using test5 = __make_integer_seq<A, int, N>;
// CHECK: `-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:72:3, col:45> col:9 test5 '__make_integer_seq<A, int, N>':'__make_integer_seq<A, int, N>'
// CHECK: `-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:106:3, col:45> col:9 test5 '__make_integer_seq<A, int, N>':'__make_integer_seq<A, int, N>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' sugar dependent
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' dependent __make_integer_seq
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' sugar dependent alias __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template A
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: `-TemplateArgument expr
// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__make_integer_seq<A, int, N>' dependent __make_integer_seq
// CHECK-NEXT: |-TemplateArgument template A
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: `-TemplateArgument expr
// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:44> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
};
template <class T, class S> struct D; // expected-note {{template is declared here}}
// expected-no-diagnostics
template <class T, class S> struct D;
template <class T> struct D<T, __make_integer_seq<A, int, sizeof(T)>> {};
template struct D<char, A<int, 0>>; // expected-error {{explicit instantiation of undefined template}}
template struct D<char, A<int, 0>>;
template <class T, class S> struct E; // expected-note {{template is declared here}}
template <class T, class S> struct E;
template <class T> struct E<T, __make_integer_seq<A, T, 2>> {};
template struct E<short, A<short, 0, 1>>; // expected-error {{explicit instantiation of undefined template}}
template struct E<short, A<short, 0, 1>>;
template <template <class A1, A1... A2> class T, class S> struct F; // expected-note {{template is declared here}}
template <template <class A1, A1... A2> class T, class S> struct F;
template <template <class A1, A1... A2> class T> struct F<T, __make_integer_seq<T, long, 3>> {};
template struct F<A, A<long, 0, 1, 2>>; // expected-error {{explicit instantiation of undefined template}}
template struct F<A, A<long, 0, 1, 2>>;
template <class T> struct G;
template <class T> struct G<__make_integer_seq<A, T, 1>> {};
@ -99,5 +141,5 @@ template <class T> struct G<__make_integer_seq<A, T, 1U>> {};
template <int S, class = __make_integer_seq<A, int, S>> struct H;
template <int S, int... Is> struct H<S, A<int, Is...>> { };
template <int S> void h(H<S>); // expected-note {{could not match '__make_integer_seq' against 'A'}}
void test_h() { h(H<5>{}); } // expected-error {{no matching function for call to 'h'}}
template <int S> void h(H<S>);
void test_h() { h(H<5>{}); }

View File

@ -3,7 +3,7 @@
using test1 = __type_pack_element<0, int>;
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <<stdin>:3:1, col:41> col:7 test1 '__type_pack_element<0, int>':'int'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, int>' sugar
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, int>' sugar __type_pack_element
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, int>' sugar alias __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <col:35> 'unsigned long'
// CHECK-NEXT: | |-value: Int 0
@ -11,53 +11,79 @@ using test1 = __type_pack_element<0, int>;
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:35> 'int' 0
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: `-SubstTemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'int' sugar
// CHECK-NEXT: |-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'auto' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} ''
// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
template<int N, class ...Ts> struct A {
using test2 = __type_pack_element<N, Ts...>;
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:17:3, col:45> col:9 test2 '__type_pack_element<N, Ts...>':'__type_pack_element<N, Ts...>'
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:20:3, col:45> col:9 test2 '__type_pack_element<N, Ts...>':'__type_pack_element<N, type-parameter-0-1...>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' sugar dependent
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' dependent __type_pack_element
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, Ts...>' sugar dependent alias __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
// CHECK-NEXT: `-TemplateArgument type 'Ts...'
// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
// CHECK-NEXT: `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
// CHECK-NEXT: |-TemplateArgument type 'Ts...'
// CHECK-NEXT: | `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, type-parameter-0-1...>' dependent __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
// CHECK-NEXT: `-TemplateArgument pack
// CHECK-NEXT: `-TemplateArgument type 'type-parameter-0-1...'
// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1...' dependent
// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack
using test3 = __type_pack_element<0, Ts...>;
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:29:3, col:45> col:9 test3 '__type_pack_element<0, Ts...>':'__type_pack_element<0, Ts...>'
// CHECK: |-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:40:3, col:45> col:9 test3 '__type_pack_element<0, Ts...>':'__type_pack_element<0, type-parameter-0-1...>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' sugar dependent
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' dependent __type_pack_element
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, Ts...>' sugar dependent alias __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ConstantExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long'
// CHECK-NEXT: | |-value: Int 0
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
// CHECK-NEXT: | `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:37> 'int' 0
// CHECK-NEXT: `-TemplateArgument type 'Ts...'
// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
// CHECK-NEXT: `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
// CHECK-NEXT: |-TemplateArgument type 'Ts...'
// CHECK-NEXT: | `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'Ts...' dependent
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'Ts'
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<0, type-parameter-0-1...>' dependent __type_pack_element
// CHECK-NEXT: |-TemplateArgument integral 0
// CHECK-NEXT: `-TemplateArgument pack
// CHECK-NEXT: `-TemplateArgument type 'type-parameter-0-1...'
// CHECK-NEXT: `-PackExpansionType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1...' dependent
// CHECK-NEXT: `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-1' dependent contains_unexpanded_pack depth 0 index 1 pack
using test4 = __type_pack_element<N, int>;
// CHECK: `-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:43:3, col:43> col:9 test4 '__type_pack_element<N, int>':'__type_pack_element<N, int>'
// CHECK: `-TypeAliasDecl 0x{{[0-9A-Fa-f]+}} <line:60:3, col:43> col:9 test4 '__type_pack_element<N, int>':'__type_pack_element<N, int>'
// CHECK-NEXT: `-ElaboratedType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' sugar dependent
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' dependent __type_pack_element
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' sugar dependent alias __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
// CHECK-NEXT: `-TemplateArgument type 'int'
// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
// CHECK-NEXT: `-TemplateSpecializationType 0x{{[0-9A-Fa-f]+}} '__type_pack_element<N, int>' dependent __type_pack_element
// CHECK-NEXT: |-TemplateArgument expr
// CHECK-NEXT: | `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'unsigned long' <IntegralCast>
// CHECK-NEXT: | `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:37> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
// CHECK-NEXT: `-TemplateArgument pack
// CHECK-NEXT: `-TemplateArgument type 'int'
// CHECK-NEXT: `-BuiltinType 0x{{[0-9A-Fa-f]+}} 'int'
};
template <class T, class S> struct B; // expected-note {{template is declared here}}
template <class T> struct B<T, __type_pack_element<sizeof(T), void, long>> {};
template struct B<char, long>; // expected-error {{explicit instantiation of undefined template}}
// expected-no-diagnostics
template <class T, class S> struct C; // expected-note {{template is declared here}}
template <class T, class S> struct B;
template <class T> struct B<T, __type_pack_element<sizeof(T), void, long>> {};
template struct B<char, long>;
template <class T, class S> struct C;
template <class T> struct C<T, __type_pack_element<0, T, short>> {};
template struct C<int, int>; // expected-error {{explicit instantiation of undefined template}}
template struct C<int, int>;
template <class T> struct D;
template <class T, class U> struct D<__type_pack_element<0, T, U>> {};