Skip to content

[clang] print correct context for diagnostics suppressed by deduction #125453

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

Conversation

mizvekov
Copy link
Contributor

@mizvekov mizvekov commented Feb 3, 2025

This patch makes it so the correct instantiation context is printed for diagnostics suppessed by template argument deduction.

The context is saved along with the suppressed diagnostic, and when the declaration they were attached to becomes used, we print the correct context, instead of whatever context was at this point.

@mizvekov mizvekov self-assigned this Feb 3, 2025
@mizvekov mizvekov requested a review from Endilll as a code owner February 3, 2025 03:26
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Feb 3, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 3, 2025

@llvm/pr-subscribers-clang

Author: Matheus Izvekov (mizvekov)

Changes

This patch makes it so the correct instantiation context is printed for diagnostics suppessed by template argument deduction.

The context is saved along with the suppressed diagnostic, and when the declaration they were attached to becomes used, we print the correct context, instead of whatever context was at this point.


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

18 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+3)
  • (modified) clang/include/clang/Sema/Sema.h (+21-5)
  • (modified) clang/lib/Sema/Sema.cpp (+11-2)
  • (modified) clang/lib/Sema/SemaAttr.cpp (+3-3)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+4-3)
  • (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+136-135)
  • (modified) clang/test/CXX/drs/cwg0xx.cpp (+5)
  • (modified) clang/test/CXX/drs/cwg4xx.cpp (+2-1)
  • (modified) clang/test/CXX/temp/temp.arg/temp.arg.type/p2.cpp (+6-3)
  • (modified) clang/test/SemaCXX/anonymous-struct.cpp (+2-3)
  • (modified) clang/test/SemaCXX/bool-increment-SFINAE.cpp (+2-2)
  • (modified) clang/test/SemaCXX/cxx98-compat-flags.cpp (+2)
  • (modified) clang/test/SemaCXX/cxx98-compat.cpp (+2)
  • (modified) clang/test/SemaCXX/deprecated.cpp (+2-2)
  • (modified) clang/test/SemaCXX/lambda-expressions.cpp (+2)
  • (modified) clang/test/SemaCXX/undefined-internal.cpp (+4-2)
  • (modified) clang/test/SemaTemplate/recovery-crash.cpp (+1)
  • (modified) clang/test/SemaTemplate/temp_arg_nontype.cpp (+1)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8be1ea2fb01455..70c3b062d97717 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -128,6 +128,9 @@ Bug Fixes to Attribute Support
 Bug Fixes to C++ Support
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
+- Clang now prints the correct instantiation context for diagnostics suppressed
+  by template argument deduction.
+
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 472a0e25adc975..7d01dc1aa4c00b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1909,7 +1909,19 @@ class Sema final : public SemaBase {
   /// '\#pragma clang attribute push' directives to the given declaration.
   void AddPragmaAttributes(Scope *S, Decl *D);
 
-  void PrintPragmaAttributeInstantiationPoint();
+  using DiagFuncRef =
+      llvm::function_ref<void(SourceLocation, PartialDiagnostic)>;
+  auto getDefaultDiagFunc() {
+    return [this](SourceLocation Loc, PartialDiagnostic PD) {
+      DiagnosticBuilder Builder(Diags.Report(Loc, PD.getDiagID()));
+      PD.Emit(Builder);
+    };
+  }
+
+  void PrintPragmaAttributeInstantiationPoint(DiagFuncRef DiagFunc);
+  void PrintPragmaAttributeInstantiationPoint() {
+    PrintPragmaAttributeInstantiationPoint(getDefaultDiagFunc());
+  }
 
   void DiagnoseUnterminatedPragmaAttribute();
 
@@ -13260,18 +13272,22 @@ class Sema final : public SemaBase {
   void pushCodeSynthesisContext(CodeSynthesisContext Ctx);
   void popCodeSynthesisContext();
 
-  void PrintContextStack() {
+  void PrintContextStack(DiagFuncRef DiagFunc) {
     if (!CodeSynthesisContexts.empty() &&
         CodeSynthesisContexts.size() != LastEmittedCodeSynthesisContextDepth) {
-      PrintInstantiationStack();
+      PrintInstantiationStack(DiagFunc);
       LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size();
     }
     if (PragmaAttributeCurrentTargetDecl)
-      PrintPragmaAttributeInstantiationPoint();
+      PrintPragmaAttributeInstantiationPoint(DiagFunc);
   }
+  void PrintContextStack() { PrintContextStack(getDefaultDiagFunc()); }
   /// Prints the current instantiation stack through a series of
   /// notes.
-  void PrintInstantiationStack();
+  void PrintInstantiationStack(DiagFuncRef DiagFunc);
+  void PrintInstantiationStack() {
+    PrintInstantiationStack(getDefaultDiagFunc());
+  }
 
   /// Determines whether we are currently in a context where
   /// template argument substitution failures are not considered
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 9507d7602aa401..33e2bd1e030513 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1654,11 +1654,20 @@ void Sema::EmitDiagnostic(unsigned DiagID, const DiagnosticBuilder &DB) {
     }
 
     case DiagnosticIDs::SFINAE_Suppress:
+      if (DiagnosticsEngine::Level Level = getDiagnostics().getDiagnosticLevel(
+              DiagInfo.getID(), DiagInfo.getLocation());
+          Level == DiagnosticsEngine::Ignored)
+        return;
       // Make a copy of this suppressed diagnostic and store it with the
       // template-deduction information;
       if (*Info) {
-        (*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(),
-                       PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
+        (*Info)->addSuppressedDiagnostic(
+            DiagInfo.getLocation(),
+            PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
+        if (!Diags.getDiagnosticIDs()->isNote(DiagID))
+          PrintContextStack([Info](SourceLocation Loc, PartialDiagnostic PD) {
+            (*Info)->addSuppressedDiagnostic(Loc, std::move(PD));
+          });
       }
 
       // Suppress this diagnostic.
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 6907fa91e28c20..b66c7d3024adc9 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -1217,10 +1217,10 @@ void Sema::AddPragmaAttributes(Scope *S, Decl *D) {
   }
 }
 
-void Sema::PrintPragmaAttributeInstantiationPoint() {
+void Sema::PrintPragmaAttributeInstantiationPoint(DiagFuncRef DiagFunc) {
   assert(PragmaAttributeCurrentTargetDecl && "Expected an active declaration");
-  Diags.Report(PragmaAttributeCurrentTargetDecl->getBeginLoc(),
-               diag::note_pragma_attribute_applied_decl_here);
+  DiagFunc(PragmaAttributeCurrentTargetDecl->getBeginLoc(),
+           PDiag(diag::note_pragma_attribute_applied_decl_here));
 }
 
 void Sema::DiagnosePrecisionLossInComplexDivision() {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ba4aaa94b90ffd..1d693333fef58b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -225,9 +225,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
     // emit them now.
     auto Pos = SuppressedDiagnostics.find(D->getCanonicalDecl());
     if (Pos != SuppressedDiagnostics.end()) {
-      for (const PartialDiagnosticAt &Suppressed : Pos->second)
-        Diag(Suppressed.first, Suppressed.second);
-
+      for (const auto &[DiagLoc, PD] : Pos->second) {
+        DiagnosticBuilder Builder(Diags.Report(DiagLoc, PD.getDiagID()));
+        PD.Emit(Builder);
+      }
       // Clear out the list of suppressed diagnostics, so that we don't emit
       // them again for this specialization. However, we don't obsolete this
       // entry from the table, because we want to avoid ever emitting these
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index dc3bfa97eff399..dd832d0dd709bf 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -904,7 +904,7 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
   return true;
 }
 
-void Sema::PrintInstantiationStack() {
+void Sema::PrintInstantiationStack(DiagFuncRef DiagFunc) {
   // Determine which template instantiations to skip, if any.
   unsigned SkipStart = CodeSynthesisContexts.size(), SkipEnd = SkipStart;
   unsigned Limit = Diags.getTemplateBacktraceLimit();
@@ -924,9 +924,9 @@ void Sema::PrintInstantiationStack() {
     if (InstantiationIdx >= SkipStart && InstantiationIdx < SkipEnd) {
       if (InstantiationIdx == SkipStart) {
         // Note that we're skipping instantiations.
-        Diags.Report(Active->PointOfInstantiation,
-                     diag::note_instantiation_contexts_suppressed)
-          << unsigned(CodeSynthesisContexts.size() - Limit);
+        DiagFunc(Active->PointOfInstantiation,
+                 PDiag(diag::note_instantiation_contexts_suppressed)
+                     << unsigned(CodeSynthesisContexts.size() - Limit));
       }
       continue;
     }
@@ -938,37 +938,34 @@ void Sema::PrintInstantiationStack() {
         unsigned DiagID = diag::note_template_member_class_here;
         if (isa<ClassTemplateSpecializationDecl>(Record))
           DiagID = diag::note_template_class_instantiation_here;
-        Diags.Report(Active->PointOfInstantiation, DiagID)
-          << Record << Active->InstantiationRange;
+        DiagFunc(Active->PointOfInstantiation,
+                 PDiag(DiagID) << Record << Active->InstantiationRange);
       } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
         unsigned DiagID;
         if (Function->getPrimaryTemplate())
           DiagID = diag::note_function_template_spec_here;
         else
           DiagID = diag::note_template_member_function_here;
-        Diags.Report(Active->PointOfInstantiation, DiagID)
-          << Function
-          << Active->InstantiationRange;
+        DiagFunc(Active->PointOfInstantiation,
+                 PDiag(DiagID) << Function << Active->InstantiationRange);
       } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
-        Diags.Report(Active->PointOfInstantiation,
-                     VD->isStaticDataMember()?
-                       diag::note_template_static_data_member_def_here
-                     : diag::note_template_variable_def_here)
-          << VD
-          << Active->InstantiationRange;
+        DiagFunc(Active->PointOfInstantiation,
+                 PDiag(VD->isStaticDataMember()
+                           ? diag::note_template_static_data_member_def_here
+                           : diag::note_template_variable_def_here)
+                     << VD << Active->InstantiationRange);
       } else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
-        Diags.Report(Active->PointOfInstantiation,
-                     diag::note_template_enum_def_here)
-          << ED
-          << Active->InstantiationRange;
+        DiagFunc(Active->PointOfInstantiation,
+                 PDiag(diag::note_template_enum_def_here)
+                     << ED << Active->InstantiationRange);
       } else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
-        Diags.Report(Active->PointOfInstantiation,
-                     diag::note_template_nsdmi_here)
-            << FD << Active->InstantiationRange;
+        DiagFunc(Active->PointOfInstantiation,
+                 PDiag(diag::note_template_nsdmi_here)
+                     << FD << Active->InstantiationRange);
       } else if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(D)) {
-        Diags.Report(Active->PointOfInstantiation,
-                     diag::note_template_class_instantiation_here)
-            << CTD << Active->InstantiationRange;
+        DiagFunc(Active->PointOfInstantiation,
+                 PDiag(diag::note_template_class_instantiation_here)
+                     << CTD << Active->InstantiationRange);
       }
       break;
     }
@@ -980,35 +977,35 @@ void Sema::PrintInstantiationStack() {
       Template->printName(OS, getPrintingPolicy());
       printTemplateArgumentList(OS, Active->template_arguments(),
                                 getPrintingPolicy());
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_default_arg_instantiation_here)
-        << OS.str()
-        << Active->InstantiationRange;
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_default_arg_instantiation_here)
+                   << OS.str() << Active->InstantiationRange);
       break;
     }
 
     case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: {
       FunctionTemplateDecl *FnTmpl = cast<FunctionTemplateDecl>(Active->Entity);
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_explicit_template_arg_substitution_here)
-        << FnTmpl
-        << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(),
-                                           Active->TemplateArgs,
-                                           Active->NumTemplateArgs)
-        << Active->InstantiationRange;
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_explicit_template_arg_substitution_here)
+                   << FnTmpl
+                   << getTemplateArgumentBindingsText(
+                          FnTmpl->getTemplateParameters(), Active->TemplateArgs,
+                          Active->NumTemplateArgs)
+                   << Active->InstantiationRange);
       break;
     }
 
     case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: {
       if (FunctionTemplateDecl *FnTmpl =
               dyn_cast<FunctionTemplateDecl>(Active->Entity)) {
-        Diags.Report(Active->PointOfInstantiation,
-                     diag::note_function_template_deduction_instantiation_here)
-          << FnTmpl
-          << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(),
-                                             Active->TemplateArgs,
-                                             Active->NumTemplateArgs)
-          << Active->InstantiationRange;
+        DiagFunc(
+            Active->PointOfInstantiation,
+            PDiag(diag::note_function_template_deduction_instantiation_here)
+                << FnTmpl
+                << getTemplateArgumentBindingsText(
+                       FnTmpl->getTemplateParameters(), Active->TemplateArgs,
+                       Active->NumTemplateArgs)
+                << Active->InstantiationRange);
       } else {
         bool IsVar = isa<VarTemplateDecl>(Active->Entity) ||
                      isa<VarTemplateSpecializationDecl>(Active->Entity);
@@ -1027,12 +1024,13 @@ void Sema::PrintInstantiationStack() {
           llvm_unreachable("unexpected template kind");
         }
 
-        Diags.Report(Active->PointOfInstantiation,
-                     diag::note_deduced_template_arg_substitution_here)
-          << IsVar << IsTemplate << cast<NamedDecl>(Active->Entity)
-          << getTemplateArgumentBindingsText(Params, Active->TemplateArgs,
-                                             Active->NumTemplateArgs)
-          << Active->InstantiationRange;
+        DiagFunc(Active->PointOfInstantiation,
+                 PDiag(diag::note_deduced_template_arg_substitution_here)
+                     << IsVar << IsTemplate << cast<NamedDecl>(Active->Entity)
+                     << getTemplateArgumentBindingsText(Params,
+                                                        Active->TemplateArgs,
+                                                        Active->NumTemplateArgs)
+                     << Active->InstantiationRange);
       }
       break;
     }
@@ -1046,10 +1044,9 @@ void Sema::PrintInstantiationStack() {
       FD->printName(OS, getPrintingPolicy());
       printTemplateArgumentList(OS, Active->template_arguments(),
                                 getPrintingPolicy());
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_default_function_arg_instantiation_here)
-        << OS.str()
-        << Active->InstantiationRange;
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_default_function_arg_instantiation_here)
+                   << OS.str() << Active->InstantiationRange);
       break;
     }
 
@@ -1066,14 +1063,13 @@ void Sema::PrintInstantiationStack() {
         TemplateParams =
           cast<ClassTemplatePartialSpecializationDecl>(Active->Template)
                                                       ->getTemplateParameters();
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_prior_template_arg_substitution)
-        << isa<TemplateTemplateParmDecl>(Parm)
-        << Name
-        << getTemplateArgumentBindingsText(TemplateParams,
-                                           Active->TemplateArgs,
-                                           Active->NumTemplateArgs)
-        << Active->InstantiationRange;
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_prior_template_arg_substitution)
+                   << isa<TemplateTemplateParmDecl>(Parm) << Name
+                   << getTemplateArgumentBindingsText(TemplateParams,
+                                                      Active->TemplateArgs,
+                                                      Active->NumTemplateArgs)
+                   << Active->InstantiationRange);
       break;
     }
 
@@ -1086,55 +1082,56 @@ void Sema::PrintInstantiationStack() {
           cast<ClassTemplatePartialSpecializationDecl>(Active->Template)
                                                       ->getTemplateParameters();
 
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_template_default_arg_checking)
-        << getTemplateArgumentBindingsText(TemplateParams,
-                                           Active->TemplateArgs,
-                                           Active->NumTemplateArgs)
-        << Active->InstantiationRange;
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_template_default_arg_checking)
+                   << getTemplateArgumentBindingsText(TemplateParams,
+                                                      Active->TemplateArgs,
+                                                      Active->NumTemplateArgs)
+                   << Active->InstantiationRange);
       break;
     }
 
     case CodeSynthesisContext::ExceptionSpecEvaluation:
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_evaluating_exception_spec_here)
-          << cast<FunctionDecl>(Active->Entity);
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_evaluating_exception_spec_here)
+                   << cast<FunctionDecl>(Active->Entity));
       break;
 
     case CodeSynthesisContext::ExceptionSpecInstantiation:
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_template_exception_spec_instantiation_here)
-        << cast<FunctionDecl>(Active->Entity)
-        << Active->InstantiationRange;
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_template_exception_spec_instantiation_here)
+                   << cast<FunctionDecl>(Active->Entity)
+                   << Active->InstantiationRange);
       break;
 
     case CodeSynthesisContext::RequirementInstantiation:
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_template_requirement_instantiation_here)
-        << Active->InstantiationRange;
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_template_requirement_instantiation_here)
+                   << Active->InstantiationRange);
       break;
     case CodeSynthesisContext::RequirementParameterInstantiation:
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_template_requirement_params_instantiation_here)
-          << Active->InstantiationRange;
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_template_requirement_params_instantiation_here)
+                   << Active->InstantiationRange);
       break;
 
     case CodeSynthesisContext::NestedRequirementConstraintsCheck:
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_nested_requirement_here)
-        << Active->InstantiationRange;
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_nested_requirement_here)
+                   << Active->InstantiationRange);
       break;
 
     case CodeSynthesisContext::DeclaringSpecialMember:
-      Diags.Report(Active->PointOfInstantiation,
-                   diag::note_in_declaration_of_implicit_special_member)
-          << cast<CXXRecordDecl>(Active->Entity)
-          << llvm::to_underlying(Active->SpecialMember);
+      DiagFunc(Active->PointOfInstantiation,
+               PDiag(diag::note_in_declaration_of_implicit_special_member)
+                   << cast<CXXRecordDecl>(Active->Entity)
+                   << llvm::to_underlying(Active->SpecialMember));
       break;
 
     case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
-      Diags.Report(Active->Entity->getLocation(),
-                   diag::note_in_declaration_of_implicit_equality_comparison);
+      DiagFunc(
+          Active->Entity->getLocation(),
+          PDiag(diag::note_in_declaration_of_implicit_equality_comparison));
       break;
 
     case CodeSynthesisContext::DefiningSynthesizedFunction: {
@@ -1145,60 +1142,62 @@ void Sema::PrintInstantiationStack() {
           FD ? getDefaultedFunctionKind(FD) : DefaultedFunctionKind();
       if (DFK.isSpecialMember()) {
         auto *MD = cast<CXXMethodDecl>(FD);
-        Diags.Report(Active->PointOfInstantiation,
-                     diag::note_member_synthesized_at)
-            << MD->isExplicitlyDefaulted()
-            << llvm::to_underlying(DFK.asSpecialMember())
-            << Context.getTagDeclType(MD->getParent());
+        DiagFunc(Active->PointOfInstantiation,
+                 PDiag(diag::note_member_synthesized_at)
+                     << MD->isExplicitlyDefaulted()
+                     << llvm::to_underlying(DFK.asSpecialMember())
+                     << Context.getTagDeclType(MD->getParent()));
       } else if (DFK.isComparison()) {
         QualType RecordType = FD->getParamDecl(0)
                                   ->getType()
                                   .getNonReferenceType()
                                   .getUnqualifiedType();
-        Diags.Report(Active->PointOfInstantiation,
-                     diag::note_comparison_synthesized_at)
-            << (int)DFK.asComparis...
[truncated]

@zygoloid
Copy link
Collaborator

zygoloid commented Feb 3, 2025

Thank you for tackling this longstanding issue! How much does saving this extra state add to the runtime and memory usage on a template-heavy compilation?

If the cost is concerning, one other option we could consider here would be performing pending local instantiations eagerly when we reach the end of a region in which we have a context note -- that'd mean we don't need to save state for later. That's subtly behavior changing because it will pick an earlier point of instantiation for those local instantiations, but it's a permitted point of instantiation; we could try it and see if it works well enough in practice. We could also delay implicit definitions of special members like we do for template instantiations to reduce the impact.

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.

Changes to C++ DR tests look good otherwise.

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.

Share some of Corentin's concerns, else just a few comments.

@mizvekov mizvekov force-pushed the users/mizvekov/clang-print-context-stack-diags-supressed-by-deduction branch from f6ea38d to ff34c10 Compare February 4, 2025 00:34
@mizvekov
Copy link
Contributor Author

mizvekov commented Feb 4, 2025

Thank you for tackling this longstanding issue! How much does saving this extra state add to the runtime and memory usage on a template-heavy compilation?

I tried building stdexec, the difference is within the noise.
Do you have any other examples of template-heavy code in mind?

If the cost is concerning, one other option we could consider here would be performing pending local instantiations eagerly when we reach the end of a region in which we have a context note -- that'd mean we don't need to save state for later. That's subtly behavior changing because it will pick an earlier point of instantiation for those local instantiations, but it's a permitted point of instantiation; we could try it and see if it works well enough in practice. We could also delay implicit definitions of special members like we do for template instantiations to reduce the impact.

Sounds worth a try, if we can find any concerns.

@mizvekov
Copy link
Contributor Author

mizvekov commented Feb 4, 2025

it's a permitted point of instantiation; we could try it and see if it works well enough in practice. We could also delay implicit definitions of special members like we do for template instantiations to reduce the impact.

Another possibility would be only saving the context up to the point of use of the decl, and then finishing the ancestors from there.

@mizvekov mizvekov force-pushed the users/mizvekov/clang-print-context-stack-diags-supressed-by-deduction branch from ff34c10 to adde9f1 Compare February 5, 2025 21:24
@mizvekov
Copy link
Contributor Author

mizvekov commented Feb 6, 2025

@mizvekov mizvekov force-pushed the users/mizvekov/clang-print-context-stack-diags-supressed-by-deduction branch from adde9f1 to a36dcb0 Compare February 6, 2025 16:12
mizvekov added a commit that referenced this pull request 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 force-pushed the users/mizvekov/clang-print-context-stack-diags-supressed-by-deduction branch from a36dcb0 to f7e2964 Compare February 19, 2025 11:03
This patch makes it so the correct instantiation context is printed
for diagnostics suppessed by template argument deduction.

The context is saved along with the suppressed diagnostic, and
when the declaration they were attached to becomes used, we print
the correct context, instead of whatever context was at this point.
@mizvekov mizvekov force-pushed the users/mizvekov/clang-print-context-stack-diags-supressed-by-deduction branch from f7e2964 to 228d525 Compare February 19, 2025 11:05
mizvekov added a commit that referenced this pull request Feb 19, 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.
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.

I'm happy once Corentin/zyn0217/others that commented are.

mizvekov added a commit that referenced this pull request Feb 19, 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 added a commit that referenced this pull request Feb 19, 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
Copy link
Contributor Author

@cor3ntin ping

@mizvekov mizvekov merged commit 0948fc8 into main Feb 20, 2025
9 checks passed
@mizvekov mizvekov deleted the users/mizvekov/clang-print-context-stack-diags-supressed-by-deduction branch February 20, 2025 11:50
mizvekov added a commit that referenced this pull request Feb 20, 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 added a commit that referenced this pull request Feb 20, 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 added a commit that referenced this pull request Feb 20, 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 added a commit that referenced this pull request Mar 1, 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 added a commit that referenced this pull request Mar 6, 2025
…rameters (#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 #125453, which is needed to avoid losing the context
note for errors occuring during template argument deduction.
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.
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 Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants