[clang] [clang][Sema] Improve template argument deduction diagnostic (PR #122754)

Matheus Izvekov via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 20 03:38:23 PST 2025


================
@@ -11714,27 +11714,51 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
     return;
   }
 
-  case TemplateDeductionResult::InvalidExplicitArguments:
+  case TemplateDeductionResult::InvalidExplicitArguments: {
     assert(ParamD && "no parameter found for invalid explicit arguments");
-    if (ParamD->getDeclName())
-      S.Diag(Templated->getLocation(),
-             diag::note_ovl_candidate_explicit_arg_mismatch_named)
-          << ParamD->getDeclName();
-    else {
-      int index = 0;
-      if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ParamD))
-        index = TTP->getIndex();
-      else if (NonTypeTemplateParmDecl *NTTP
-                                  = dyn_cast<NonTypeTemplateParmDecl>(ParamD))
-        index = NTTP->getIndex();
-      else
-        index = cast<TemplateTemplateParmDecl>(ParamD)->getIndex();
-      S.Diag(Templated->getLocation(),
-             diag::note_ovl_candidate_explicit_arg_mismatch_unnamed)
-          << (index + 1);
-    }
+    TemplateArgument FirstArg = *DeductionFailure.getFirstArg();
+    TemplateArgument SecondArg = *DeductionFailure.getSecondArg();
+
+    auto TupleResult = [&]() -> std::tuple<int, int, int, int, QualType> {
+      switch (ParamD->getKind()) {
+      case Decl::TemplateTypeParm: {
+        auto *TTPD = cast<TemplateTypeParmDecl>(ParamD);
+        return {1, 0, 1, TTPD->getIndex(), QualType()};
+      }
+      case Decl::NonTypeTemplateParm: {
+        auto *NTTPD = cast<NonTypeTemplateParmDecl>(ParamD);
+        if (SecondArg.isNull()) {
+          return {1, 1, 0, NTTPD->getIndex(), NTTPD->getType()};
+        } else {
+          // FIXME: This is a hack. We should emit a better message
+          // for ill-formed const exprs in >=C++20.
+          QualType qt = NTTPD->getType();
+          if (qt.getCanonicalType() ==
+              SecondArg.getAsType().getCanonicalType()) {
+            return {3, -1, -1, NTTPD->getIndex(), NTTPD->getType()};
+          } else {
+            return {2, -1, -1, NTTPD->getIndex(), NTTPD->getType()};
+          }
+        }
+      }
+      case Decl::TemplateTemplateParm: {
+        auto *TTempPD = cast<TemplateTemplateParmDecl>(ParamD);
+        return {3, -1, -1, TTempPD->getIndex(), QualType()};
+      }
+      default:
+        llvm_unreachable("unexpected param decl kind");
+      }
+    };
+    auto [Which, Provided, Expected, Index, Type] = TupleResult();
+    S.NoteTemplateParameterLocation(*ParamD);
+    S.Diag(Templated->getLocation(),
+           diag::note_ovl_candidate_explicit_arg_mismatch)
+        << Which << Provided << Expected << FirstArg << SecondArg << Type
+        << (Index + 1);
----------------
mizvekov wrote:

```suggestion
    S.Diag(Templated->getLocation(),
           diag::note_ovl_candidate_explicit_arg_mismatch)
        << Which << Provided << Expected << FirstArg << SecondArg << Type
        << (Index + 1);
    S.NoteTemplateParameterLocation(*ParamD);
```

The note must always come after the error, otherwise it becomes attached to whatever diagnostic we emitted previously.

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


More information about the cfe-commits mailing list