Skip to content

Commit 32717ea

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 773e88f commit 32717ea

File tree

97 files changed

+633
-560
lines changed

Some content is hidden

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

97 files changed

+633
-560
lines changed

clang/docs/ReleaseNotes.rst

+10
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,16 @@ Bug Fixes to C++ Support
300300
not in the last position.
301301
- Clang now correctly parses ``if constexpr`` expressions in immediate function context. (#GH123524)
302302

303+
Improvements to C++ diagnostics
304+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
305+
306+
- Clang now more consistently adds a note pointing to the relevant template
307+
parameter. Some diagnostics are reworded to better take advantage of this.
308+
- Template Template Parameter diagnostics now stop referring to template
309+
parameters as template arguments, in some circumstances, better hiding
310+
from the users template template parameter partial ordering arcana.
311+
312+
303313
Bug Fixes to AST Handling
304314
^^^^^^^^^^^^^^^^^^^^^^^^^
305315
- Fixed type checking when a statement expression ends in an l-value of atomic type. (#GH106576)

clang/include/clang/Basic/DiagnosticSemaKinds.td

+9-18
Original file line numberDiff line numberDiff line change
@@ -5213,16 +5213,11 @@ def err_template_unnamed_class : Error<
52135213
def err_template_param_list_different_arity : Error<
52145214
"%select{too few|too many}0 template parameters in template "
52155215
"%select{|template parameter }1redeclaration">;
5216-
def note_template_param_list_different_arity : Note<
5217-
"%select{too few|too many}0 template parameters in template template "
5218-
"argument">;
52195216
def note_template_prev_declaration : Note<
52205217
"previous template %select{declaration|template parameter}0 is here">;
52215218
def err_template_param_different_kind : Error<
52225219
"template parameter has a different kind in template "
52235220
"%select{|template parameter }0redeclaration">;
5224-
def note_template_param_different_kind : Note<
5225-
"template parameter has a different kind in template argument">;
52265221

52275222
def err_invalid_decl_specifier_in_nontype_parm : Error<
52285223
"invalid declaration specifier in template non-type parameter">;
@@ -5231,8 +5226,6 @@ def err_template_nontype_parm_different_type : Error<
52315226
"template non-type parameter has a different type %0 in template "
52325227
"%select{|template parameter }1redeclaration">;
52335228

5234-
def note_template_nontype_parm_different_type : Note<
5235-
"template non-type parameter has a different type %0 in template argument">;
52365229
def note_template_nontype_parm_prev_declaration : Note<
52375230
"previous non-type template parameter with type %0 is here">;
52385231
def err_template_nontype_parm_bad_type : Error<
@@ -5323,10 +5316,15 @@ def err_template_missing_args : Error<
53235316
"%select{class template|function template|variable template|alias template|"
53245317
"template template parameter|concept|template}0 %1 requires template "
53255318
"arguments">;
5326-
def err_template_arg_list_different_arity : Error<
5327-
"%select{too few|too many}0 template arguments for "
5319+
def err_template_param_missing_arg : Error<
5320+
"missing template argument for template parameter">;
5321+
def err_template_template_param_missing_param : Error<
5322+
"no template parameter in this template template parameter "
5323+
"corresponds to non-defaulted template parameter of argument template">;
5324+
def err_template_too_many_args : Error<
5325+
"too many template arguments for "
53285326
"%select{class template|function template|variable template|alias template|"
5329-
"template template parameter|concept|template}1 %2">;
5327+
"template template parameter|concept|template}0 %1">;
53305328
def note_template_decl_here : Note<"template is declared here">;
53315329
def note_template_decl_external : Note<
53325330
"template declaration from hidden source: %0">;
@@ -5364,11 +5362,8 @@ def err_template_arg_not_valid_template : Error<
53645362
"template parameter">;
53655363
def note_template_arg_refers_here_func : Note<
53665364
"template argument refers to function template %0, here">;
5367-
def err_template_arg_template_params_mismatch : Error<
5368-
"template template argument has different template parameters than its "
5369-
"corresponding template template parameter">;
53705365
def note_template_arg_template_params_mismatch : Note<
5371-
"template template argument has different template parameters than its "
5366+
"template template argument is incompatible with its "
53725367
"corresponding template template parameter">;
53735368
def err_non_deduced_mismatch : Error<
53745369
"could not match %diff{$ against $|types}0,1">;
@@ -5933,10 +5928,6 @@ def err_template_parameter_pack_non_pack : Error<
59335928
"%select{template type|non-type template|template template}0 parameter"
59345929
"%select{| pack}1 conflicts with previous %select{template type|"
59355930
"non-type template|template template}0 parameter%select{ pack|}1">;
5936-
def note_template_parameter_pack_non_pack : Note<
5937-
"%select{template type|non-type template|template template}0 parameter"
5938-
"%select{| pack}1 does not match %select{template type|non-type template"
5939-
"|template template}0 parameter%select{ pack|}1 in template argument">;
59405931
def note_template_parameter_pack_here : Note<
59415932
"previous %select{template type|non-type template|template template}0 "
59425933
"parameter%select{| pack}1 declared here">;

clang/include/clang/Sema/Sema.h

+28-9
Original file line numberDiff line numberDiff line change
@@ -11828,7 +11828,7 @@ class Sema final : public SemaBase {
1182811828
bool *ConstraintsNotSatisfied = nullptr);
1182911829

1183011830
bool CheckTemplateTypeArgument(
11831-
TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
11831+
TemplateArgumentLoc &Arg,
1183211832
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1183311833
SmallVectorImpl<TemplateArgument> &CanonicalConverted);
1183411834

@@ -11864,9 +11864,13 @@ class Sema final : public SemaBase {
1186411864
bool PartialOrdering,
1186511865
bool *StrictPackMatch);
1186611866

11867+
/// Print the given named declaration to a string,
11868+
/// using the current PrintingPolicy, except that
11869+
/// TerseOutput will always be set.
11870+
SmallString<128> toTerseString(const NamedDecl &D) const;
11871+
1186711872
void NoteTemplateLocation(const NamedDecl &Decl,
1186811873
std::optional<SourceRange> ParamRange = {});
11869-
void NoteTemplateParameterLocation(const NamedDecl &Decl);
1187011874

1187111875
/// Given a non-type template argument that refers to a
1187211876
/// declaration and the type of its corresponding non-type template
@@ -11981,15 +11985,13 @@ class Sema final : public SemaBase {
1198111985
bool TemplateParameterListsAreEqual(
1198211986
const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
1198311987
const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
11984-
TemplateParameterListEqualKind Kind,
11985-
SourceLocation TemplateArgLoc = SourceLocation());
11988+
TemplateParameterListEqualKind Kind);
1198611989

11987-
bool TemplateParameterListsAreEqual(
11988-
TemplateParameterList *New, TemplateParameterList *Old, bool Complain,
11989-
TemplateParameterListEqualKind Kind,
11990-
SourceLocation TemplateArgLoc = SourceLocation()) {
11990+
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
11991+
TemplateParameterList *Old, bool Complain,
11992+
TemplateParameterListEqualKind Kind) {
1199111993
return TemplateParameterListsAreEqual(nullptr, New, nullptr, Old, Complain,
11992-
Kind, TemplateArgLoc);
11994+
Kind);
1199311995
}
1199411996

1199511997
/// Check whether a template can be declared within this scope.
@@ -12869,6 +12871,11 @@ class Sema final : public SemaBase {
1286912871

1287012872
/// We are performing partial ordering for template template parameters.
1287112873
PartialOrderingTTP,
12874+
12875+
/// We are Checking a Template Parameter, so for any diagnostics which
12876+
/// occur in this scope, we will add a context note which points to this
12877+
/// template parameter.
12878+
CheckTemplateParameter,
1287212879
} Kind;
1287312880

1287412881
/// Was the enclosing context a non-instantiation SFINAE context?
@@ -13096,6 +13103,11 @@ class Sema final : public SemaBase {
1309613103
PartialOrderingTTP, TemplateDecl *PArg,
1309713104
SourceRange InstantiationRange = SourceRange());
1309813105

13106+
struct CheckTemplateParameter {};
13107+
/// \brief Note that we are checking a template parameter.
13108+
InstantiatingTemplate(Sema &SemaRef, CheckTemplateParameter,
13109+
NamedDecl *Param);
13110+
1309913111
/// Note that we have finished instantiating this template.
1310013112
void Clear();
1310113113

@@ -13129,6 +13141,13 @@ class Sema final : public SemaBase {
1312913141
InstantiatingTemplate &operator=(const InstantiatingTemplate &) = delete;
1313013142
};
1313113143

13144+
/// For any diagnostics which occur within its scope, adds a context note
13145+
/// pointing to the declaration of the template parameter.
13146+
struct CheckTemplateParameterRAII : InstantiatingTemplate {
13147+
CheckTemplateParameterRAII(Sema &S, NamedDecl *Param)
13148+
: InstantiatingTemplate(S, CheckTemplateParameter(), Param) {}
13149+
};
13150+
1313213151
bool SubstTemplateArgument(const TemplateArgumentLoc &Input,
1313313152
const MultiLevelTemplateArgumentList &TemplateArgs,
1313413153
TemplateArgumentLoc &Output,

clang/lib/Frontend/FrontendActions.cpp

+16-8
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,8 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
403403
}
404404

405405
private:
406-
static std::string toString(CodeSynthesisContext::SynthesisKind Kind) {
406+
static std::optional<std::string>
407+
toString(CodeSynthesisContext::SynthesisKind Kind) {
407408
switch (Kind) {
408409
case CodeSynthesisContext::TemplateInstantiation:
409410
return "TemplateInstantiation";
@@ -461,21 +462,25 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
461462
return "TypeAliasTemplateInstantiation";
462463
case CodeSynthesisContext::PartialOrderingTTP:
463464
return "PartialOrderingTTP";
465+
case CodeSynthesisContext::CheckTemplateParameter:
466+
return std::nullopt;
464467
}
465-
return "";
468+
return std::nullopt;
466469
}
467470

468471
template <bool BeginInstantiation>
469472
static void displayTemplightEntry(llvm::raw_ostream &Out, const Sema &TheSema,
470473
const CodeSynthesisContext &Inst) {
471474
std::string YAML;
472475
{
476+
std::optional<TemplightEntry> Entry =
477+
getTemplightEntry<BeginInstantiation>(TheSema, Inst);
478+
if (!Entry)
479+
return;
473480
llvm::raw_string_ostream OS(YAML);
474481
llvm::yaml::Output YO(OS);
475-
TemplightEntry Entry =
476-
getTemplightEntry<BeginInstantiation>(TheSema, Inst);
477482
llvm::yaml::EmptyContext Context;
478-
llvm::yaml::yamlize(YO, Entry, true, Context);
483+
llvm::yaml::yamlize(YO, *Entry, true, Context);
479484
}
480485
Out << "---" << YAML << "\n";
481486
}
@@ -555,10 +560,13 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
555560
}
556561

557562
template <bool BeginInstantiation>
558-
static TemplightEntry getTemplightEntry(const Sema &TheSema,
559-
const CodeSynthesisContext &Inst) {
563+
static std::optional<TemplightEntry>
564+
getTemplightEntry(const Sema &TheSema, const CodeSynthesisContext &Inst) {
560565
TemplightEntry Entry;
561-
Entry.Kind = toString(Inst.Kind);
566+
std::optional<std::string> Kind = toString(Inst.Kind);
567+
if (!Kind)
568+
return std::nullopt;
569+
Entry.Kind = *Kind;
562570
Entry.Event = BeginInstantiation ? "Begin" : "End";
563571
llvm::raw_string_ostream OS(Entry.Name);
564572
printEntryName(TheSema, Inst.Entity, OS);

clang/lib/Sema/SemaInit.cpp

+3-4
Original file line numberDiff line numberDiff line change
@@ -7271,7 +7271,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
72717271

72727272
void InitializationSequence::PrintInitLocationNote(Sema &S,
72737273
const InitializedEntity &Entity) {
7274-
if (Entity.isParamOrTemplateParamKind() && Entity.getDecl()) {
7274+
if (Entity.isParameterKind() && Entity.getDecl()) {
72757275
if (Entity.getDecl()->getLocation().isInvalid())
72767276
return;
72777277

@@ -7280,9 +7280,8 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
72807280
<< Entity.getDecl()->getDeclName();
72817281
else
72827282
S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
7283-
}
7284-
else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
7285-
Entity.getMethodDecl())
7283+
} else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
7284+
Entity.getMethodDecl())
72867285
S.Diag(Entity.getMethodDecl()->getLocation(),
72877286
diag::note_method_return_type_change)
72887287
<< Entity.getMethodDecl()->getDeclName();

clang/lib/Sema/SemaLambda.cpp

+3-4
Original file line numberDiff line numberDiff line change
@@ -1506,14 +1506,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
15061506
TemplateParameterList *TemplateParams =
15071507
getGenericLambdaTemplateParameterList(LSI, *this);
15081508
if (TemplateParams) {
1509-
for (const auto *TP : TemplateParams->asArray()) {
1509+
for (auto *TP : TemplateParams->asArray()) {
15101510
if (!TP->getIdentifier())
15111511
continue;
1512+
CheckTemplateParameterRAII CTP(*this, TP);
15121513
for (const auto &Capture : Intro.Captures) {
1513-
if (Capture.Id == TP->getIdentifier()) {
1514+
if (Capture.Id == TP->getIdentifier())
15141515
Diag(Capture.Loc, diag::err_template_param_shadow) << Capture.Id;
1515-
NoteTemplateParameterLocation(*TP);
1516-
}
15171516
}
15181517
}
15191518
}

clang/lib/Sema/SemaLookup.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -1580,9 +1580,13 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
15801580
unsigned N = CodeSynthesisContexts.size();
15811581
for (unsigned I = CodeSynthesisContextLookupModules.size();
15821582
I != N; ++I) {
1583-
Module *M = CodeSynthesisContexts[I].Entity ?
1584-
getDefiningModule(*this, CodeSynthesisContexts[I].Entity) :
1585-
nullptr;
1583+
auto &Ctx = CodeSynthesisContexts[I];
1584+
// FIXME: Are there any other context kinds that shouldn't be looked at
1585+
// here?
1586+
if (Ctx.Kind == CodeSynthesisContext::PartialOrderingTTP ||
1587+
Ctx.Kind == CodeSynthesisContext::CheckTemplateParameter)
1588+
continue;
1589+
Module *M = Ctx.Entity ? getDefiningModule(*this, Ctx.Entity) : nullptr;
15861590
if (M && !LookupModulesCache.insert(M).second)
15871591
M = nullptr;
15881592
CodeSynthesisContextLookupModules.push_back(M);
@@ -3703,7 +3707,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
37033707
TemplateParameterList *Params = FD->getTemplateParameters();
37043708
if (Params->size() == 1) {
37053709
IsTemplate = true;
3706-
if (!Params->getParam(0)->isTemplateParameterPack() && !StringLit) {
3710+
NamedDecl *Param = Params->getParam(0);
3711+
if (!Param->isTemplateParameterPack() && !StringLit) {
37073712
// Implied but not stated: user-defined integer and floating literals
37083713
// only ever use numeric literal operator templates, not templates
37093714
// taking a parameter of class type.
@@ -3716,6 +3721,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
37163721
if (StringLit) {
37173722
SFINAETrap Trap(*this);
37183723
CheckTemplateArgumentInfo CTAI;
3724+
CheckTemplateParameterRAII CTP(*this, Param);
37193725
TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
37203726
if (CheckTemplateArgument(
37213727
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),

0 commit comments

Comments
 (0)