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

Aidan Goldfarb via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 15 13:51:39 PST 2025


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

>From b6c576fb90362640b2fd4e41bd7f13dfee95d04d Mon Sep 17 00:00:00 2001
From: Aidan <aidan.goldfarb at mail.mcgill.ca>
Date: Mon, 13 Jan 2025 11:53:39 -0500
Subject: [PATCH 1/3] initial template arg fix push

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 +-
 clang/include/clang/Sema/TemplateDeduction.h  |  5 ++
 clang/lib/Sema/SemaOverload.cpp               | 56 +++++++++++++++----
 clang/lib/Sema/SemaTemplateDeduction.cpp      |  8 +++
 4 files changed, 61 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8be4f946dce1cc..1456f34538bcc0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4871,8 +4871,8 @@ def note_ovl_candidate_inconsistent_deduction_types : Note<
     "of conflicting types for parameter %0 (%1 of type $ vs. %3 of type $)|"
     "%1 and %3 of conflicting types for parameter %0}2,4">;
 def note_ovl_candidate_explicit_arg_mismatch_named : Note<
-    "candidate template ignored: invalid explicitly-specified argument "
-    "for template parameter %0">;
+    "template argument deduction/substitution failed:" 
+    "error: could not convert '%0' from %1 to %2">;
 def note_ovl_candidate_unsatisfied_constraints : Note<
     "candidate template ignored: constraints not satisfied%0">;
 def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note<
diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h
index 28b014fd84e4b3..9edd3724cf53cd 100644
--- a/clang/include/clang/Sema/TemplateDeduction.h
+++ b/clang/include/clang/Sema/TemplateDeduction.h
@@ -250,6 +250,9 @@ class TemplateDeductionInfo {
   /// \brief The constraint satisfaction details resulting from the associated
   /// constraints satisfaction tests.
   ConstraintSatisfaction AssociatedConstraintsSatisfaction;
+
+  /// \brief Type supplied by user for deduction
+  TemplateArgument SuppliedType;
 };
 
 } // namespace sema
@@ -300,6 +303,8 @@ struct DeductionFailureInfo {
   TemplateDeductionResult getResult() const {
     return static_cast<TemplateDeductionResult>(Result);
   }
+
+  const TemplateArgument *getSuppliedType();
 };
 
 /// TemplateSpecCandidate - This is a generalization of OverloadCandidate
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 34c287926b1d7d..6c437a52be21db 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -715,12 +715,18 @@ namespace {
   struct DFIParamWithArguments : DFIArguments {
     TemplateParameter Param;
   };
+
   // Structure used by DeductionFailureInfo to store template argument
   // information and the index of the problematic call argument.
   struct DFIDeducedMismatchArgs : DFIArguments {
     TemplateArgumentList *TemplateArgs;
     unsigned CallArgIndex;
   };
+
+  struct DFIParamWithArgumentsAndSuppliedType : DFIArguments {
+    TemplateParameter Param;
+    TemplateArgument SuppliedType;
+  };
   // Structure used by DeductionFailureInfo to store information about
   // unsatisfied constraints.
   struct CNSInfo {
@@ -736,8 +742,10 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
                                 TemplateDeductionResult TDK,
                                 TemplateDeductionInfo &Info) {
   DeductionFailureInfo Result;
+
   Result.Result = static_cast<unsigned>(TDK);
   Result.HasDiagnostic = false;
+
   switch (TDK) {
   case TemplateDeductionResult::Invalid:
   case TemplateDeductionResult::InstantiationDepth:
@@ -749,10 +757,9 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
     break;
 
   case TemplateDeductionResult::Incomplete:
-  case TemplateDeductionResult::InvalidExplicitArguments:
+    // case TemplateDeductionResult::InvalidExplicitArguments:
     Result.Data = Info.Param.getOpaqueValue();
     break;
-
   case TemplateDeductionResult::DeducedMismatch:
   case TemplateDeductionResult::DeducedMismatchNested: {
     // FIXME: Should allocate from normal heap so that we can free this later.
@@ -777,6 +784,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
   case TemplateDeductionResult::IncompletePack:
     // FIXME: It's slightly wasteful to allocate two TemplateArguments for this.
   case TemplateDeductionResult::Inconsistent:
+
   case TemplateDeductionResult::Underqualified: {
     // FIXME: Should allocate from normal heap so that we can free this later.
     DFIParamWithArguments *Saved = new (Context) DFIParamWithArguments;
@@ -786,6 +794,16 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
     Result.Data = Saved;
     break;
   }
+  case TemplateDeductionResult::InvalidExplicitArguments: {
+    DFIParamWithArgumentsAndSuppliedType *Saved =
+        new (Context) DFIParamWithArgumentsAndSuppliedType;
+    Saved->Param = Info.Param;
+    Saved->FirstArg = Info.FirstArg;
+    Saved->SecondArg = Info.SecondArg;
+    Saved->SuppliedType = Info.SuppliedType;
+    Result.Data = Saved;
+    break;
+  }
 
   case TemplateDeductionResult::SubstitutionFailure:
     Result.Data = Info.takeSugared();
@@ -822,13 +840,14 @@ void DeductionFailureInfo::Destroy() {
   case TemplateDeductionResult::Incomplete:
   case TemplateDeductionResult::TooManyArguments:
   case TemplateDeductionResult::TooFewArguments:
-  case TemplateDeductionResult::InvalidExplicitArguments:
+  // case TemplateDeductionResult::InvalidExplicitArguments:
   case TemplateDeductionResult::CUDATargetMismatch:
   case TemplateDeductionResult::NonDependentConversionFailure:
     break;
 
   case TemplateDeductionResult::IncompletePack:
   case TemplateDeductionResult::Inconsistent:
+  case TemplateDeductionResult::InvalidExplicitArguments:
   case TemplateDeductionResult::Underqualified:
   case TemplateDeductionResult::DeducedMismatch:
   case TemplateDeductionResult::DeducedMismatchNested:
@@ -885,11 +904,11 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() {
     return TemplateParameter();
 
   case TemplateDeductionResult::Incomplete:
-  case TemplateDeductionResult::InvalidExplicitArguments:
     return TemplateParameter::getFromOpaqueValue(Data);
 
   case TemplateDeductionResult::IncompletePack:
   case TemplateDeductionResult::Inconsistent:
+  case TemplateDeductionResult::InvalidExplicitArguments:
   case TemplateDeductionResult::Underqualified:
     return static_cast<DFIParamWithArguments*>(Data)->Param;
 
@@ -938,6 +957,16 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
   return nullptr;
 }
 
+const TemplateArgument *DeductionFailureInfo::getSuppliedType() {
+  switch (static_cast<TemplateDeductionResult>(Result)) {
+  case TemplateDeductionResult::InvalidExplicitArguments:
+    return &static_cast<DFIParamWithArgumentsAndSuppliedType *>(Data)
+                ->SuppliedType;
+  default:
+    return nullptr;
+  }
+}
+
 const TemplateArgument *DeductionFailureInfo::getFirstArg() {
   switch (static_cast<TemplateDeductionResult>(Result)) {
   case TemplateDeductionResult::Success:
@@ -946,15 +975,17 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
   case TemplateDeductionResult::Incomplete:
   case TemplateDeductionResult::TooManyArguments:
   case TemplateDeductionResult::TooFewArguments:
-  case TemplateDeductionResult::InvalidExplicitArguments:
+  // case TemplateDeductionResult::InvalidExplicitArguments:
   case TemplateDeductionResult::SubstitutionFailure:
   case TemplateDeductionResult::CUDATargetMismatch:
   case TemplateDeductionResult::NonDependentConversionFailure:
   case TemplateDeductionResult::ConstraintsNotSatisfied:
     return nullptr;
-
+  // case TemplateDeductionResult::InvalidExplicitArguments: //move back up
+  // there^^
   case TemplateDeductionResult::IncompletePack:
   case TemplateDeductionResult::Inconsistent:
+  case TemplateDeductionResult::InvalidExplicitArguments:
   case TemplateDeductionResult::Underqualified:
   case TemplateDeductionResult::DeducedMismatch:
   case TemplateDeductionResult::DeducedMismatchNested:
@@ -979,7 +1010,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
   case TemplateDeductionResult::IncompletePack:
   case TemplateDeductionResult::TooManyArguments:
   case TemplateDeductionResult::TooFewArguments:
-  case TemplateDeductionResult::InvalidExplicitArguments:
+  // case TemplateDeductionResult::InvalidExplicitArguments:
   case TemplateDeductionResult::SubstitutionFailure:
   case TemplateDeductionResult::CUDATargetMismatch:
   case TemplateDeductionResult::NonDependentConversionFailure:
@@ -987,6 +1018,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
     return nullptr;
 
   case TemplateDeductionResult::Inconsistent:
+  case TemplateDeductionResult::InvalidExplicitArguments:
   case TemplateDeductionResult::Underqualified:
   case TemplateDeductionResult::DeducedMismatch:
   case TemplateDeductionResult::DeducedMismatchNested:
@@ -11613,6 +11645,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
   (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) ||
   (ParamD = Param.dyn_cast<NonTypeTemplateParmDecl*>()) ||
   (ParamD = Param.dyn_cast<TemplateTemplateParmDecl*>());
+
   switch (DeductionFailure.getResult()) {
   case TemplateDeductionResult::Success:
     llvm_unreachable(
@@ -11716,11 +11749,14 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
 
   case TemplateDeductionResult::InvalidExplicitArguments:
     assert(ParamD && "no parameter found for invalid explicit arguments");
-    if (ParamD->getDeclName())
+    if (ParamD->getDeclName()) {
+      auto FirstArg = *DeductionFailure.getFirstArg();
+      auto SecondArg = *DeductionFailure.getSecondArg();
+      auto SuppliedType = *DeductionFailure.getSuppliedType();
       S.Diag(Templated->getLocation(),
              diag::note_ovl_candidate_explicit_arg_mismatch_named)
-          << ParamD->getDeclName();
-    else {
+          << FirstArg << SuppliedType << SecondArg;
+    } else {
       int index = 0;
       if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ParamD))
         index = TTP->getIndex();
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 1c1f6e30ab7b83..92415d49ee7a49 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3575,7 +3575,15 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments(
     unsigned Index = SugaredBuilder.size();
     if (Index >= TemplateParams->size())
       return TemplateDeductionResult::SubstitutionFailure;
+
     Info.Param = makeTemplateParameter(TemplateParams->getParam(Index));
+    Info.FirstArg = ExplicitTemplateArgs[Index].getArgument();
+    Info.SecondArg = TemplateArgument(
+        dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(Index))
+            ->getType());
+    Info.SuppliedType = TemplateArgument(
+        ExplicitTemplateArgs[Index].getSourceExpression()->getType());
+
     return TemplateDeductionResult::InvalidExplicitArguments;
   }
 

>From e3a60c1f0adbf1801d51ab4d7834469349c0382a Mon Sep 17 00:00:00 2001
From: Aidan <aidan.goldfarb at mail.mcgill.ca>
Date: Tue, 14 Jan 2025 11:41:17 -0500
Subject: [PATCH 2/3] Improved safety, added some rt checks

---
 clang/lib/Sema/SemaTemplateDeduction.cpp | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 92415d49ee7a49..521e0da3ef2f92 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -766,6 +766,12 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
 
   return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
 }
+// Helper function to make template argument
+static TemplateArgument makeTemplateArgument(Decl *D) {
+  if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
+    return TemplateArgument(NTTP->getType());
+  return TemplateArgument();
+}
 
 /// A pack that we're currently deducing.
 struct clang::DeducedPack {
@@ -3578,11 +3584,19 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments(
 
     Info.Param = makeTemplateParameter(TemplateParams->getParam(Index));
     Info.FirstArg = ExplicitTemplateArgs[Index].getArgument();
-    Info.SecondArg = TemplateArgument(
-        dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(Index))
-            ->getType());
-    Info.SuppliedType = TemplateArgument(
-        ExplicitTemplateArgs[Index].getSourceExpression()->getType());
+    Info.SecondArg = makeTemplateArgument(TemplateParams->getParam(Index));
+    // Info.SecondArg = TemplateArgument(
+    //     dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(Index))
+    //         ->getType());
+
+    // NonTypeTemplateParmDecl tmp =
+    // makeTemplateArgument(TemplateParams->getParam(Index)); if(!tmp.isNull()){
+    //   Info.SecondArg = tmp->getType();
+    // }
+    if (ExplicitTemplateArgs[Index].getArgument().getKind() ==
+        TemplateArgument::Expression)
+      Info.SuppliedType = TemplateArgument(
+          ExplicitTemplateArgs[Index].getSourceExpression()->getType());
 
     return TemplateDeductionResult::InvalidExplicitArguments;
   }

>From 86d44be78faaac1439977ea0ae2f8a213ca28aa3 Mon Sep 17 00:00:00 2001
From: Aidan <aidan.goldfarb at mail.mcgill.ca>
Date: Wed, 15 Jan 2025 16:51:10 -0500
Subject: [PATCH 3/3] Fixed error message formatting

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1456f34538bcc0..0afba2ad681319 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4871,8 +4871,8 @@ def note_ovl_candidate_inconsistent_deduction_types : Note<
     "of conflicting types for parameter %0 (%1 of type $ vs. %3 of type $)|"
     "%1 and %3 of conflicting types for parameter %0}2,4">;
 def note_ovl_candidate_explicit_arg_mismatch_named : Note<
-    "template argument deduction/substitution failed:" 
-    "error: could not convert '%0' from %1 to %2">;
+    "candidate template ignored: invalid explicitly-specified argument "
+    "could not convert '%0' from %1 to %2">;
 def note_ovl_candidate_unsatisfied_constraints : Note<
     "candidate template ignored: constraints not satisfied%0">;
 def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note<



More information about the cfe-commits mailing list