Skip to content

Commit f4ea3bd

Browse files
committed
[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 <[email protected]> Differential Revision: https://reviews.llvm.org/D133262
1 parent a8843ec commit f4ea3bd

File tree

10 files changed

+229
-99
lines changed

10 files changed

+229
-99
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ Bug Fixes
122122
- Clang will now no longer treat a C 'overloadable' function without a prototype as
123123
a variadic function with the attribute. This should make further diagnostics more
124124
clear.
125+
- Fixes to builtin template emulation of regular templates.
126+
`Issue 42102 <https://github.com/llvm/llvm-project/issues/42102>`_
127+
`Issue 51928 <https://github.com/llvm/llvm-project/issues/51928>`_
125128

126129

127130
Improvements to Clang's diagnostics

clang/include/clang/AST/ASTContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1636,7 +1636,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
16361636
ArrayRef<TemplateArgument> Args) const;
16371637

16381638
QualType getTemplateSpecializationType(TemplateName T,
1639-
const TemplateArgumentListInfo &Args,
1639+
ArrayRef<TemplateArgumentLoc> Args,
16401640
QualType Canon = QualType()) const;
16411641

16421642
TypeSourceInfo *

clang/include/clang/AST/DeclTemplate.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,9 @@ class TemplateDecl : public NamedDecl {
440440
/// Get the underlying, templated declaration.
441441
NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
442442

443+
// Should a specialization behave like an alias for another type.
444+
bool isTypeAlias() const;
445+
443446
// Implement isa/cast/dyncast/etc.
444447
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
445448

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4848,7 +4848,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
48484848
QualType Underlying) const {
48494849
assert(!Name.getAsDependentTemplateName() &&
48504850
"No dependent template names here!");
4851-
QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
4851+
QualType TST =
4852+
getTemplateSpecializationType(Name, Args.arguments(), Underlying);
48524853

48534854
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
48544855
TemplateSpecializationTypeLoc TL =
@@ -4864,14 +4865,14 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
48644865

48654866
QualType
48664867
ASTContext::getTemplateSpecializationType(TemplateName Template,
4867-
const TemplateArgumentListInfo &Args,
4868+
ArrayRef<TemplateArgumentLoc> Args,
48684869
QualType Underlying) const {
48694870
assert(!Template.getAsDependentTemplateName() &&
48704871
"No dependent template names here!");
48714872

48724873
SmallVector<TemplateArgument, 4> ArgVec;
48734874
ArgVec.reserve(Args.size());
4874-
for (const TemplateArgumentLoc &Arg : Args.arguments())
4875+
for (const TemplateArgumentLoc &Arg : Args)
48754876
ArgVec.push_back(Arg.getArgument());
48764877

48774878
return getTemplateSpecializationType(Template, ArgVec, Underlying);
@@ -4897,8 +4898,8 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
48974898
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
48984899
Template = QTN->getUnderlyingTemplate();
48994900

4900-
bool IsTypeAlias =
4901-
isa_and_nonnull<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
4901+
const auto *TD = Template.getAsTemplateDecl();
4902+
bool IsTypeAlias = TD && TD->isTypeAlias();
49024903
QualType CanonType;
49034904
if (!Underlying.isNull())
49044905
CanonType = getCanonicalType(Underlying);

clang/lib/AST/DeclTemplate.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,16 @@ bool TemplateDecl::hasAssociatedConstraints() const {
250250
return false;
251251
}
252252

253+
bool TemplateDecl::isTypeAlias() const {
254+
switch (getKind()) {
255+
case TemplateDecl::TypeAliasTemplate:
256+
case TemplateDecl::BuiltinTemplate:
257+
return true;
258+
default:
259+
return false;
260+
};
261+
}
262+
253263
//===----------------------------------------------------------------------===//
254264
// RedeclarableTemplateDecl Implementation
255265
//===----------------------------------------------------------------------===//

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,10 +1263,11 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
12631263
assert(Ty->isTypeAlias());
12641264
llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit);
12651265

1266-
auto *AliasDecl =
1267-
cast<TypeAliasTemplateDecl>(Ty->getTemplateName().getAsTemplateDecl())
1268-
->getTemplatedDecl();
1266+
const TemplateDecl *TD = Ty->getTemplateName().getAsTemplateDecl();
1267+
if (isa<BuiltinTemplateDecl>(TD))
1268+
return Src;
12691269

1270+
const auto *AliasDecl = cast<TypeAliasTemplateDecl>(TD)->getTemplatedDecl();
12701271
if (AliasDecl->hasAttr<NoDebugAttr>())
12711272
return Src;
12721273

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3501,45 +3501,70 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
35013501
SourceLocation TemplateLoc,
35023502
TemplateArgumentListInfo &TemplateArgs) {
35033503
ASTContext &Context = SemaRef.getASTContext();
3504+
3505+
TemplateParameterList *TPL = BTD->getTemplateParameters();
3506+
3507+
// Wrap the type in substitution sugar.
3508+
auto getSubstType = [&](unsigned IndexReplaced, QualType Replacement) {
3509+
QualType TTP = SemaRef.Context.getTemplateTypeParmType(
3510+
0, IndexReplaced, false,
3511+
cast<TemplateTypeParmDecl>(TPL->getParam(IndexReplaced)));
3512+
return SemaRef.Context.getSubstTemplateTypeParmType(
3513+
cast<TemplateTypeParmType>(TTP), Replacement.getCanonicalType());
3514+
};
3515+
35043516
switch (BTD->getBuiltinTemplateKind()) {
35053517
case BTK__make_integer_seq: {
35063518
// Specializations of __make_integer_seq<S, T, N> are treated like
35073519
// S<T, 0, ..., N-1>.
35083520

3521+
QualType OrigType = Converted[1].getAsType();
35093522
// C++14 [inteseq.intseq]p1:
35103523
// T shall be an integer type.
3511-
if (!Converted[1].getAsType()->isIntegralType(Context)) {
3524+
if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) {
35123525
SemaRef.Diag(TemplateArgs[1].getLocation(),
35133526
diag::err_integer_sequence_integral_element_type);
35143527
return QualType();
35153528
}
35163529

3517-
// C++14 [inteseq.make]p1:
3518-
// If N is negative the program is ill-formed.
35193530
TemplateArgument NumArgsArg = Converted[2];
3520-
llvm::APSInt NumArgs = NumArgsArg.getAsIntegral();
3521-
if (NumArgs < 0) {
3531+
if (NumArgsArg.isDependent())
3532+
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
3533+
Converted);
3534+
3535+
TemplateArgumentListInfo SyntheticTemplateArgs;
3536+
// The type argument, wrapped in substitution sugar, gets reused as the
3537+
// first template argument in the synthetic template argument list.
3538+
QualType SyntheticType = getSubstType(1, OrigType);
3539+
SyntheticTemplateArgs.addArgument(
3540+
TemplateArgumentLoc(TemplateArgument(SyntheticType),
3541+
SemaRef.Context.getTrivialTypeSourceInfo(
3542+
SyntheticType, TemplateArgs[1].getLocation())));
3543+
3544+
if (llvm::APSInt NumArgs = NumArgsArg.getAsIntegral(); NumArgs >= 0) {
3545+
// Expand N into 0 ... N-1.
3546+
for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
3547+
I < NumArgs; ++I) {
3548+
TemplateArgument TA(Context, I, SyntheticType);
3549+
SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
3550+
TA, SyntheticType, TemplateArgs[2].getLocation()));
3551+
}
3552+
} else {
3553+
// C++14 [inteseq.make]p1:
3554+
// If N is negative the program is ill-formed.
35223555
SemaRef.Diag(TemplateArgs[2].getLocation(),
35233556
diag::err_integer_sequence_negative_length);
35243557
return QualType();
35253558
}
35263559

3527-
QualType ArgTy = NumArgsArg.getIntegralType();
3528-
TemplateArgumentListInfo SyntheticTemplateArgs;
3529-
// The type argument gets reused as the first template argument in the
3530-
// synthetic template argument list.
3531-
SyntheticTemplateArgs.addArgument(TemplateArgs[1]);
3532-
// Expand N into 0 ... N-1.
3533-
for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
3534-
I < NumArgs; ++I) {
3535-
TemplateArgument TA(Context, I, ArgTy);
3536-
SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
3537-
TA, ArgTy, TemplateArgs[2].getLocation()));
3538-
}
3560+
// Wrap the template in substitution sugar.
3561+
TemplateName TN = SemaRef.Context.getSubstTemplateTemplateParm(
3562+
cast<TemplateTemplateParmDecl>(TPL->getParam(0)),
3563+
Converted[0].getAsTemplate());
3564+
35393565
// The first template argument will be reused as the template decl that
35403566
// our synthetic template arguments will be applied to.
3541-
return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(),
3542-
TemplateLoc, SyntheticTemplateArgs);
3567+
return SemaRef.CheckTemplateIdType(TN, TemplateLoc, SyntheticTemplateArgs);
35433568
}
35443569

35453570
case BTK__type_pack_element:
@@ -3549,11 +3574,15 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
35493574
assert(Converted.size() == 2 &&
35503575
"__type_pack_element should be given an index and a parameter pack");
35513576

3552-
// If the Index is out of bounds, the program is ill-formed.
35533577
TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
3578+
if (IndexArg.isDependent() || Ts.isDependent())
3579+
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
3580+
Converted);
3581+
35543582
llvm::APSInt Index = IndexArg.getAsIntegral();
35553583
assert(Index >= 0 && "the index used with __type_pack_element should be of "
35563584
"type std::size_t, and hence be non-negative");
3585+
// If the Index is out of bounds, the program is ill-formed.
35573586
if (Index >= Ts.pack_size()) {
35583587
SemaRef.Diag(TemplateArgs[0].getLocation(),
35593588
diag::err_type_pack_element_out_of_bounds);
@@ -3562,7 +3591,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
35623591

35633592
// We simply return the type at index `Index`.
35643593
auto Nth = std::next(Ts.pack_begin(), Index.getExtValue());
3565-
return Nth->getAsType();
3594+
return getSubstType(1, Nth->getAsType());
35663595
}
35673596
llvm_unreachable("unexpected BuiltinTemplateDecl!");
35683597
}
@@ -3730,7 +3759,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
37303759
// We might have a substituted template template parameter pack. If so,
37313760
// build a template specialization type for it.
37323761
if (Name.getAsSubstTemplateTemplateParmPack())
3733-
return Context.getTemplateSpecializationType(Name, TemplateArgs);
3762+
return Context.getTemplateSpecializationType(Name,
3763+
TemplateArgs.arguments());
37343764

37353765
Diag(TemplateLoc, diag::err_template_id_not_a_type)
37363766
<< Name;
@@ -3808,6 +3838,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
38083838

38093839
return QualType();
38103840
}
3841+
} else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
3842+
CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc,
3843+
TemplateArgs);
38113844
} else if (Name.isDependent() ||
38123845
TemplateSpecializationType::anyDependentTemplateArguments(
38133846
TemplateArgs, Converted)) {
@@ -3857,8 +3890,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
38573890
break;
38583891
}
38593892
}
3860-
} else if (ClassTemplateDecl *ClassTemplate
3861-
= dyn_cast<ClassTemplateDecl>(Template)) {
3893+
} else if (ClassTemplateDecl *ClassTemplate =
3894+
dyn_cast<ClassTemplateDecl>(Template)) {
38623895
// Find the class template specialization declaration that
38633896
// corresponds to these arguments.
38643897
void *InsertPos = nullptr;
@@ -3895,15 +3928,15 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
38953928
CanonType = Context.getTypeDeclType(Decl);
38963929
assert(isa<RecordType>(CanonType) &&
38973930
"type of non-dependent specialization is not a RecordType");
3898-
} else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
3899-
CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc,
3900-
TemplateArgs);
3931+
} else {
3932+
llvm_unreachable("Unhandled template kind");
39013933
}
39023934

39033935
// Build the fully-sugared type for this class template
39043936
// specialization, which refers back to the class template
39053937
// specialization we created or found.
3906-
return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
3938+
return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(),
3939+
CanonType);
39073940
}
39083941

39093942
void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName,

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,12 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
563563
// FIXME: Try to preserve type sugar here, which is hard
564564
// because of the unresolved template arguments.
565565
const auto *TP = UP.getCanonicalType()->castAs<TemplateSpecializationType>();
566+
TemplateName TNP = TP->getTemplateName();
567+
568+
// If the parameter is an alias template, there is nothing to deduce.
569+
if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias())
570+
return Sema::TDK_Success;
571+
566572
ArrayRef<TemplateArgument> PResolved = TP->template_arguments();
567573

568574
QualType UA = A;
@@ -574,10 +580,15 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
574580
// FIXME: Should not lose sugar here.
575581
if (const auto *SA =
576582
dyn_cast<TemplateSpecializationType>(UA.getCanonicalType())) {
583+
TemplateName TNA = SA->getTemplateName();
584+
585+
// If the argument is an alias template, there is nothing to deduce.
586+
if (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias())
587+
return Sema::TDK_Success;
588+
577589
// Perform template argument deduction for the template name.
578590
if (auto Result =
579-
DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(),
580-
SA->getTemplateName(), Info, Deduced))
591+
DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, Deduced))
581592
return Result;
582593
// Perform template argument deduction on each template
583594
// argument. Ignore any missing/extra arguments, since they could be

0 commit comments

Comments
 (0)