Skip to content

Commit

Permalink
[clang] Instantiate NTTPs and template default arguments with sugar
Browse files Browse the repository at this point in the history
This makes use of the changes introduced in D134604, in order to
instantiate non-type template parameters and default template arguments
with a final sugared substitution.

This comes at no additional relevant cost.
Since we don't track / unique them in specializations, we wouldn't be
able to resugar them later anyway.

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

Differential Revision: https://reviews.llvm.org/D136564
  • Loading branch information
mizvekov committed Oct 26, 2022
1 parent c4c2a3c commit 2560c12
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 100 deletions.
13 changes: 5 additions & 8 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -8199,14 +8199,11 @@ class Sema final {
SourceLocation TemplateLoc,
Declarator &D);

TemplateArgumentLoc
SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
Decl *Param,
SmallVectorImpl<TemplateArgument>
&Converted,
bool &HasDefaultArg);
TemplateArgumentLoc SubstDefaultTemplateArgumentIfAvailable(
TemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation RAngleLoc, Decl *Param,
ArrayRef<TemplateArgument> SugaredConverted,
ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg);

/// Specifies the context in which a particular template
/// argument is being checked.
Expand Down
120 changes: 53 additions & 67 deletions clang/lib/Sema/SemaTemplate.cpp
Expand Up @@ -5261,27 +5261,25 @@ bool Sema::CheckTemplateTypeArgument(
/// \param Converted the list of template arguments provided for template
/// parameters that precede \p Param in the template parameter list.
/// \returns the substituted template argument, or NULL if an error occurred.
static TypeSourceInfo *
SubstDefaultTemplateArgument(Sema &SemaRef,
TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
TemplateTypeParmDecl *Param,
SmallVectorImpl<TemplateArgument> &Converted) {
static TypeSourceInfo *SubstDefaultTemplateArgument(
Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation RAngleLoc, TemplateTypeParmDecl *Param,
ArrayRef<TemplateArgument> SugaredConverted,
ArrayRef<TemplateArgument> CanonicalConverted) {
TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo();

// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
if (ArgType->getType()->isInstantiationDependentType()) {
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
Param, Template, Converted,
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template,
SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return nullptr;

// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists(Template, Converted,
/*Final=*/false);
MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
/*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
TemplateArgLists.addOuterTemplateArguments(None);

Expand Down Expand Up @@ -5320,22 +5318,20 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// parameters that precede \p Param in the template parameter list.
///
/// \returns the substituted template argument, or NULL if an error occurred.
static ExprResult
SubstDefaultTemplateArgument(Sema &SemaRef,
TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
NonTypeTemplateParmDecl *Param,
SmallVectorImpl<TemplateArgument> &Converted) {
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
Param, Template, Converted,
static ExprResult SubstDefaultTemplateArgument(
Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param,
ArrayRef<TemplateArgument> SugaredConverted,
ArrayRef<TemplateArgument> CanonicalConverted) {
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template,
SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return ExprError();

// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists(Template, Converted,
/*Final=*/false);
MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
/*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
TemplateArgLists.addOuterTemplateArguments(None);

Expand Down Expand Up @@ -5370,23 +5366,21 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// source-location information) that precedes the template name.
///
/// \returns the substituted template argument, or NULL if an error occurred.
static TemplateName
SubstDefaultTemplateArgument(Sema &SemaRef,
TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
TemplateTemplateParmDecl *Param,
SmallVectorImpl<TemplateArgument> &Converted,
NestedNameSpecifierLoc &QualifierLoc) {
static TemplateName SubstDefaultTemplateArgument(
Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param,
ArrayRef<TemplateArgument> SugaredConverted,
ArrayRef<TemplateArgument> CanonicalConverted,
NestedNameSpecifierLoc &QualifierLoc) {
Sema::InstantiatingTemplate Inst(
SemaRef, TemplateLoc, TemplateParameter(Param), Template, Converted,
SourceRange(TemplateLoc, RAngleLoc));
SemaRef, TemplateLoc, TemplateParameter(Param), Template,
SugaredConverted, SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return TemplateName();

// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists(Template, Converted,
/*Final=*/false);
MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
/*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
TemplateArgLists.addOuterTemplateArguments(None);

Expand All @@ -5410,26 +5404,21 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// If the given template parameter has a default template
/// argument, substitute into that default template argument and
/// return the corresponding template argument.
TemplateArgumentLoc
Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation RAngleLoc,
Decl *Param,
SmallVectorImpl<TemplateArgument>
&Converted,
bool &HasDefaultArg) {
TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable(
TemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation RAngleLoc, Decl *Param,
ArrayRef<TemplateArgument> SugaredConverted,
ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg) {
HasDefaultArg = false;

if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (!hasReachableDefaultArgument(TypeParm))
return TemplateArgumentLoc();

HasDefaultArg = true;
TypeSourceInfo *DI = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
RAngleLoc,
TypeParm,
Converted);
TypeSourceInfo *DI = SubstDefaultTemplateArgument(
*this, Template, TemplateLoc, RAngleLoc, TypeParm, SugaredConverted,
CanonicalConverted);
if (DI)
return TemplateArgumentLoc(TemplateArgument(DI->getType()), DI);

Expand All @@ -5442,11 +5431,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
return TemplateArgumentLoc();

HasDefaultArg = true;
ExprResult Arg = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
RAngleLoc,
NonTypeParm,
Converted);
ExprResult Arg = SubstDefaultTemplateArgument(
*this, Template, TemplateLoc, RAngleLoc, NonTypeParm, SugaredConverted,
CanonicalConverted);
if (Arg.isInvalid())
return TemplateArgumentLoc();

Expand All @@ -5461,12 +5448,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,

HasDefaultArg = true;
NestedNameSpecifierLoc QualifierLoc;
TemplateName TName = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
RAngleLoc,
TempTempParm,
Converted,
QualifierLoc);
TemplateName TName = SubstDefaultTemplateArgument(
*this, Template, TemplateLoc, RAngleLoc, TempTempParm, SugaredConverted,
CanonicalConverted, QualifierLoc);
if (TName.isNull())
return TemplateArgumentLoc();

Expand Down Expand Up @@ -5562,13 +5546,13 @@ bool Sema::CheckTemplateArgument(
!Template->getDeclContext()->isDependentContext()) {
// Do substitution on the type of the non-type template parameter.
InstantiatingTemplate Inst(*this, TemplateLoc, Template, NTTP,
CanonicalConverted,
SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;

MultiLevelTemplateArgumentList MLTAL(Template, CanonicalConverted,
/*Final=*/false);
MultiLevelTemplateArgumentList MLTAL(Template, SugaredConverted,
/*Final=*/true);
// If the parameter is a pack expansion, expand this slice of the pack.
if (auto *PET = NTTPType->getAs<PackExpansionType>()) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this,
Expand Down Expand Up @@ -5733,7 +5717,7 @@ bool Sema::CheckTemplateArgument(
Params =
SubstTemplateParams(Params, CurContext,
MultiLevelTemplateArgumentList(
Template, CanonicalConverted, /*Final=*/false));
Template, SugaredConverted, /*Final=*/true));
if (!Params)
return true;
}
Expand Down Expand Up @@ -6012,7 +5996,8 @@ bool Sema::CheckTemplateArgumentList(
NewArgs);

TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(
*this, Template, TemplateLoc, RAngleLoc, TTP, CanonicalConverted);
*this, Template, TemplateLoc, RAngleLoc, TTP, SugaredConverted,
CanonicalConverted);
if (!ArgType)
return true;

Expand All @@ -6025,7 +6010,8 @@ bool Sema::CheckTemplateArgumentList(
NewArgs);

ExprResult E = SubstDefaultTemplateArgument(
*this, Template, TemplateLoc, RAngleLoc, NTTP, CanonicalConverted);
*this, Template, TemplateLoc, RAngleLoc, NTTP, SugaredConverted,
CanonicalConverted);
if (E.isInvalid())
return true;

Expand All @@ -6041,8 +6027,8 @@ bool Sema::CheckTemplateArgumentList(

NestedNameSpecifierLoc QualifierLoc;
TemplateName Name = SubstDefaultTemplateArgument(
*this, Template, TemplateLoc, RAngleLoc, TempParm, CanonicalConverted,
QualifierLoc);
*this, Template, TemplateLoc, RAngleLoc, TempParm, SugaredConverted,
CanonicalConverted, QualifierLoc);
if (Name.isNull())
return true;

Expand All @@ -6056,7 +6042,7 @@ bool Sema::CheckTemplateArgumentList(
// template here, we just create this object to put a note into the
// context stack.
InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param,
CanonicalConverted,
SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;
Expand Down
21 changes: 10 additions & 11 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Expand Up @@ -2687,20 +2687,20 @@ static bool ConvertDeducedTemplateArgument(
// itself, in case that substitution fails.
if (SugaredPackedArgsBuilder.empty()) {
LocalInstantiationScope Scope(S);
MultiLevelTemplateArgumentList Args(Template, CanonicalOutput,
/*Final=*/false);
MultiLevelTemplateArgumentList Args(Template, SugaredOutput,
/*Final=*/true);

if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
NTTP, CanonicalOutput,
NTTP, SugaredOutput,
Template->getSourceRange());
if (Inst.isInvalid() ||
S.SubstType(NTTP->getType(), Args, NTTP->getLocation(),
NTTP->getDeclName()).isNull())
return true;
} else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) {
Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
TTP, CanonicalOutput,
TTP, SugaredOutput,
Template->getSourceRange());
if (Inst.isInvalid() || !S.SubstDecl(TTP, S.CurContext, Args))
return true;
Expand Down Expand Up @@ -2810,7 +2810,7 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(

DefArg = S.SubstDefaultTemplateArgumentIfAvailable(
TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param,
CanonicalBuilder, HasDefaultArg);
SugaredBuilder, CanonicalBuilder, HasDefaultArg);
}

// If there was no default argument, deduction is incomplete.
Expand Down Expand Up @@ -2960,10 +2960,9 @@ FinishTemplateArgumentDeduction(
PartialTemplArgInfo->RAngleLoc);

if (S.SubstTemplateArguments(PartialTemplArgInfo->arguments(),
MultiLevelTemplateArgumentList(
Partial,
CanonicalDeducedArgumentList->asArray(),
/*Final=*/false),
MultiLevelTemplateArgumentList(Partial,
SugaredBuilder,
/*Final=*/true),
InstArgs)) {
unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx;
if (ParamIdx >= Partial->getTemplateParameters()->size())
Expand Down Expand Up @@ -3303,8 +3302,8 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments(
ExtParameterInfoBuilder ExtParamInfos;

MultiLevelTemplateArgumentList MLTAL(FunctionTemplate,
CanonicalExplicitArgumentList->asArray(),
/*Final=*/false);
SugaredExplicitArgumentList->asArray(),
/*Final=*/true);

// Instantiate the types of each of the function parameters given the
// explicitly-specified template arguments. If the function has a trailing
Expand Down
8 changes: 3 additions & 5 deletions clang/test/AST/ast-dump-template-decls.cpp
Expand Up @@ -172,11 +172,9 @@ using test1 = D<E, int>;
// CHECK: TypeAliasDecl 0x{{[^ ]*}} <line:{{[1-9]+}}:1, col:23> col:7 test1 'D<subst_default_argument::E, int>':'subst_default_argument::E<int, subst_default_argument::A<int>>'
// CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'A<int>' sugar A
// CHECK-NEXT: |-TemplateArgument type 'int':'int'
// CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar class depth 0 index 0 E1
// CHECK-NEXT: | |-ClassTemplate 0x{{[^ ]*}} 'E'
// CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar class depth 0 index 1 D2
// CHECK-NEXT: | |-TypeAliasTemplate 0x{{[^ ]*}} 'D'
// CHECK-NEXT: | `-BuiltinType 0x{{[^ ]*}} 'int'
// CHECK-NEXT: | `-SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar class depth 0 index 1 D2
// CHECK-NEXT: | |-TypeAliasTemplate 0x{{[^ ]*}} 'D'
// CHECK-NEXT: | `-BuiltinType 0x{{[^ ]*}} 'int'
// CHECK-NEXT: `-RecordType 0x{{[^ ]*}} 'subst_default_argument::A<int>'
// CHECK-NEXT: `-ClassTemplateSpecialization 0x{{[^ ]*}} 'A'
} // namespace subst_default_argument
4 changes: 2 additions & 2 deletions clang/test/CXX/drs/dr3xx.cpp
Expand Up @@ -924,9 +924,9 @@ namespace dr367 { // dr367: yes
namespace dr368 { // dr368: yes
template<typename T, T> struct S {}; // expected-note {{here}}
template<typename T> int f(S<T, T()> *); // expected-error {{function type}}
template<typename T> int g(S<T, (T())> *); // cxx98_17-note {{type 'dr368::X'}}
template<typename T> int g(S<T, (T())> *); // cxx98_17-note {{type 'X'}}
// cxx20_2b-note@-1 {{candidate function [with T = dr368::X]}}
template<typename T> int g(S<T, true ? T() : T()> *); // cxx98_17-note {{type 'dr368::X'}}
template<typename T> int g(S<T, true ? T() : T()> *); // cxx98_17-note {{type 'X'}}
// cxx20_2b-note@-1 {{candidate function [with T = dr368::X]}}
struct X {};
int n = g<X>(0); // cxx98_17-error {{no matching}}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/expr/expr.const/p3-0x.cpp
Expand Up @@ -88,7 +88,7 @@ void noexcept_true() noexcept(true);
Val<decltype(&noexcept_false), &noexcept_true> remove_noexcept;
Val<decltype(&noexcept_true), &noexcept_false> add_noexcept;
#if __cplusplus > 201402L
// expected-error@-2 {{value of type 'void (*)() noexcept(false)' is not implicitly convertible to 'void (*)() noexcept'}}
// expected-error@-2 {{value of type 'void (*)() noexcept(false)' is not implicitly convertible to 'decltype(&noexcept_true)' (aka 'void (*)() noexcept(true)')}}
#endif

// (no other conversions are permitted)
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Misc/diag-template-diffing.cpp
Expand Up @@ -1454,7 +1454,7 @@ void run() {
D<X::X1>(VectorType<X::X2>());
}
// CHECK-ELIDE-NOTREE: error: no matching function for call to 'D'
// CHECK-ELIDE-NOTREE: note: candidate function template not viable: no known conversion from 'VectorType<X::X2>' to 'const VectorType<(TypeAlias::X)0>' for 1st argument
// CHECK-ELIDE-NOTREE: note: candidate function template not viable: no known conversion from 'VectorType<X::X2>' to 'const VectorType<(X)0>' for 1st argument
}

namespace TypeAlias2 {
Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaTemplate/instantiation-default-1.cpp
Expand Up @@ -33,7 +33,7 @@ void test_Def2(Def2<int, int const*> *d2) {
}

typedef int& int_ref_t;
Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int &>' required here}}
Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int_ref_t>' required here}}


template<> struct Def1<const int> { }; // expected-error{{redefinition of 'Def1<const int>'}}
Expand Down

0 comments on commit 2560c12

Please sign in to comment.