Skip to content

Commit 80dd859

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 llvm#125453, which is needed to avoid losing the context note for errors occuring during template argument deduction. Original PR: llvm#126088
1 parent 5b3fba3 commit 80dd859

File tree

101 files changed

+641
-528
lines changed

Some content is hidden

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

101 files changed

+641
-528
lines changed

clang/docs/ReleaseNotes.rst

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

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

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5361,19 +5361,14 @@ def err_template_linkage : Error<"templates must have C++ linkage">;
53615361
def err_template_typedef : Error<"a typedef cannot be a template">;
53625362
def err_template_unnamed_class : Error<
53635363
"cannot declare a class template with no name">;
5364-
def err_template_param_list_different_arity : Error<
5365-
"%select{too few|too many}0 template parameters in template "
5366-
"%select{|template parameter }1redeclaration">;
5367-
def note_template_param_list_different_arity : Note<
5368-
"%select{too few|too many}0 template parameters in template template "
5369-
"argument">;
5364+
def err_template_param_list_different_arity
5365+
: Error<"%select{too few|too many}0 template parameters in template "
5366+
"%select{|template parameter }1redeclaration">;
53705367
def note_template_prev_declaration : Note<
53715368
"previous template %select{declaration|template parameter}0 is here">;
5372-
def err_template_param_different_kind : Error<
5373-
"template parameter has a different kind in template "
5374-
"%select{|template parameter }0redeclaration">;
5375-
def note_template_param_different_kind : Note<
5376-
"template parameter has a different kind in template argument">;
5369+
def err_template_param_different_kind
5370+
: Error<"template parameter has a different kind in template "
5371+
"%select{|template parameter }0redeclaration">;
53775372

53785373
def err_invalid_decl_specifier_in_nontype_parm : Error<
53795374
"invalid declaration specifier in template non-type parameter">;
@@ -5382,8 +5377,6 @@ def err_template_nontype_parm_different_type : Error<
53825377
"template non-type parameter has a different type %0 in template "
53835378
"%select{|template parameter }1redeclaration">;
53845379

5385-
def note_template_nontype_parm_different_type : Note<
5386-
"template non-type parameter has a different type %0 in template argument">;
53875380
def note_template_nontype_parm_prev_declaration : Note<
53885381
"previous non-type template parameter with type %0 is here">;
53895382
def err_template_nontype_parm_bad_type : Error<
@@ -5457,10 +5450,17 @@ def err_template_missing_args : Error<
54575450
"%select{class template|function template|variable template|alias template|"
54585451
"template template parameter|concept|template}0 %1 requires template "
54595452
"arguments">;
5460-
def err_template_arg_list_different_arity : Error<
5461-
"%select{too few|too many}0 template arguments for "
5462-
"%select{class template|function template|variable template|alias template|"
5463-
"template template parameter|concept|template}1 %2">;
5453+
def err_template_param_missing_arg
5454+
: Error<"missing template argument for template parameter">;
5455+
def err_template_template_param_missing_param
5456+
: Error<"no template parameter in this template template parameter "
5457+
"corresponds to non-defaulted template parameter of argument "
5458+
"template">;
5459+
def err_template_too_many_args
5460+
: Error<"too many template arguments for "
5461+
"%select{class template|function template|variable template|alias "
5462+
"template|"
5463+
"template template parameter|concept|template}0 %1">;
54645464
def note_template_decl_here : Note<"template is declared here">;
54655465
def note_template_decl_external : Note<
54665466
"template declaration from hidden source: %0">;
@@ -5503,12 +5503,9 @@ def err_template_arg_not_valid_template
55035503
def note_template_arg_refers_to_template_here
55045504
: Note<"template argument refers to a %select{function template|class "
55055505
"template|variable template|concept}0 %1, here">;
5506-
def err_template_arg_template_params_mismatch : Error<
5507-
"template template argument has different template parameters than its "
5508-
"corresponding template template parameter">;
5509-
def note_template_arg_template_params_mismatch : Note<
5510-
"template template argument has different template parameters than its "
5511-
"corresponding template template parameter">;
5506+
def note_template_arg_template_params_mismatch
5507+
: Note<"template template argument is incompatible with its "
5508+
"corresponding template template parameter">;
55125509
def err_non_deduced_mismatch : Error<
55135510
"could not match %diff{$ against $|types}0,1">;
55145511
def err_inconsistent_deduction : Error<
@@ -6055,14 +6052,11 @@ def err_template_param_pack_default_arg : Error<
60556052
def err_template_param_pack_must_be_last_template_parameter : Error<
60566053
"template parameter pack must be the last template parameter">;
60576054

6058-
def err_template_parameter_pack_non_pack : Error<
6059-
"%select{template type|non-type template|template template}0 parameter"
6060-
"%select{| pack}1 conflicts with previous %select{template type|"
6061-
"non-type template|template template}0 parameter%select{ pack|}1">;
6062-
def note_template_parameter_pack_non_pack : Note<
6063-
"%select{template type|non-type template|template template}0 parameter"
6064-
"%select{| pack}1 does not match %select{template type|non-type template"
6065-
"|template template}0 parameter%select{ pack|}1 in template argument">;
6055+
def err_template_parameter_pack_non_pack
6056+
: Error<"%select{template type|non-type template|template template}0 "
6057+
"parameter"
6058+
"%select{| pack}1 conflicts with previous %select{template type|"
6059+
"non-type template|template template}0 parameter%select{ pack|}1">;
60666060
def note_template_parameter_pack_here : Note<
60676061
"previous %select{template type|non-type template|template template}0 "
60686062
"parameter%select{| pack}1 declared here">;

clang/include/clang/Sema/Sema.h

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12040,7 +12040,7 @@ class Sema final : public SemaBase {
1204012040
bool *ConstraintsNotSatisfied = nullptr);
1204112041

1204212042
bool CheckTemplateTypeArgument(
12043-
TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
12043+
TemplateArgumentLoc &Arg,
1204412044
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1204512045
SmallVectorImpl<TemplateArgument> &CanonicalConverted);
1204612046

@@ -12080,9 +12080,13 @@ class Sema final : public SemaBase {
1208012080
TemplateTemplateParmDecl *Param,
1208112081
const TemplateArgumentLoc &Arg);
1208212082

12083+
/// Print the given named declaration to a string,
12084+
/// using the current PrintingPolicy, except that
12085+
/// TerseOutput will always be set.
12086+
SmallString<128> toTerseString(const NamedDecl &D) const;
12087+
1208312088
void NoteTemplateLocation(const NamedDecl &Decl,
1208412089
std::optional<SourceRange> ParamRange = {});
12085-
void NoteTemplateParameterLocation(const NamedDecl &Decl);
1208612090

1208712091
/// Given a non-type template argument that refers to a
1208812092
/// declaration and the type of its corresponding non-type template
@@ -12197,15 +12201,13 @@ class Sema final : public SemaBase {
1219712201
bool TemplateParameterListsAreEqual(
1219812202
const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
1219912203
const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
12200-
TemplateParameterListEqualKind Kind,
12201-
SourceLocation TemplateArgLoc = SourceLocation());
12204+
TemplateParameterListEqualKind Kind);
1220212205

12203-
bool TemplateParameterListsAreEqual(
12204-
TemplateParameterList *New, TemplateParameterList *Old, bool Complain,
12205-
TemplateParameterListEqualKind Kind,
12206-
SourceLocation TemplateArgLoc = SourceLocation()) {
12206+
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
12207+
TemplateParameterList *Old, bool Complain,
12208+
TemplateParameterListEqualKind Kind) {
1220712209
return TemplateParameterListsAreEqual(nullptr, New, nullptr, Old, Complain,
12208-
Kind, TemplateArgLoc);
12210+
Kind);
1220912211
}
1221012212

1221112213
/// Check whether a template can be declared within this scope.
@@ -13168,6 +13170,11 @@ class Sema final : public SemaBase {
1316813170

1316913171
/// We are performing partial ordering for template template parameters.
1317013172
PartialOrderingTTP,
13173+
13174+
/// We are Checking a Template Parameter, so for any diagnostics which
13175+
/// occur in this scope, we will add a context note which points to this
13176+
/// template parameter.
13177+
CheckTemplateParameter,
1317113178
} Kind;
1317213179

1317313180
/// Whether we're substituting into constraints.
@@ -13386,6 +13393,10 @@ class Sema final : public SemaBase {
1338613393
PartialOrderingTTP, TemplateDecl *PArg,
1338713394
SourceRange InstantiationRange = SourceRange());
1338813395

13396+
struct CheckTemplateParameter {};
13397+
/// \brief Note that we are checking a template parameter.
13398+
InstantiatingTemplate(Sema &SemaRef, CheckTemplateParameter);
13399+
1338913400
/// Note that we have finished instantiating this template.
1339013401
void Clear();
1339113402

@@ -13411,6 +13422,30 @@ class Sema final : public SemaBase {
1341113422
InstantiatingTemplate &operator=(const InstantiatingTemplate &) = delete;
1341213423
};
1341313424

13425+
/// For any diagnostics which occur within its scope, adds a context note
13426+
/// pointing to the declaration of the template parameter.
13427+
struct CheckTemplateParameterRAII : InstantiatingTemplate {
13428+
CheckTemplateParameterRAII(Sema &S, NamedDecl *Param = nullptr)
13429+
: InstantiatingTemplate(S, CheckTemplateParameter()),
13430+
Context(isInvalid() ? nullptr : &S.CodeSynthesisContexts.back()) {
13431+
setParam(Param);
13432+
}
13433+
13434+
void setParam(NamedDecl *Param) {
13435+
assert(!Param || Param->isTemplateParameter());
13436+
if (isInvalid())
13437+
return;
13438+
Context->Entity = Param;
13439+
Context->PointOfInstantiation =
13440+
Param ? Param->getLocation() : SourceLocation();
13441+
Context->InstantiationRange =
13442+
Param ? Param->getSourceRange() : SourceRange();
13443+
}
13444+
13445+
private:
13446+
Sema::CodeSynthesisContext *Context;
13447+
};
13448+
1341413449
bool SubstTemplateArgument(const TemplateArgumentLoc &Input,
1341513450
const MultiLevelTemplateArgumentList &TemplateArgs,
1341613451
TemplateArgumentLoc &Output,

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
@@ -7331,7 +7331,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
73317331

73327332
void InitializationSequence::PrintInitLocationNote(Sema &S,
73337333
const InitializedEntity &Entity) {
7334-
if (Entity.isParamOrTemplateParamKind() && Entity.getDecl()) {
7334+
if (Entity.isParameterKind() && Entity.getDecl()) {
73357335
if (Entity.getDecl()->getLocation().isInvalid())
73367336
return;
73377337

@@ -7340,9 +7340,8 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
73407340
<< Entity.getDecl()->getDeclName();
73417341
else
73427342
S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
7343-
}
7344-
else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
7345-
Entity.getMethodDecl())
7343+
} else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
7344+
Entity.getMethodDecl())
73467345
S.Diag(Entity.getMethodDecl()->getLocation(),
73477346
diag::note_method_return_type_change)
73487347
<< 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);
@@ -3735,7 +3739,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
37353739
TemplateParameterList *Params = FD->getTemplateParameters();
37363740
if (Params->size() == 1) {
37373741
IsTemplate = true;
3738-
if (!Params->getParam(0)->isTemplateParameterPack() && !StringLit) {
3742+
NamedDecl *Param = Params->getParam(0);
3743+
if (!Param->isTemplateParameterPack() && !StringLit) {
37393744
// Implied but not stated: user-defined integer and floating literals
37403745
// only ever use numeric literal operator templates, not templates
37413746
// taking a parameter of class type.
@@ -3748,6 +3753,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
37483753
if (StringLit) {
37493754
SFINAETrap Trap(*this);
37503755
CheckTemplateArgumentInfo CTAI;
3756+
CheckTemplateParameterRAII CTP(*this, Param);
37513757
TemplateArgumentLoc Arg(
37523758
TemplateArgument(StringLit, /*IsCanonical=*/false), StringLit);
37533759
if (CheckTemplateArgument(

0 commit comments

Comments
 (0)