Skip to content

Commit 4fb33c6

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 fd073a3 commit 4fb33c6

File tree

101 files changed

+642
-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

+642
-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
@@ -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<
@@ -6052,14 +6049,11 @@ def err_template_param_pack_default_arg : Error<
60526049
def err_template_param_pack_must_be_last_template_parameter : Error<
60536050
"template parameter pack must be the last template parameter">;
60546051

6055-
def err_template_parameter_pack_non_pack : Error<
6056-
"%select{template type|non-type template|template template}0 parameter"
6057-
"%select{| pack}1 conflicts with previous %select{template type|"
6058-
"non-type template|template template}0 parameter%select{ pack|}1">;
6059-
def note_template_parameter_pack_non_pack : Note<
6060-
"%select{template type|non-type template|template template}0 parameter"
6061-
"%select{| pack}1 does not match %select{template type|non-type template"
6062-
"|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">;
60636057
def note_template_parameter_pack_here : Note<
60646058
"previous %select{template type|non-type template|template template}0 "
60656059
"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
@@ -12047,7 +12047,7 @@ class Sema final : public SemaBase {
1204712047
bool *ConstraintsNotSatisfied = nullptr);
1204812048

1204912049
bool CheckTemplateTypeArgument(
12050-
TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
12050+
TemplateArgumentLoc &Arg,
1205112051
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1205212052
SmallVectorImpl<TemplateArgument> &CanonicalConverted);
1205312053

@@ -12087,9 +12087,13 @@ class Sema final : public SemaBase {
1208712087
TemplateTemplateParmDecl *Param,
1208812088
const TemplateArgumentLoc &Arg);
1208912089

12090+
/// Print the given named declaration to a string,
12091+
/// using the current PrintingPolicy, except that
12092+
/// TerseOutput will always be set.
12093+
SmallString<128> toTerseString(const NamedDecl &D) const;
12094+
1209012095
void NoteTemplateLocation(const NamedDecl &Decl,
1209112096
std::optional<SourceRange> ParamRange = {});
12092-
void NoteTemplateParameterLocation(const NamedDecl &Decl);
1209312097

1209412098
/// Given a non-type template argument that refers to a
1209512099
/// declaration and the type of its corresponding non-type template
@@ -12204,15 +12208,13 @@ class Sema final : public SemaBase {
1220412208
bool TemplateParameterListsAreEqual(
1220512209
const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
1220612210
const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
12207-
TemplateParameterListEqualKind Kind,
12208-
SourceLocation TemplateArgLoc = SourceLocation());
12211+
TemplateParameterListEqualKind Kind);
1220912212

12210-
bool TemplateParameterListsAreEqual(
12211-
TemplateParameterList *New, TemplateParameterList *Old, bool Complain,
12212-
TemplateParameterListEqualKind Kind,
12213-
SourceLocation TemplateArgLoc = SourceLocation()) {
12213+
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
12214+
TemplateParameterList *Old, bool Complain,
12215+
TemplateParameterListEqualKind Kind) {
1221412216
return TemplateParameterListsAreEqual(nullptr, New, nullptr, Old, Complain,
12215-
Kind, TemplateArgLoc);
12217+
Kind);
1221612218
}
1221712219

1221812220
/// Check whether a template can be declared within this scope.
@@ -13155,6 +13157,11 @@ class Sema final : public SemaBase {
1315513157

1315613158
/// We are performing partial ordering for template template parameters.
1315713159
PartialOrderingTTP,
13160+
13161+
/// We are Checking a Template Parameter, so for any diagnostics which
13162+
/// occur in this scope, we will add a context note which points to this
13163+
/// template parameter.
13164+
CheckTemplateParameter,
1315813165
} Kind;
1315913166

1316013167
/// Was the enclosing context a non-instantiation SFINAE context?
@@ -13390,6 +13397,10 @@ class Sema final : public SemaBase {
1339013397
PartialOrderingTTP, TemplateDecl *PArg,
1339113398
SourceRange InstantiationRange = SourceRange());
1339213399

13400+
struct CheckTemplateParameter {};
13401+
/// \brief Note that we are checking a template parameter.
13402+
InstantiatingTemplate(Sema &SemaRef, CheckTemplateParameter);
13403+
1339313404
/// Note that we have finished instantiating this template.
1339413405
void Clear();
1339513406

@@ -13416,6 +13427,30 @@ class Sema final : public SemaBase {
1341613427
InstantiatingTemplate &operator=(const InstantiatingTemplate &) = delete;
1341713428
};
1341813429

13430+
/// For any diagnostics which occur within its scope, adds a context note
13431+
/// pointing to the declaration of the template parameter.
13432+
struct CheckTemplateParameterRAII : InstantiatingTemplate {
13433+
CheckTemplateParameterRAII(Sema &S, NamedDecl *Param = nullptr)
13434+
: InstantiatingTemplate(S, CheckTemplateParameter()),
13435+
Context(isInvalid() ? nullptr : &S.CodeSynthesisContexts.back()) {
13436+
setParam(Param);
13437+
}
13438+
13439+
void setParam(NamedDecl *Param) {
13440+
assert(!Param || Param->isTemplateParameter());
13441+
if (isInvalid())
13442+
return;
13443+
Context->Entity = Param;
13444+
Context->PointOfInstantiation =
13445+
Param ? Param->getLocation() : SourceLocation();
13446+
Context->InstantiationRange =
13447+
Param ? Param->getSourceRange() : SourceRange();
13448+
}
13449+
13450+
private:
13451+
Sema::CodeSynthesisContext *Context;
13452+
};
13453+
1341913454
bool SubstTemplateArgument(const TemplateArgumentLoc &Input,
1342013455
const MultiLevelTemplateArgumentList &TemplateArgs,
1342113456
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
@@ -7330,7 +7330,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
73307330

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

@@ -7339,9 +7339,8 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
73397339
<< Entity.getDecl()->getDeclName();
73407340
else
73417341
S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
7342-
}
7343-
else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
7344-
Entity.getMethodDecl())
7342+
} else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
7343+
Entity.getMethodDecl())
73457344
S.Diag(Entity.getMethodDecl()->getLocation(),
73467345
diag::note_method_return_type_change)
73477346
<< 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)