Skip to content

[clang] Implement instantiation context note for checking template parameters #126088

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

mizvekov
Copy link
Contributor

@mizvekov mizvekov commented Feb 6, 2025

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.

@mizvekov mizvekov self-assigned this Feb 6, 2025
@mizvekov mizvekov requested a review from Endilll as a code owner February 6, 2025 16:32
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules HLSL HLSL Language Support labels Feb 6, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 6, 2025

@llvm/pr-subscribers-hlsl

@llvm/pr-subscribers-clang-modules

Author: Matheus Izvekov (mizvekov)

Changes

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 --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]

@llvmbot
Copy link
Member

llvmbot commented Feb 6, 2025

@llvm/pr-subscribers-clang

Author: Matheus Izvekov (mizvekov)

Changes

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 --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]

@zyn0217
Copy link
Contributor

zyn0217 commented Feb 6, 2025

(Did you mean Implement *instantiation* context for checking template parameters?)

@mizvekov
Copy link
Contributor Author

mizvekov commented Feb 6, 2025

(Did you mean Implement *instantiation* context for checking template parameters?)

Oops, yes of course :)

@mizvekov mizvekov changed the title [clang] Implement evaluation context for checking template parameters [clang] Implement instantiation context for checking template parameters Feb 6, 2025
@mizvekov mizvekov changed the title [clang] Implement instantiation context for checking template parameters [clang] Implement instantiation context note for checking template parameters Feb 6, 2025
Copy link
Contributor

@Endilll Endilll left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job following the way expected directives are written in C++ DR tests, but I have to ask you to fix the remaining discrepancies to keep them consistent.

I also spotted the same note emitted twice for the same line. That seems unfortunate.

@mizvekov mizvekov force-pushed the users/mizvekov/clang-print-context-stack-diags-supressed-by-deduction branch 2 times, most recently from f7e2964 to 228d525 Compare February 19, 2025 11:05
Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few quick comments, else the source changes LGTM. Note that @endill's suggestion to use 'bookmarks' for notes (or something like that) are good ones that I agree with.

@mizvekov mizvekov force-pushed the users/mizvekov/clang-check-template-parameter-eval-context branch 6 times, most recently from 2af6244 to ae8b23b Compare February 19, 2025 20:26
Comment on lines 5299 to 5291
def err_template_template_param_missing_param : Error<
"missing template parameter to bind to template template parameter">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formulation of this is a bit weird.
Maybe: "template template argument 'foo' incompatible with 'bar': template parameter list arity mismatch"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can point to the template template parameter and argument source locations, so we shouldn't try to spell them in the diagnostic.

The 'parameter list arity mismatch' is an exact match oriented kind of diagnostic, which becomes confusing with P0522, where you can default the parameter to make this work.

Here we can be more helpful and say how the argument is incompatible with the template template parameter: we will point out in a later note which template parameter doesn't have a corresponding parameter in the template template parameter.

I think the ideal here is for the error to be formulated in such a way as to mention the template parameter which we will note later, so that it doesn't look like the note came out of the blue.

For a test case like:

template <class T1, class T2> struct A;
template <template <class T3> class TT> struct B;
template struct B<A>;

I made another change to clarify this error. Here is how this prints now with this patch:

test.cc:2:29: error: no template parameter in this template template parameter corresponds to non-defaulted template parameter of argument template
    2 | template <template <class T3> class TT> struct B;
      |                             ^
test.cc:1:27: note: template parameter is declared here
    1 | template <class T1, class T2> struct A;
      |                     ~~~~~~^~
test.cc:3:19: note: template template argument is incompatible with its corresponding template template parameter
    3 | template struct B<A>;
      |                   ^
test.cc:2:37: note: template parameter is declared here
    2 | template <template <class T3> class TT> struct B;
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~^~
1 error generated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For comparison, before this patch, the diagnostic for this example is bad:

test.cc:3:19: error: too few template arguments for class template 'A'
    3 | template struct B<A>;
      |                   ^
test.cc:3:19: note: template template argument has different template parameters than its corresponding template template parameter
test.cc:2:37: note: previous template template parameter is here
    2 | template <template <class T3> class TT> struct B;
      |           ~~~~~~~~~~~~~~~~~~~       ^
test.cc:1:38: note: template is declared here
    1 | template <class T1, class T2> struct A;
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~        ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the peanut gallery: as someone who stares at error messages from building 100s of projects in a distribution a lot, I'd find it a lot more intuitive if the error message started with

test.cc:3:19: error: <something here>
    3 | template struct B<A>;
      |                   ^
test.cc:3:<line>: note: <elaboration>

where ideally the elaboration goes like "template A from <here> doesn't satisfy template template for B from <there>".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the diagnostic should have started with the second note as an error, but this is a different problem, and is out of scope for this patch.

There are too many possible things that can be diagnosed when matching template template parameters, and most of these diagnostics are implemented for problems which occur outside of that context.

My thinking is that we will eventually need to be able to turn errors and warnings into notes, and perform transformations on the sequence of diagnostics depending on the context where they occur.

Base automatically changed from users/mizvekov/clang-print-context-stack-diags-supressed-by-deduction to main February 20, 2025 11:50
@mizvekov mizvekov force-pushed the users/mizvekov/clang-check-template-parameter-eval-context branch from ae8b23b to e094d95 Compare February 20, 2025 11:52
@mizvekov mizvekov force-pushed the users/mizvekov/clang-check-template-parameter-eval-context branch 3 times, most recently from 339f296 to 59048ff Compare February 20, 2025 18:24
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.
@mizvekov mizvekov force-pushed the users/mizvekov/clang-check-template-parameter-eval-context branch from 59048ff to e30bd8a Compare March 1, 2025 12:02
@mizvekov
Copy link
Contributor Author

mizvekov commented Mar 5, 2025

Ping. I'll merge tomorrow if there are no further objections.

@erichkeane
Copy link
Collaborator

Ping. I'll merge tomorrow if there are no further objections.

SGTM. I haven't been paying SUPER close attention, but have been keeping an eye on this at least a little, and have no objections.

@mizvekov mizvekov merged commit a24523a into main Mar 6, 2025
12 checks passed
@mizvekov mizvekov deleted the users/mizvekov/clang-check-template-parameter-eval-context branch March 6, 2025 17:58
@nikic
Copy link
Contributor

nikic commented Mar 6, 2025

This causes a large compile-time regression for C++ code: https://llvm-compile-time-tracker.com/compare_clang.php?from=37aad2c1196ea3de242d855cfe38bc25a65d6f5e&to=a24523ac8dc07f3478311a5969184b922b520395&stat=instructions%3Au&sortBy=interestingness It adds 1-3% overhead per file during the stage2 build.

Please revert this change until the regression can be resolved.

nikic added a commit that referenced this pull request Mar 10, 2025
…plate parameters (#126088)"

This reverts commit a24523a.

This is causing significant compile-time regressions for C++ code, see:
#126088 (comment)
@cor3ntin
Copy link
Contributor

@mizvekov

llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Mar 10, 2025
…hecking template parameters (#126088)"

This reverts commit a24523a.

This is causing significant compile-time regressions for C++ code, see:
llvm/llvm-project#126088 (comment)
@mizvekov
Copy link
Contributor Author

mizvekov commented Mar 10, 2025

@nikic thanks for the report, I missed your message, only saw when Corentin pinged.

Are you sure that's correct? I had run this patch through llvm-compile-time-tracker before merging, and it had shown practically no impact.

Here: https://llvm-compile-time-tracker.com/compare.php?from=4eab2194872d54e2d4496135a277b1610ff33ead&to=adde9f1f8eabe4d98ba09fd978f8d152a9865347&stat=instructions:u

@nikic
Copy link
Contributor

nikic commented Mar 10, 2025

Yes, reverting the change did recover the regression. Did you test exactly the change that was landed? It's also possible that it interacted with something that landed in the meantime...

@mizvekov
Copy link
Contributor Author

It's not exactly the same patch, had more changes on top, but the meat with the expected impact was the same.

Anyway, thanks for the revert, will investigate.

@mizvekov
Copy link
Contributor Author

Correction, I was thinking of a different PR.

I did not test this PR on compile-time-tracker, as we didn't anticipate an impact.

mizvekov added a commit that referenced this pull request Mar 10, 2025
…rameters

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
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
…rameters (llvm#126088)

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.
@damyanp damyanp moved this to Closed in HLSL Support Apr 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
Status: Closed
Development

Successfully merging this pull request may close these issues.

9 participants