[llvm-branch-commits] [clang] [clang] Implement evaluation context for checking template parameters (PR #126088)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Feb 6 08:32:48 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Matheus Izvekov (mizvekov)

<details>
<summary>Changes</summary>

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.

---

Patch is 166.58 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/126088.diff


95 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+10) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+7-3) 
- (modified) clang/include/clang/Sema/Sema.h (+18-2) 
- (modified) clang/lib/Frontend/FrontendActions.cpp (+16-8) 
- (modified) clang/lib/Sema/SemaInit.cpp (+3-4) 
- (modified) clang/lib/Sema/SemaLambda.cpp (+3-4) 
- (modified) clang/lib/Sema/SemaLookup.cpp (+10-4) 
- (modified) clang/lib/Sema/SemaTemplate.cpp (+48-93) 
- (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+3-2) 
- (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+24-6) 
- (modified) clang/test/AST/ByteCode/cxx1z.cpp (+1-1) 
- (modified) clang/test/AST/ByteCode/cxx20.cpp (+1-1) 
- (modified) clang/test/AST/ByteCode/cxx98.cpp (+1-1) 
- (modified) clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp (+1) 
- (modified) clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp (+1-1) 
- (modified) clang/test/CXX/drs/cwg0xx.cpp (+6-4) 
- (modified) clang/test/CXX/drs/cwg10xx.cpp (+1) 
- (modified) clang/test/CXX/drs/cwg13xx.cpp (+1) 
- (modified) clang/test/CXX/drs/cwg18xx.cpp (+10-9) 
- (modified) clang/test/CXX/drs/cwg1xx.cpp (+11-5) 
- (modified) clang/test/CXX/drs/cwg20xx.cpp (+7-3) 
- (modified) clang/test/CXX/drs/cwg21xx.cpp (+2-1) 
- (modified) clang/test/CXX/drs/cwg3xx.cpp (+3) 
- (modified) clang/test/CXX/drs/cwg4xx.cpp (+9-2) 
- (modified) clang/test/CXX/drs/cwg6xx.cpp (+3-2) 
- (modified) clang/test/CXX/expr/expr.const/p3-0x.cpp (+4-3) 
- (modified) clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp (+1-1) 
- (modified) clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp (+1-1) 
- (modified) clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp (+4-3) 
- (modified) clang/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp (+7-7) 
- (modified) clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp (+6-6) 
- (modified) clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp (+4-4) 
- (modified) clang/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp (+12-6) 
- (modified) clang/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp (+2-2) 
- (modified) clang/test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp (+21-21) 
- (modified) clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp (+5-5) 
- (modified) clang/test/CXX/temp/temp.deduct/p9.cpp (+3-2) 
- (modified) clang/test/CXX/temp/temp.param/p1.cpp (+5-4) 
- (modified) clang/test/CXX/temp/temp.param/p12.cpp (+1-1) 
- (modified) clang/test/CXX/temp/temp.param/p15-cxx0x.cpp (+5-5) 
- (modified) clang/test/CXX/temp/temp.param/p8-cxx20.cpp (+1-1) 
- (modified) clang/test/CXX/temp/temp.res/temp.dep/temp.dep.constexpr/p2.cpp (+1-1) 
- (modified) clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp (+5-5) 
- (modified) clang/test/CXX/temp/temp.spec/part.spec.cpp (+2-2) 
- (modified) clang/test/CXX/temp/temp.spec/temp.expl.spec/p20.cpp (+4-4) 
- (modified) clang/test/Misc/integer-literal-printing.cpp (+7) 
- (modified) clang/test/Modules/missing-body-in-import.cpp (+1) 
- (modified) clang/test/Modules/template-default-args.cpp (+3-1) 
- (modified) clang/test/Parser/MicrosoftExtensions.cpp (+1-1) 
- (modified) clang/test/Parser/cxx-template-argument.cpp (+6-6) 
- (modified) clang/test/Parser/cxx-template-template-recovery.cpp (+12-12) 
- (modified) clang/test/Parser/cxx1z-class-template-argument-deduction.cpp (+5-5) 
- (modified) clang/test/SemaCXX/access-base-class.cpp (+12-12) 
- (modified) clang/test/SemaCXX/alias-template.cpp (+4-1) 
- (modified) clang/test/SemaCXX/anonymous-struct.cpp (+2-1) 
- (modified) clang/test/SemaCXX/constant-expression-cxx11.cpp (+2-2) 
- (modified) clang/test/SemaCXX/constant-expression.cpp (+1-1) 
- (modified) clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp (+1) 
- (modified) clang/test/SemaCXX/cxx2a-consteval.cpp (+1-1) 
- (modified) clang/test/SemaCXX/cxx98-compat-flags.cpp (+2-1) 
- (modified) clang/test/SemaCXX/cxx98-compat.cpp (+6-5) 
- (modified) clang/test/SemaCXX/implicit-member-functions.cpp (+1) 
- (modified) clang/test/SemaCXX/lambda-expressions.cpp (+4-2) 
- (modified) clang/test/SemaCXX/make_integer_seq.cpp (+1) 
- (modified) clang/test/SemaCXX/type-trait-common-type.cpp (+4-2) 
- (modified) clang/test/SemaCXX/undefined-internal.cpp (+4-2) 
- (modified) clang/test/SemaCXX/warn-deprecated-specializations-in-system-headers.cpp (+1) 
- (modified) clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl (+2-2) 
- (modified) clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl (+31-31) 
- (modified) clang/test/SemaObjCXX/parameterized_classes_subst.mm (+1-1) 
- (modified) clang/test/SemaTemplate/alias-templates.cpp (+5-4) 
- (modified) clang/test/SemaTemplate/cwg2398.cpp (+16-16) 
- (modified) clang/test/SemaTemplate/default-arguments.cpp (+13-10) 
- (modified) clang/test/SemaTemplate/instantiate-member-pointers.cpp (+6-6) 
- (modified) clang/test/SemaTemplate/instantiate-template-template-parm.cpp (+2-2) 
- (modified) clang/test/SemaTemplate/instantiation-default-1.cpp (+7-6) 
- (modified) clang/test/SemaTemplate/instantiation-default-2.cpp (+1-2) 
- (modified) clang/test/SemaTemplate/instantiation-dependence.cpp (+2-1) 
- (modified) clang/test/SemaTemplate/instantiation-depth-defarg.cpp (+4-4) 
- (modified) clang/test/SemaTemplate/instantiation-depth-exception-spec.cpp (+4-4) 
- (modified) clang/test/SemaTemplate/instantiation-depth.cpp (+3-3) 
- (modified) clang/test/SemaTemplate/ms-unqualified-base-class.cpp (+2-2) 
- (modified) clang/test/SemaTemplate/nested-template.cpp (+2-2) 
- (modified) clang/test/SemaTemplate/partial-spec-instantiate.cpp (+2-1) 
- (modified) clang/test/SemaTemplate/recovery-crash.cpp (+2-1) 
- (modified) clang/test/SemaTemplate/stack-exhaustion.cpp (+4-4) 
- (modified) clang/test/SemaTemplate/temp_arg.cpp (+6-6) 
- (modified) clang/test/SemaTemplate/temp_arg_nontype.cpp (+14-6) 
- (modified) clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp (+1-1) 
- (modified) clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp (+4-4) 
- (modified) clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp (+12-12) 
- (modified) clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp (+5-5) 
- (modified) clang/test/SemaTemplate/temp_arg_template.cpp (+9-6) 
- (modified) clang/test/SemaTemplate/temp_arg_template_p0522.cpp (+5-8) 
- (modified) clang/test/SemaTemplate/temp_arg_type.cpp (+5-2) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index dfce173d414ebb2..7e20954c65e67b4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -149,6 +149,16 @@ Bug Fixes to C++ Support
 - Clang now prints the correct instantiation context for diagnostics suppressed
   by template argument deduction.
 
+Improvements to C++ diagnostics
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Clang now more consistently adds a note pointing to the relevant template
+  parameter. Some diagnostics are reworded to better take advantage of this.
+- Template Template Parameter diagnostics now stop referring to template
+  parameters as template arguments, in some circumstances, better hiding
+  from the users template template parameter partial ordering arcana.
+
+
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7b3b932c482baa2..6ab26fb25d8238f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5290,10 +5290,14 @@ def err_template_missing_args : Error<
   "%select{class template|function template|variable template|alias template|"
   "template template parameter|concept|template}0 %1 requires template "
   "arguments">;
-def err_template_arg_list_different_arity : Error<
-  "%select{too few|too many}0 template arguments for "
+def err_template_param_missing_arg : Error<
+  "missing template argument for template parameter">;
+def err_template_template_param_missing_param : Error<
+  "missing template parameter to bind to template template parameter">;
+def err_template_too_many_args : Error<
+  "too many template arguments for "
   "%select{class template|function template|variable template|alias template|"
-  "template template parameter|concept|template}1 %2">;
+  "template template parameter|concept|template}0 %1">;
 def note_template_decl_here : Note<"template is declared here">;
 def note_template_decl_external : Note<
   "template declaration from hidden source: %0">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index e39930c1a450343..93b1094616d6a1a 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11781,7 +11781,7 @@ class Sema final : public SemaBase {
                                  bool *ConstraintsNotSatisfied = nullptr);
 
   bool CheckTemplateTypeArgument(
-      TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
+      TemplateArgumentLoc &Arg,
       SmallVectorImpl<TemplateArgument> &SugaredConverted,
       SmallVectorImpl<TemplateArgument> &CanonicalConverted);
 
@@ -11817,9 +11817,10 @@ class Sema final : public SemaBase {
                                      bool PartialOrdering,
                                      bool *StrictPackMatch);
 
+  SmallString<128> toTerseString(const NamedDecl &D) const;
+
   void NoteTemplateLocation(const NamedDecl &Decl,
                             std::optional<SourceRange> ParamRange = {});
-  void NoteTemplateParameterLocation(const NamedDecl &Decl);
 
   /// Given a non-type template argument that refers to a
   /// declaration and the type of its corresponding non-type template
@@ -12821,6 +12822,9 @@ class Sema final : public SemaBase {
 
       /// We are performing partial ordering for template template parameters.
       PartialOrderingTTP,
+
+      /// Checking a Template Parameter
+      CheckTemplateParameter,
     } Kind;
 
     /// Was the enclosing context a non-instantiation SFINAE context?
@@ -13048,6 +13052,11 @@ class Sema final : public SemaBase {
                           PartialOrderingTTP, TemplateDecl *PArg,
                           SourceRange InstantiationRange = SourceRange());
 
+    struct CheckTemplateParameter {};
+    /// \brief Note that we are checking a template parameter.
+    InstantiatingTemplate(Sema &SemaRef, CheckTemplateParameter,
+                          NamedDecl *Param);
+
     /// Note that we have finished instantiating this template.
     void Clear();
 
@@ -13081,6 +13090,13 @@ class Sema final : public SemaBase {
     InstantiatingTemplate &operator=(const InstantiatingTemplate &) = delete;
   };
 
+  /// For any diagnostics which occur within its scope, adds a context note
+  /// pointing to the declaration of the template parameter.
+  struct CheckTemplateParameterRAII : InstantiatingTemplate {
+    CheckTemplateParameterRAII(Sema &S, NamedDecl *Param)
+        : InstantiatingTemplate(S, CheckTemplateParameter(), Param) {}
+  };
+
   bool SubstTemplateArgument(const TemplateArgumentLoc &Input,
                              const MultiLevelTemplateArgumentList &TemplateArgs,
                              TemplateArgumentLoc &Output,
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index 1ea4a2e9e88cf59..60e103e643e273b 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -403,7 +403,8 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
   }
 
 private:
-  static std::string toString(CodeSynthesisContext::SynthesisKind Kind) {
+  static std::optional<std::string>
+  toString(CodeSynthesisContext::SynthesisKind Kind) {
     switch (Kind) {
     case CodeSynthesisContext::TemplateInstantiation:
       return "TemplateInstantiation";
@@ -461,8 +462,10 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
       return "TypeAliasTemplateInstantiation";
     case CodeSynthesisContext::PartialOrderingTTP:
       return "PartialOrderingTTP";
+    case CodeSynthesisContext::CheckTemplateParameter:
+      return std::nullopt;
     }
-    return "";
+    return std::nullopt;
   }
 
   template <bool BeginInstantiation>
@@ -470,12 +473,14 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
                                     const CodeSynthesisContext &Inst) {
     std::string YAML;
     {
+      std::optional<TemplightEntry> Entry =
+          getTemplightEntry<BeginInstantiation>(TheSema, Inst);
+      if (!Entry)
+        return;
       llvm::raw_string_ostream OS(YAML);
       llvm::yaml::Output YO(OS);
-      TemplightEntry Entry =
-          getTemplightEntry<BeginInstantiation>(TheSema, Inst);
       llvm::yaml::EmptyContext Context;
-      llvm::yaml::yamlize(YO, Entry, true, Context);
+      llvm::yaml::yamlize(YO, *Entry, true, Context);
     }
     Out << "---" << YAML << "\n";
   }
@@ -555,10 +560,13 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
   }
 
   template <bool BeginInstantiation>
-  static TemplightEntry getTemplightEntry(const Sema &TheSema,
-                                          const CodeSynthesisContext &Inst) {
+  static std::optional<TemplightEntry>
+  getTemplightEntry(const Sema &TheSema, const CodeSynthesisContext &Inst) {
     TemplightEntry Entry;
-    Entry.Kind = toString(Inst.Kind);
+    std::optional<std::string> Kind = toString(Inst.Kind);
+    if (!Kind)
+      return std::nullopt;
+    Entry.Kind = *Kind;
     Entry.Event = BeginInstantiation ? "Begin" : "End";
     llvm::raw_string_ostream OS(Entry.Name);
     printEntryName(TheSema, Inst.Entity, OS);
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index f206cd57eca898b..9281cfc950232f1 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -7246,7 +7246,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
 
 void InitializationSequence::PrintInitLocationNote(Sema &S,
                                               const InitializedEntity &Entity) {
-  if (Entity.isParamOrTemplateParamKind() && Entity.getDecl()) {
+  if (Entity.isParameterKind() && Entity.getDecl()) {
     if (Entity.getDecl()->getLocation().isInvalid())
       return;
 
@@ -7255,9 +7255,8 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
         << Entity.getDecl()->getDeclName();
     else
       S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
-  }
-  else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
-           Entity.getMethodDecl())
+  } else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
+             Entity.getMethodDecl())
     S.Diag(Entity.getMethodDecl()->getLocation(),
            diag::note_method_return_type_change)
       << Entity.getMethodDecl()->getDeclName();
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index ceb32ee15dfa39c..4d278bbc67d281a 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1506,14 +1506,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
   TemplateParameterList *TemplateParams =
       getGenericLambdaTemplateParameterList(LSI, *this);
   if (TemplateParams) {
-    for (const auto *TP : TemplateParams->asArray()) {
+    for (auto *TP : TemplateParams->asArray()) {
       if (!TP->getIdentifier())
         continue;
+      CheckTemplateParameterRAII CTP(*this, TP);
       for (const auto &Capture : Intro.Captures) {
-        if (Capture.Id == TP->getIdentifier()) {
+        if (Capture.Id == TP->getIdentifier())
           Diag(Capture.Loc, diag::err_template_param_shadow) << Capture.Id;
-          NoteTemplateParameterLocation(*TP);
-        }
       }
     }
   }
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 0f5b7426e743e05..71d9add9d8c098f 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -1586,9 +1586,13 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
   unsigned N = CodeSynthesisContexts.size();
   for (unsigned I = CodeSynthesisContextLookupModules.size();
        I != N; ++I) {
-    Module *M = CodeSynthesisContexts[I].Entity ?
-                getDefiningModule(*this, CodeSynthesisContexts[I].Entity) :
-                nullptr;
+    auto &Ctx = CodeSynthesisContexts[I];
+    // FIXME: Are there any other context kinds that shouldn't be looked at
+    // here?
+    if (Ctx.Kind == CodeSynthesisContext::PartialOrderingTTP ||
+        Ctx.Kind == CodeSynthesisContext::CheckTemplateParameter)
+      continue;
+    Module *M = Ctx.Entity ? getDefiningModule(*this, Ctx.Entity) : nullptr;
     if (M && !LookupModulesCache.insert(M).second)
       M = nullptr;
     CodeSynthesisContextLookupModules.push_back(M);
@@ -3709,7 +3713,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
       TemplateParameterList *Params = FD->getTemplateParameters();
       if (Params->size() == 1) {
         IsTemplate = true;
-        if (!Params->getParam(0)->isTemplateParameterPack() && !StringLit) {
+        NamedDecl *Param = Params->getParam(0);
+        if (!Param->isTemplateParameterPack() && !StringLit) {
           // Implied but not stated: user-defined integer and floating literals
           // only ever use numeric literal operator templates, not templates
           // taking a parameter of class type.
@@ -3722,6 +3727,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
         if (StringLit) {
           SFINAETrap Trap(*this);
           CheckTemplateArgumentInfo CTAI;
+          CheckTemplateParameterRAII CTP(*this, Param);
           TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
           if (CheckTemplateArgument(
                   Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 9e68972b33f0a03..78093c66c1a53aa 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -869,9 +869,11 @@ void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl,
           ? diag::ext_template_param_shadow
           : (SupportedForCompatibility ? diag::ext_compat_template_param_shadow
                                        : diag::err_template_param_shadow);
-  const auto *ND = cast<NamedDecl>(PrevDecl);
+  auto *ND = cast<NamedDecl>(PrevDecl);
+  CheckTemplateParameterRAII CTP(*this, ND);
+  // FIXME: Don't put the name in the diagnostic, unless there is no source
+  // location.
   Diag(Loc, DiagId) << ND->getDeclName();
-  NoteTemplateParameterLocation(*ND);
 }
 
 TemplateDecl *Sema::AdjustDeclIfTemplate(Decl *&D) {
@@ -4824,7 +4826,7 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
 }
 
 bool Sema::CheckTemplateTypeArgument(
-    TemplateTypeParmDecl *Param, TemplateArgumentLoc &AL,
+    TemplateArgumentLoc &AL,
     SmallVectorImpl<TemplateArgument> &SugaredConverted,
     SmallVectorImpl<TemplateArgument> &CanonicalConverted) {
   const TemplateArgument &Arg = AL.getArgument();
@@ -4880,7 +4882,6 @@ bool Sema::CheckTemplateTypeArgument(
                       ? diag::ext_ms_template_type_arg_missing_typename
                       : diag::err_template_arg_must_be_type_suggest)
             << FixItHint::CreateInsertion(Loc, "typename ");
-        NoteTemplateParameterLocation(*Param);
 
         // Recover by synthesizing a type using the location information that we
         // already have.
@@ -4918,7 +4919,6 @@ bool Sema::CheckTemplateTypeArgument(
     // is not a type.
     SourceRange SR = AL.getSourceRange();
     Diag(SR.getBegin(), diag::err_template_arg_must_be_type) << SR;
-    NoteTemplateParameterLocation(*Param);
 
     return true;
   }
@@ -5208,8 +5208,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
                                  CheckTemplateArgumentInfo &CTAI,
                                  CheckTemplateArgumentKind CTAK) {
   // Check template type parameters.
-  if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
-    return CheckTemplateTypeArgument(TTP, ArgLoc, CTAI.SugaredConverted,
+  if (isa<TemplateTypeParmDecl>(Param))
+    return CheckTemplateTypeArgument(ArgLoc, CTAI.SugaredConverted,
                                      CTAI.CanonicalConverted);
 
   const TemplateArgument &Arg = ArgLoc.getArgument();
@@ -5354,8 +5354,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
       // therefore cannot be a non-type template argument.
       Diag(ArgLoc.getLocation(), diag::err_template_arg_must_be_expr)
           << ArgLoc.getSourceRange();
-      NoteTemplateParameterLocation(*Param);
-
       return true;
 
     case TemplateArgument::Type: {
@@ -5375,7 +5373,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
         Diag(SR.getBegin(), diag::err_template_arg_nontype_ambig) << SR << T;
       else
         Diag(SR.getBegin(), diag::err_template_arg_must_be_expr) << SR;
-      NoteTemplateParameterLocation(*Param);
       return true;
     }
 
@@ -5466,11 +5463,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
 }
 
 /// Diagnose a missing template argument.
-template<typename TemplateParmDecl>
+template <typename TemplateParmDecl>
 static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
-                                    TemplateDecl *TD,
-                                    const TemplateParmDecl *D,
-                                    TemplateArgumentListInfo &Args) {
+                                    TemplateDecl *TD, const TemplateParmDecl *D,
+                                    TemplateArgumentListInfo &Args,
+                                    bool MatchingTTP) {
   // Dig out the most recent declaration of the template parameter; there may be
   // declarations of the template that are more recent than TD.
   D = cast<TemplateParmDecl>(cast<TemplateDecl>(TD->getMostRecentDecl())
@@ -5488,16 +5485,12 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
     return true;
   }
 
+  SourceLocation DiagLoc = Args.getRAngleLoc();
   // FIXME: If there's a more recent default argument that *is* visible,
   // diagnose that it was declared too late.
-
-  TemplateParameterList *Params = TD->getTemplateParameters();
-
-  S.Diag(Loc, diag::err_template_arg_list_different_arity)
-    << /*not enough args*/0
-    << (int)S.getTemplateNameKindForDiagnostics(TemplateName(TD))
-    << TD;
-  S.NoteTemplateLocation(*TD, Params->getSourceRange());
+  S.Diag(DiagLoc.isValid() ? DiagLoc : Loc,
+         MatchingTTP ? diag::err_template_template_param_missing_param
+                     : diag::err_template_param_missing_arg);
   return true;
 }
 
@@ -5536,6 +5529,8 @@ bool Sema::CheckTemplateArgumentList(
                                        Param = ParamBegin;
        Param != ParamEnd;
        /* increment in loop */) {
+    CheckTemplateParameterRAII CTP1(*this, *Param);
+
     if (size_t ParamIdx = Param - ParamBegin;
         DefaultArgs && ParamIdx >= DefaultArgs.StartPos) {
       // All written arguments should have been consumed by this point.
@@ -5572,11 +5567,9 @@ bool Sema::CheckTemplateArgumentList(
         continue;
       } else if (ArgIdx == NumArgs && !PartialTemplateArgs) {
         // Not enough arguments for this parameter pack.
-        Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
-          << /*not enough args*/0
-          << (int)getTemplateNameKindForDiagnostics(TemplateName(Template))
-          << Template;
-        NoteTemplateLocation(*Template, Params->getSourceRange());
+        Diag(RAngleLoc, CTAI.MatchingTTP
+                            ? diag::err_template_template_param_missing_param
+                            : diag::err_template_param_missing_arg);
         return true;
       }
     }
@@ -5589,8 +5582,10 @@ bool Sema::CheckTemplateArgumentList(
 
       if (ArgIsExpansion && CTAI.MatchingTTP) {
         SmallVector<TemplateArgument, 4> Args(ParamEnd - Param);
+        CTP1.Clear(); // Will continue processing parameters below.
         for (TemplateParameterList::iterator First = Param; Param != ParamEnd;
              ++Param) {
+          CheckTemplateParameterRAII CTP2(*this, *Param);
           TemplateArgument &Arg = Args[Param - First];
           Arg = ArgLoc.getArgument();
           if (!(*Param)->isTemplateParameterPack() ||
@@ -5631,7 +5626,6 @@ bool Sema::CheckTemplateArgumentList(
                  diag::err_template_expansion_into_fixed_list)
                 << (isa<ConceptDecl>(Template) ? 1 : 0)
                 << ArgLoc.getSourceRange();
-            NoteTemplateParameterLocation(**Param);
             return true;
           }
         }
@@ -5738,14 +5732,14 @@ bool Sema::CheckTemplateArgumentList(
       if (!HasDefaultArg) {
         if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param))
           return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
-                                         NewArgs);
+                                         NewArgs, CTAI.MatchingTTP);
         if (NonTypeTemplateParmDecl *NTTP =
                 dyn_cast<NonTypeTemplateParmDecl>(*Param))
           return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
-                                         NewArgs);
+                                         NewArgs, CTAI.MatchingTTP);
         return diagnoseMissingArgument(*this, TemplateLoc, Template,
                                        cast<TemplateTemplateParmDecl>(*Param),
-                                       NewArgs);
+                                       NewArgs, CTAI.MatchingTTP);
       }
       return true;
     }
@@ -5801,8 +5795,7 @@ bool Sema::CheckTemplateArgumentList(
   // If we have any leftover arguments, then there were too many arguments.
   // Complain and fail.
   if (ArgIdx < NumArgs) {
-    Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
-        << /*too many args*/1
+    Diag(TemplateLoc, diag::err_template_too_many_args)
         << (int)getTemplateNameKindForDiagnostics(TemplateName(Template))
         << Template
         << SourceRange(NewArgs[ArgIdx].getLocation(), NewArgs.getRAngleLoc());
@@ -6227,8 +6220,6 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
       << Arg->getType() << Arg->getSourceRange();
     for (unsigned I = 0, N = Notes.size(); I != N; ++I)
       S.Diag(Notes[I].first, Notes[I].second);
-
-    S.NoteTemplateParameterLocation(*Param);
     return NPV_Error;
   }
 
@@ -6253,8 +6244,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
     // The types didn't match, but we ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/126088


More information about the llvm-branch-commits mailing list