Skip to content

Commit 0aa0cc7

Browse files
committed
Reland: [clang] Implement evaluation context for checking template parameters
Instead of manually adding a note pointing to the relevant template parameter to every relevant error, which is very easy to miss, this patch adds a new instantiation context note, so that this can work using RAII magic. This fixes a bunch of places where these notes were missing, and is more future-proof. Some diagnostics are reworked to make better use of this note: - Errors about missing template arguments now refer to the parameter which is missing an argument. - Template Template parameter mismatches now refer to template parameters as parameters instead of arguments. It's likely this will add the note to some diagnostics where the parameter is not super relevant, but this can be reworked with time and the decrease in maintenance burden makes up for it. This bypasses the templight dumper for the new context entry, as the tests are very hard to update. This depends on #125453, which is needed to avoid losing the context note for errors occuring during template argument deduction. Original PR: #126088
1 parent 078e99e commit 0aa0cc7

File tree

104 files changed

+688
-578
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+688
-578
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,11 @@ Improvements to Clang's diagnostics
304304
- Fixed false positives in ``-Waddress-of-packed-member`` diagnostics when
305305
potential misaligned members get processed before they can get discarded.
306306
(#GH144729)
307-
307+
- Clang now more consistently adds a note pointing to the relevant template
308+
parameter. Some diagnostics are reworded to better take advantage of this.
309+
- Template Template Parameter diagnostics now stop referring to template
310+
parameters as template arguments, in some circumstances, better hiding
311+
from the users template template parameter partial ordering arcana.
308312
- Clang now emits dignostic with correct message in case of assigning to const reference captured in lambda. (#GH105647)
309313

310314
- Fixed false positive in ``-Wmissing-noreturn`` diagnostic when it was requiring the usage of

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5358,19 +5358,14 @@ def err_template_linkage : Error<"templates must have C++ linkage">;
53585358
def err_template_typedef : Error<"a typedef cannot be a template">;
53595359
def err_template_unnamed_class : Error<
53605360
"cannot declare a class template with no name">;
5361-
def err_template_param_list_different_arity : Error<
5362-
"%select{too few|too many}0 template parameters in template "
5363-
"%select{|template parameter }1redeclaration">;
5364-
def note_template_param_list_different_arity : Note<
5365-
"%select{too few|too many}0 template parameters in template template "
5366-
"argument">;
5361+
def err_template_param_list_different_arity
5362+
: Error<"%select{too few|too many}0 template parameters in template "
5363+
"%select{|template parameter }1redeclaration">;
53675364
def note_template_prev_declaration : Note<
53685365
"previous template %select{declaration|template parameter}0 is here">;
5369-
def err_template_param_different_kind : Error<
5370-
"template parameter has a different kind in template "
5371-
"%select{|template parameter }0redeclaration">;
5372-
def note_template_param_different_kind : Note<
5373-
"template parameter has a different kind in template argument">;
5366+
def err_template_param_different_kind
5367+
: Error<"template parameter has a different kind in template "
5368+
"%select{|template parameter }0redeclaration">;
53745369

53755370
def err_invalid_decl_specifier_in_nontype_parm : Error<
53765371
"invalid declaration specifier in template non-type parameter">;
@@ -5379,8 +5374,6 @@ def err_template_nontype_parm_different_type : Error<
53795374
"template non-type parameter has a different type %0 in template "
53805375
"%select{|template parameter }1redeclaration">;
53815376

5382-
def note_template_nontype_parm_different_type : Note<
5383-
"template non-type parameter has a different type %0 in template argument">;
53845377
def note_template_nontype_parm_prev_declaration : Note<
53855378
"previous non-type template parameter with type %0 is here">;
53865379
def err_template_nontype_parm_bad_type : Error<
@@ -5454,10 +5447,17 @@ def err_template_missing_args : Error<
54545447
"%select{class template|function template|variable template|alias template|"
54555448
"template template parameter|concept|template}0 %1 requires template "
54565449
"arguments">;
5457-
def err_template_arg_list_different_arity : Error<
5458-
"%select{too few|too many}0 template arguments for "
5459-
"%select{class template|function template|variable template|alias template|"
5460-
"template template parameter|concept|template}1 %2">;
5450+
def err_template_param_missing_arg
5451+
: Error<"missing template argument for template parameter">;
5452+
def err_template_template_param_missing_param
5453+
: Error<"no template parameter in this template template parameter "
5454+
"corresponds to non-defaulted template parameter of argument "
5455+
"template">;
5456+
def err_template_too_many_args
5457+
: Error<"too many template arguments for "
5458+
"%select{class template|function template|variable template|alias "
5459+
"template|"
5460+
"template template parameter|concept|template}0 %1">;
54615461
def note_template_decl_here : Note<"template is declared here">;
54625462
def note_template_decl_external : Note<
54635463
"template declaration from hidden source: %0">;
@@ -5500,12 +5500,9 @@ def err_template_arg_not_valid_template
55005500
def note_template_arg_refers_to_template_here
55015501
: Note<"template argument refers to a %select{function template|class "
55025502
"template|variable template|concept}0 %1, here">;
5503-
def err_template_arg_template_params_mismatch : Error<
5504-
"template template argument has different template parameters than its "
5505-
"corresponding template template parameter">;
5506-
def note_template_arg_template_params_mismatch : Note<
5507-
"template template argument has different template parameters than its "
5508-
"corresponding template template parameter">;
5503+
def note_template_arg_template_params_mismatch
5504+
: Note<"template template argument is incompatible with its "
5505+
"corresponding template template parameter">;
55095506
def err_non_deduced_mismatch : Error<
55105507
"could not match %diff{$ against $|types}0,1">;
55115508
def err_inconsistent_deduction : Error<
@@ -5770,8 +5767,10 @@ def err_template_recursion_depth_exceeded : Error<
57705767
def err_constraint_depends_on_self
57715768
: Error<"satisfaction of constraint %0 depends on itself">,
57725769
NoSFINAE;
5773-
def note_template_recursion_depth : Note<
5774-
"use -ftemplate-depth=N to increase recursive template instantiation depth">;
5770+
def note_template_recursion_depth
5771+
: Note<"use -ftemplate-depth=N to increase recursive template "
5772+
"instantiation depth">,
5773+
NoSFINAE;
57755774

57765775
def err_template_instantiate_within_definition : Error<
57775776
"%select{implicit|explicit}0 instantiation of template %1 within its"
@@ -6050,14 +6049,11 @@ def err_template_param_pack_default_arg : Error<
60506049
def err_template_param_pack_must_be_last_template_parameter : Error<
60516050
"template parameter pack must be the last template parameter">;
60526051

6053-
def err_template_parameter_pack_non_pack : Error<
6054-
"%select{template type|non-type template|template template}0 parameter"
6055-
"%select{| pack}1 conflicts with previous %select{template type|"
6056-
"non-type template|template template}0 parameter%select{ pack|}1">;
6057-
def note_template_parameter_pack_non_pack : Note<
6058-
"%select{template type|non-type template|template template}0 parameter"
6059-
"%select{| pack}1 does not match %select{template type|non-type template"
6060-
"|template template}0 parameter%select{ pack|}1 in template argument">;
6052+
def err_template_parameter_pack_non_pack
6053+
: Error<"%select{template type|non-type template|template template}0 "
6054+
"parameter"
6055+
"%select{| pack}1 conflicts with previous %select{template type|"
6056+
"non-type template|template template}0 parameter%select{ pack|}1">;
60616057
def note_template_parameter_pack_here : Note<
60626058
"previous %select{template type|non-type template|template template}0 "
60636059
"parameter%select{| pack}1 declared here">;

clang/include/clang/Sema/Sema.h

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12026,7 +12026,7 @@ class Sema final : public SemaBase {
1202612026
bool *ConstraintsNotSatisfied = nullptr);
1202712027

1202812028
bool CheckTemplateTypeArgument(
12029-
TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
12029+
TemplateArgumentLoc &Arg,
1203012030
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1203112031
SmallVectorImpl<TemplateArgument> &CanonicalConverted);
1203212032

@@ -12066,9 +12066,13 @@ class Sema final : public SemaBase {
1206612066
TemplateTemplateParmDecl *Param,
1206712067
const TemplateArgumentLoc &Arg);
1206812068

12069+
/// Print the given named declaration to a string,
12070+
/// using the current PrintingPolicy, except that
12071+
/// TerseOutput will always be set.
12072+
SmallString<128> toTerseString(const NamedDecl &D) const;
12073+
1206912074
void NoteTemplateLocation(const NamedDecl &Decl,
1207012075
std::optional<SourceRange> ParamRange = {});
12071-
void NoteTemplateParameterLocation(const NamedDecl &Decl);
1207212076

1207312077
/// Given a non-type template argument that refers to a
1207412078
/// declaration and the type of its corresponding non-type template
@@ -12183,15 +12187,13 @@ class Sema final : public SemaBase {
1218312187
bool TemplateParameterListsAreEqual(
1218412188
const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
1218512189
const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
12186-
TemplateParameterListEqualKind Kind,
12187-
SourceLocation TemplateArgLoc = SourceLocation());
12190+
TemplateParameterListEqualKind Kind);
1218812191

12189-
bool TemplateParameterListsAreEqual(
12190-
TemplateParameterList *New, TemplateParameterList *Old, bool Complain,
12191-
TemplateParameterListEqualKind Kind,
12192-
SourceLocation TemplateArgLoc = SourceLocation()) {
12192+
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
12193+
TemplateParameterList *Old, bool Complain,
12194+
TemplateParameterListEqualKind Kind) {
1219312195
return TemplateParameterListsAreEqual(nullptr, New, nullptr, Old, Complain,
12194-
Kind, TemplateArgLoc);
12196+
Kind);
1219512197
}
1219612198

1219712199
/// Check whether a template can be declared within this scope.
@@ -13088,6 +13090,11 @@ class Sema final : public SemaBase {
1308813090

1308913091
/// We are performing partial ordering for template template parameters.
1309013092
PartialOrderingTTP,
13093+
13094+
/// We are Checking a Template Parameter, so for any diagnostics which
13095+
/// occur in this scope, we will add a context note which points to this
13096+
/// template parameter.
13097+
CheckTemplateParameter,
1309113098
} Kind;
1309213099

1309313100
/// Was the enclosing context a non-instantiation SFINAE context?
@@ -13318,6 +13325,10 @@ class Sema final : public SemaBase {
1331813325
PartialOrderingTTP, TemplateDecl *PArg,
1331913326
SourceRange InstantiationRange = SourceRange());
1332013327

13328+
struct CheckTemplateParameter {};
13329+
/// \brief Note that we are checking a template parameter.
13330+
InstantiatingTemplate(Sema &SemaRef, CheckTemplateParameter);
13331+
1332113332
/// Note that we have finished instantiating this template.
1332213333
void Clear();
1332313334

@@ -13335,8 +13346,6 @@ class Sema final : public SemaBase {
1333513346
Sema &SemaRef;
1333613347
bool Invalid;
1333713348
bool AlreadyInstantiating;
13338-
bool CheckInstantiationDepth(SourceLocation PointOfInstantiation,
13339-
SourceRange InstantiationRange);
1334013349

1334113350
InstantiatingTemplate(Sema &SemaRef,
1334213351
CodeSynthesisContext::SynthesisKind Kind,
@@ -13351,6 +13360,30 @@ class Sema final : public SemaBase {
1335113360
InstantiatingTemplate &operator=(const InstantiatingTemplate &) = delete;
1335213361
};
1335313362

13363+
/// For any diagnostics which occur within its scope, adds a context note
13364+
/// pointing to the declaration of the template parameter.
13365+
struct CheckTemplateParameterRAII : InstantiatingTemplate {
13366+
CheckTemplateParameterRAII(Sema &S, NamedDecl *Param = nullptr)
13367+
: InstantiatingTemplate(S, CheckTemplateParameter()),
13368+
Context(isInvalid() ? nullptr : &S.CodeSynthesisContexts.back()) {
13369+
setParam(Param);
13370+
}
13371+
13372+
void setParam(NamedDecl *Param) {
13373+
assert(!Param || Param->isTemplateParameter());
13374+
if (isInvalid())
13375+
return;
13376+
Context->Entity = Param;
13377+
Context->PointOfInstantiation =
13378+
Param ? Param->getLocation() : SourceLocation();
13379+
Context->InstantiationRange =
13380+
Param ? Param->getSourceRange() : SourceRange();
13381+
}
13382+
13383+
private:
13384+
Sema::CodeSynthesisContext *Context;
13385+
};
13386+
1335413387
bool SubstTemplateArgument(const TemplateArgumentLoc &Input,
1335513388
const MultiLevelTemplateArgumentList &TemplateArgs,
1335613389
TemplateArgumentLoc &Output,
@@ -13529,7 +13562,7 @@ class Sema final : public SemaBase {
1352913562
~ArgPackSubstIndexRAII() { Self.ArgPackSubstIndex = OldSubstIndex; }
1353013563
};
1353113564

13532-
void pushCodeSynthesisContext(CodeSynthesisContext Ctx);
13565+
bool pushCodeSynthesisContext(CodeSynthesisContext Ctx);
1353313566
void popCodeSynthesisContext();
1353413567

1353513568
void PrintContextStack(InstantiationContextDiagFuncRef DiagFunc) {

clang/lib/Frontend/FrontendActions.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,8 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
418418
}
419419

420420
private:
421-
static std::string toString(CodeSynthesisContext::SynthesisKind Kind) {
421+
static std::optional<std::string>
422+
toString(CodeSynthesisContext::SynthesisKind Kind) {
422423
switch (Kind) {
423424
case CodeSynthesisContext::TemplateInstantiation:
424425
return "TemplateInstantiation";
@@ -476,21 +477,25 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
476477
return "TypeAliasTemplateInstantiation";
477478
case CodeSynthesisContext::PartialOrderingTTP:
478479
return "PartialOrderingTTP";
480+
case CodeSynthesisContext::CheckTemplateParameter:
481+
return std::nullopt;
479482
}
480-
return "";
483+
return std::nullopt;
481484
}
482485

483486
template <bool BeginInstantiation>
484487
static void displayTemplightEntry(llvm::raw_ostream &Out, const Sema &TheSema,
485488
const CodeSynthesisContext &Inst) {
486489
std::string YAML;
487490
{
491+
std::optional<TemplightEntry> Entry =
492+
getTemplightEntry<BeginInstantiation>(TheSema, Inst);
493+
if (!Entry)
494+
return;
488495
llvm::raw_string_ostream OS(YAML);
489496
llvm::yaml::Output YO(OS);
490-
TemplightEntry Entry =
491-
getTemplightEntry<BeginInstantiation>(TheSema, Inst);
492497
llvm::yaml::EmptyContext Context;
493-
llvm::yaml::yamlize(YO, Entry, true, Context);
498+
llvm::yaml::yamlize(YO, *Entry, true, Context);
494499
}
495500
Out << "---" << YAML << "\n";
496501
}
@@ -570,10 +575,13 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
570575
}
571576

572577
template <bool BeginInstantiation>
573-
static TemplightEntry getTemplightEntry(const Sema &TheSema,
574-
const CodeSynthesisContext &Inst) {
578+
static std::optional<TemplightEntry>
579+
getTemplightEntry(const Sema &TheSema, const CodeSynthesisContext &Inst) {
575580
TemplightEntry Entry;
576-
Entry.Kind = toString(Inst.Kind);
581+
std::optional<std::string> Kind = toString(Inst.Kind);
582+
if (!Kind)
583+
return std::nullopt;
584+
Entry.Kind = *Kind;
577585
Entry.Event = BeginInstantiation ? "Begin" : "End";
578586
llvm::raw_string_ostream OS(Entry.Name);
579587
printEntryName(TheSema, Inst.Entity, OS);

clang/lib/Sema/SemaInit.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7342,7 +7342,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
73427342

73437343
void InitializationSequence::PrintInitLocationNote(Sema &S,
73447344
const InitializedEntity &Entity) {
7345-
if (Entity.isParamOrTemplateParamKind() && Entity.getDecl()) {
7345+
if (Entity.isParameterKind() && Entity.getDecl()) {
73467346
if (Entity.getDecl()->getLocation().isInvalid())
73477347
return;
73487348

@@ -7351,9 +7351,8 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
73517351
<< Entity.getDecl()->getDeclName();
73527352
else
73537353
S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
7354-
}
7355-
else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
7356-
Entity.getMethodDecl())
7354+
} else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
7355+
Entity.getMethodDecl())
73577356
S.Diag(Entity.getMethodDecl()->getLocation(),
73587357
diag::note_method_return_type_change)
73597358
<< Entity.getMethodDecl()->getDeclName();

clang/lib/Sema/SemaLambda.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,13 +1525,16 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
15251525
TemplateParameterList *TemplateParams =
15261526
getGenericLambdaTemplateParameterList(LSI, *this);
15271527
if (TemplateParams) {
1528-
for (const auto *TP : TemplateParams->asArray()) {
1528+
CheckTemplateParameterRAII CTP(*this);
1529+
for (auto *TP : TemplateParams->asArray()) {
15291530
if (!TP->getIdentifier())
15301531
continue;
1532+
CTP.setParam(TP);
15311533
for (const auto &Capture : Intro.Captures) {
15321534
if (Capture.Id == TP->getIdentifier()) {
15331535
Diag(Capture.Loc, diag::err_template_param_shadow) << Capture.Id;
1534-
NoteTemplateParameterLocation(*TP);
1536+
// forget we already emitted this stack.
1537+
LastEmittedCodeSynthesisContextDepth = 0;
15351538
}
15361539
}
15371540
}

clang/lib/Sema/SemaLookup.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,9 +1613,13 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
16131613
unsigned N = CodeSynthesisContexts.size();
16141614
for (unsigned I = CodeSynthesisContextLookupModules.size();
16151615
I != N; ++I) {
1616-
Module *M = CodeSynthesisContexts[I].Entity ?
1617-
getDefiningModule(*this, CodeSynthesisContexts[I].Entity) :
1618-
nullptr;
1616+
auto &Ctx = CodeSynthesisContexts[I];
1617+
// FIXME: Are there any other context kinds that shouldn't be looked at
1618+
// here?
1619+
if (Ctx.Kind == CodeSynthesisContext::PartialOrderingTTP ||
1620+
Ctx.Kind == CodeSynthesisContext::CheckTemplateParameter)
1621+
continue;
1622+
Module *M = Ctx.Entity ? getDefiningModule(*this, Ctx.Entity) : nullptr;
16191623
if (M && !LookupModulesCache.insert(M).second)
16201624
M = nullptr;
16211625
CodeSynthesisContextLookupModules.push_back(M);
@@ -3738,7 +3742,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
37383742
TemplateParameterList *Params = FD->getTemplateParameters();
37393743
if (Params->size() == 1) {
37403744
IsTemplate = true;
3741-
if (!Params->getParam(0)->isTemplateParameterPack() && !StringLit) {
3745+
NamedDecl *Param = Params->getParam(0);
3746+
if (!Param->isTemplateParameterPack() && !StringLit) {
37423747
// Implied but not stated: user-defined integer and floating literals
37433748
// only ever use numeric literal operator templates, not templates
37443749
// taking a parameter of class type.
@@ -3751,6 +3756,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
37513756
if (StringLit) {
37523757
SFINAETrap Trap(*this);
37533758
CheckTemplateArgumentInfo CTAI;
3759+
CheckTemplateParameterRAII CTP(*this, Param);
37543760
TemplateArgumentLoc Arg(
37553761
TemplateArgument(StringLit, /*IsCanonical=*/false), StringLit);
37563762
if (CheckTemplateArgument(

0 commit comments

Comments
 (0)