[clang] 3b639d7 - [Clang] Clarify diagnostic notes for implicitly generated deduction guides (#96084)

via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 2 04:34:51 PDT 2024


Author: Younan Zhang
Date: 2024-07-02T19:34:48+08:00
New Revision: 3b639d7d1d9b9f352c57460deaf70aaad238f8d9

URL: https://github.com/llvm/llvm-project/commit/3b639d7d1d9b9f352c57460deaf70aaad238f8d9
DIFF: https://github.com/llvm/llvm-project/commit/3b639d7d1d9b9f352c57460deaf70aaad238f8d9.diff

LOG: [Clang] Clarify diagnostic notes for implicitly generated deduction guides (#96084)

Given the following invalid code,
```cpp
template <class T>
struct S {
  T *a;
};
S s = {1};
```
we produce such diagnostics currently:
```
<source>:2:8: note: candidate template ignored: could not match 'S<T>' against 'int'
    2 | struct S {
      |        ^
<source>:2:8: note: candidate template ignored: could not match 'T *' against 'int'
```
Which I think is confusing because there's no `S<T>` nor `T *` at the
location it points to. This is because we're deducing the initializer
against implicitly generated deduction guides, and their source
locations just point to the corresponding `RecordDecl`. Hence the
misleading notes.

This patch alleviates the issue by adding extra notes demonstrating
which implicit deduction guide we're deducing against. In other words,
in addition to the note of `could not match 'T *' against 'int'`, we
would also say the implicit deduction guide we're trying to use:
`template <class T> S(T *) -> S<T>`, which looks clearer IMO.

---------

Co-authored-by: Sirraide <aeternalmail at gmail.com>

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaOverload.cpp
    clang/test/CXX/drs/cwg26xx.cpp
    clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
    clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
    clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
    clang/test/Modules/template_name_lookup.cpp
    clang/test/PCH/cxx-explicit-specifier.cpp
    clang/test/Sema/tls_alignment.cpp
    clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
    clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
    clang/test/SemaCXX/cxx2a-explicit-bool.cpp
    clang/test/SemaCXX/gh65522.cpp
    clang/test/SemaCXX/invalid-deduction-guide-as-template-candidates.cpp
    clang/test/SemaCXX/lookup-template-name-extern-CXX.cpp
    clang/test/SemaTemplate/aggregate-deduction-candidate.cpp
    clang/test/SemaTemplate/class-template-id.cpp
    clang/test/SemaTemplate/ctad.cpp
    clang/test/SemaTemplate/deduction-crash.cpp
    clang/test/SemaTemplate/deduction-guide.cpp
    clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
    clang/test/SemaTemplate/temp_arg.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e4707bf15bb6c..9741730604441 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -651,6 +651,8 @@ Improvements to Clang's diagnostics
   that will be destroyed at the end of the full expression.
   Fixes #GH54492.
 
+- Clang now shows implicit deduction guides when diagnosing overload resolution failure. #GH92393.
+
 Improvements to Clang's time-trace
 ----------------------------------
 

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 64f7935d25d65..c852f1893fe14 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2419,6 +2419,7 @@ def err_selected_explicit_constructor : Error<
   "chosen constructor is explicit in copy-initialization">;
 def note_explicit_ctor_deduction_guide_here : Note<
   "explicit %select{constructor|deduction guide}0 declared here">;
+def note_implicit_deduction_guide : Note<"implicit deduction guide declared as '%0'">;
 
 // C++11 auto
 def warn_cxx98_compat_auto_type_specifier : Warning<

diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 982cca61c3d6b..5ea6b06121c7c 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -40,6 +40,7 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/STLForwardCompat.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
@@ -11884,6 +11885,46 @@ static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
       << (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange());
 }
 
+static void NoteImplicitDeductionGuide(Sema &S, FunctionDecl *Fn) {
+  auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
+  if (!DG)
+    return;
+  TemplateDecl *OriginTemplate =
+      DG->getDeclName().getCXXDeductionGuideTemplate();
+  // We want to always print synthesized deduction guides for type aliases.
+  // They would retain the explicit bit of the corresponding constructor.
+  if (!(DG->isImplicit() || (OriginTemplate && OriginTemplate->isTypeAlias())))
+    return;
+  std::string FunctionProto;
+  llvm::raw_string_ostream OS(FunctionProto);
+  FunctionTemplateDecl *Template = DG->getDescribedFunctionTemplate();
+  if (!Template) {
+    // This also could be an instantiation. Find out the primary template.
+    FunctionDecl *Pattern =
+        DG->getTemplateInstantiationPattern(/*ForDefinition=*/false);
+    if (!Pattern) {
+      // The implicit deduction guide is built on an explicit non-template
+      // deduction guide. Currently, this might be the case only for type
+      // aliases.
+      // FIXME: Add a test once https://github.com/llvm/llvm-project/pull/96686
+      // gets merged.
+      assert(OriginTemplate->isTypeAlias() &&
+             "Non-template implicit deduction guides are only possible for "
+             "type aliases");
+      DG->print(OS);
+      S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
+          << FunctionProto;
+      return;
+    }
+    Template = Pattern->getDescribedFunctionTemplate();
+    assert(Template && "Cannot find the associated function template of "
+                       "CXXDeductionGuideDecl?");
+  }
+  Template->print(OS);
+  S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
+      << FunctionProto;
+}
+
 /// Generates a 'note' diagnostic for an overload candidate.  We've
 /// already generated a primary error at the call site.
 ///
@@ -11941,6 +11982,17 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
     return;
   }
 
+  // If this is a synthesized deduction guide we're deducing against, add a note
+  // for it. These deduction guides are not explicitly spelled in the source
+  // code, so simply printing a deduction failure note mentioning synthesized
+  // template parameters or pointing to the header of the surrounding RecordDecl
+  // would be confusing.
+  //
+  // We prefer adding such notes at the end of the deduction failure because
+  // duplicate code snippets appearing in the diagnostic would likely become
+  // noisy.
+  auto _ = llvm::make_scope_exit([&] { NoteImplicitDeductionGuide(S, Fn); });
+
   switch (Cand->FailureKind) {
   case ovl_fail_too_many_arguments:
   case ovl_fail_too_few_arguments:

diff  --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index e180c93011a7e..d843b09ee075a 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -193,8 +193,11 @@ static_assert(__is_same(decltype(i), I<char, 4>));
 J j = { "ghi" };
 // since-cxx20-error at -1 {{no viable constructor or deduction guide}}
 //   since-cxx20-note@#cwg2681-J {{candidate template ignored: could not match 'J<N>' against 'const char *'}}
+//   since-cxx20-note@#cwg2681-J {{implicit deduction guide declared as 'template <size_t N> J(J<N>) -> J<N>'}}
 //   since-cxx20-note@#cwg2681-J {{candidate template ignored: could not match 'const unsigned char' against 'const char'}}
+//   since-cxx20-note@#cwg2681-J {{implicit deduction guide declared as 'template <size_t N> J(const unsigned char (&)[N]) -> J<N>'}}
 //   since-cxx20-note@#cwg2681-J {{candidate function template not viable: requires 0 arguments, but 1 was provided}}
+//   since-cxx20-note@#cwg2681-J {{implicit deduction guide declared as 'template <size_t N> J() -> J<N>'}}
 #endif
 }
 

diff  --git a/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp b/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
index f3608bc378bc7..f8d88e13fce31 100644
--- a/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
+++ b/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -std=c++1z -verify %s
 
-template<typename T> struct A { // expected-note 2{{candidate}}
+template<typename T> struct A { // expected-note 2{{candidate}} expected-note 2{{implicit deduction guide}}
   T t, u;
 };
 template<typename T> A(T, T) -> A<T>; // expected-note {{deduced conflicting types for parameter 'T'}}

diff  --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
index 49fde292f6a36..d192070132d78 100644
--- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
+++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
@@ -35,8 +35,9 @@ namespace std {
 }
 
 namespace p0702r1 {
-  template<typename T> struct X { // expected-note {{candidate}}
-    X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'std::initializer_list<T>' against 'Z'}}
+  template<typename T> struct X { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
+    X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'std::initializer_list<T>' against 'Z'}} \
+                                 // expected-note {{implicit deduction guide declared as 'template <typename T> X(std::initializer_list<T>) -> X<T>'}}
   };
 
   X xi = {0};

diff  --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
index 8592626269eed..ed445360c4fdd 100644
--- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
+++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
@@ -6,8 +6,8 @@
 #if __cplusplus > 201402L
 namespace ClassTemplateParamNotForwardingRef {
   // This is not a forwarding reference.
-  template<typename T> struct A { // expected-note {{candidate}}
-    A(T&&); // expected-note {{expects an rvalue}}
+  template<typename T> struct A { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
+    A(T&&); // expected-note {{expects an rvalue}} expected-note {{implicit deduction guide}}
   };
   int n;
   A a = n; // expected-error {{no viable constructor or deduction guide}}
@@ -75,10 +75,12 @@ namespace std_example {
   int n3 = g(i); // expected-error{{no matching function for call to 'g'}}
 
 #if __cplusplus > 201402L
-  template<class T> struct A { // expected-note {{candidate}}
+  template<class T> struct A { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
     template<class U>
-    A(T &&, U &&, int *); // expected-note {{[with T = int, U = int] not viable: expects an rvalue}}
-    A(T &&, int *);       // expected-note {{requires 2}}
+    A(T &&, U &&, int *); // expected-note {{[with T = int, U = int] not viable: expects an rvalue}} \
+                          // expected-note {{implicit deduction guide declared as 'template <class T, class U> A(T &&, type-parameter-0-1 &&, int *) -> A<T>'}}
+    A(T &&, int *);       // expected-note {{requires 2}} \
+                          // expected-note {{implicit deduction guide declared as 'template <class T> A(T &&, int *) -> A<T>'}}
   };
   template<class T> A(T &&, int *) -> A<T>; // expected-note {{requires 2}}
 

diff  --git a/clang/test/Modules/template_name_lookup.cpp b/clang/test/Modules/template_name_lookup.cpp
index 29375e514025f..82b06e83afce3 100644
--- a/clang/test/Modules/template_name_lookup.cpp
+++ b/clang/test/Modules/template_name_lookup.cpp
@@ -7,5 +7,7 @@ import foo;
 void use() {
   X x; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'X'}}
        // expected-note at Inputs/template_name_lookup/foo.cppm:3 {{candidate template ignored: couldn't infer template argument 'T'}}
+       // expected-note at Inputs/template_name_lookup/foo.cppm:3 {{implicit deduction guide declared as 'template <typename T> X(X<T>) -> X<T>'}}
        // expected-note at Inputs/template_name_lookup/foo.cppm:3 {{candidate function template not viable: requires 1 argument, but 0 were provided}}
+       // expected-note at Inputs/template_name_lookup/foo.cppm:3 {{implicit deduction guide declared as 'template <typename T> X() -> X<T>'}}
 }

diff  --git a/clang/test/PCH/cxx-explicit-specifier.cpp b/clang/test/PCH/cxx-explicit-specifier.cpp
index 94ca9f7b080db..84548faf48810 100644
--- a/clang/test/PCH/cxx-explicit-specifier.cpp
+++ b/clang/test/PCH/cxx-explicit-specifier.cpp
@@ -79,8 +79,8 @@ struct A {
 B<true> b_true;
 B<false> b_false;
 #else
-//expected-note at -8 {{candidate template ignored}}
-//expected-note at -8 {{explicit constructor declared here}}
+//expected-note at -8 {{candidate template ignored}} expected-note at -8 {{implicit deduction guide declared as 'template <bool b> A(A<b>) -> A<b>'}}
+//expected-note at -8 {{explicit constructor declared here}} expected-note at -8 {{implicit deduction guide declared as 'template <bool b> explicit(b) A(B<b>) -> A<b>'}}
 //expected-note at -15+ {{candidate constructor}}
 //expected-note at -8+ {{explicit conversion function is not a candidate (explicit specifier}}
 //expected-note at -11 {{explicit constructor is not a candidate (explicit specifier}}

diff  --git a/clang/test/Sema/tls_alignment.cpp b/clang/test/Sema/tls_alignment.cpp
index c5c79aafa9ead..65b6b035e7917 100644
--- a/clang/test/Sema/tls_alignment.cpp
+++ b/clang/test/Sema/tls_alignment.cpp
@@ -22,7 +22,9 @@ struct  struct_with_aligned_field {
 template <typename>
 struct templated_struct {};
 // expected-note at -1{{candidate template ignored: couldn't infer template argument ''}}
-// expected-note at -2{{candidate function template not viable: requires 1 argument, but 0 were provided}}
+// expected-note at -2{{implicit deduction guide declared as 'template <typename> templated_struct() -> templated_struct<type-parameter-0-0>'}}
+// expected-note at -3{{candidate function template not viable: requires 1 argument, but 0 were provided}}
+// expected-note at -4{{implicit deduction guide declared as 'template <typename> templated_struct(templated_struct<type-parameter-0-0>) -> templated_struct<type-parameter-0-0>'}}
 
 // A typedef of the aligned struct.
 typedef aligned_struct another_aligned_struct;

diff  --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 90404f115c75f..9ef5303a9c4df 100644
--- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -139,11 +139,13 @@ namespace look_into_current_instantiation {
                     // templates, and members of the current instantiation
   A<float> &r = a;
 
-  template<typename T> struct B { // expected-note {{could not match 'B<T>' against 'int'}}
+  template<typename T> struct B { // expected-note {{could not match 'B<T>' against 'int'}} \
+                                  // expected-note {{implicit deduction guide declared as 'template <typename T> B(B<T>) -> B<T>'}}
     struct X {
       typedef T type;
     };
-    B(typename X::type); // expected-note {{couldn't infer template argument 'T'}}
+    B(typename X::type); // expected-note {{couldn't infer template argument 'T'}} \
+                         // expected-note {{implicit deduction guide declared as 'template <typename T> B(typename X::type) -> B<T>'}}
   };
   B b = 0; // expected-error {{no viable}}
 
@@ -564,8 +566,10 @@ namespace PR47175 {
 
 // Ensure we don't crash when CTAD fails.
 template <typename T1, typename T2>
-struct Foo {   // expected-note{{candidate function template not viable}}
-  Foo(T1, T2); // expected-note{{candidate function template not viable}}
+struct Foo {   // expected-note {{candidate function template not viable}} \
+               // expected-note {{implicit deduction guide declared as 'template <typename T1, typename T2> Foo(Foo<T1, T2>) -> Foo<T1, T2>'}}
+  Foo(T1, T2); // expected-note {{candidate function template not viable}} \
+               // expected-note {{implicit deduction guide declared as 'template <typename T1, typename T2> Foo(T1, T2) -> Foo<T1, T2>'}}
 };
 
 template <typename... Args>

diff  --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index b71dfc6ccaf4f..3dafe823fbbaa 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -110,6 +110,8 @@ struct Foo {
 
 template <typename X, int Y>
 using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \
+                               // expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) Bar(Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
+                               // expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) Bar(const type-parameter-0-0 (&)[sizeof(type-parameter-0-0)]) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
                                // expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \
                                // expected-note {{cannot deduce template arguments for 'Bar' from 'Foo<int, 4UL>'}}
 
@@ -137,9 +139,12 @@ struct A {};
 template<class T> struct Foo { T c; };
 template<class X, class Y=A>
 using AFoo = Foo<Y>; // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0>' against 'int'}} \
+                    // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<type-parameter-0-0>) AFoo(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
                     // expected-note {{candidate template ignored: constraints not satisfied [with Y = int]}} \
                     // expected-note {{cannot deduce template arguments for 'AFoo' from 'Foo<int>'}} \
-                    // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}}
+                    // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<type-parameter-0-0>) AFoo(type-parameter-0-0) -> Foo<type-parameter-0-0>'}} \
+                    // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
+                    // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<type-parameter-0-0>) AFoo() -> Foo<type-parameter-0-0>'}}
 
 AFoo s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'AFoo'}}
 } // namespace test11
@@ -192,6 +197,8 @@ struct Foo {
 template <int K>
 using Bar = Foo<double, K>; // expected-note {{constraints not satisfied for class template 'Foo'}}
 // expected-note at -1 {{candidate template ignored: could not match}}
+// expected-note at -2 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(Foo<double, K>) -> Foo<double, K>'}}
+// expected-note at -3 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(const double (&)[K]) -> Foo<double, K>'}}
 double abc[3];
 Bar s2 = {abc}; // expected-error {{no viable constructor or deduction guide for deduction }}
 } // namespace test14
@@ -204,7 +211,9 @@ template<typename> concept False = false;
 template<False W>
 using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with V = int]}} \
                       // expected-note {{cannot deduce template arguments for 'BFoo' from 'Foo<int *>'}} \
-                      // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}}
+                      // expected-note {{implicit deduction guide declared as 'template <class V> requires __is_deducible(AFoo, Foo<type-parameter-0-0 *>) && __is_deducible(test15::BFoo, Foo<type-parameter-0-0 *>) BFoo(type-parameter-0-0 *) -> Foo<type-parameter-0-0 *>}} \
+                      // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}} \
+                      // expected-note {{template <class V> requires __is_deducible(AFoo, Foo<type-parameter-0-0 *>) && __is_deducible(test15::BFoo, Foo<type-parameter-0-0 *>) BFoo(Foo<type-parameter-0-0 *>) -> Foo<type-parameter-0-0 *>}}
 int i = 0;
 AFoo a1(&i); // OK, deduce Foo<int *>
 
@@ -255,8 +264,11 @@ Foo(T) -> Foo<int>;
 
 template <typename U>
 using Bar = Foo<U>; // expected-note {{could not match 'Foo<type-parameter-0-0>' against 'int'}} \
+                    // expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<type-parameter-0-0>) Bar(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
                     // expected-note {{candidate template ignored: constraints not satisfied}} \
-                    // expected-note {{candidate function template not viable}}
+                    // expected-note {{implicit deduction guide declared as 'template <typename T> requires False<T> && __is_deducible(test18::Bar, Foo<int>) Bar(type-parameter-0-0) -> Foo<int>'}} \
+                    // expected-note {{candidate function template not viable}} \
+                    // expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<type-parameter-0-0>) Bar() -> Foo<type-parameter-0-0>'}}
 
 Bar s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
 } // namespace test18
@@ -284,7 +296,8 @@ class Foo {};
 // Verify that template template type parameter TTP is referenced/used in the
 // template arguments of the RHS.
 template <template<typename> typename TTP>
-using Bar = Foo<K<TTP>>; // expected-note {{candidate template ignored: could not match 'Foo<K<template-parameter-0-0>>' against 'int'}}
+using Bar = Foo<K<TTP>>; // expected-note {{candidate template ignored: could not match 'Foo<K<template-parameter-0-0>>' against 'int'}} \
+                        // expected-note {{implicit deduction guide declared as 'template <template <typename> typename TTP> requires __is_deducible(test20::Bar, Foo<K<template-parameter-0-0>>) Bar(Foo<K<template-parameter-0-0>>) -> Foo<K<template-parameter-0-0>>'}}
 
 template <class T>
 class Container {};

diff  --git a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
index 9fdc059493aac..03799c52654a5 100644
--- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
+++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -394,9 +394,11 @@ using type = T;
 template<typename T1, typename T2, bool b>
 struct A {
   // expected-note at -1+ {{candidate function}}
+  // expected-note at -2+ {{implicit deduction guide}}
   explicit(false)
   A(typename nondeduced<T1>::type, typename nondeduced<T2>::type, typename nondeduced<B<b>>::type) {}
   // expected-note at -1+ {{candidate template ignored}}
+  // expected-note at -2+ {{implicit deduction guide}}
 };
 
 template<typename T1, typename T2, bool b>
@@ -678,10 +680,12 @@ namespace deduction_guide2 {
 template<typename T1 = int, typename T2 = int>
 struct A {
   // expected-note at -1+ {{candidate template ignored}}
+  // expected-note at -2+ {{implicit deduction guide}}
   explicit(!is_same<T1, T2>::value)
   A(T1 = 0, T2 = 0) {}
   // expected-note at -1 {{explicit constructor declared here}}
   // expected-note at -2 2{{explicit constructor is not a candidate}}
+  // expected-note at -3 2{{implicit deduction guide declared}}
 };
 
 A a0 = 0;

diff  --git a/clang/test/SemaCXX/gh65522.cpp b/clang/test/SemaCXX/gh65522.cpp
index 2d6331b0372a3..80281248c6d49 100644
--- a/clang/test/SemaCXX/gh65522.cpp
+++ b/clang/test/SemaCXX/gh65522.cpp
@@ -3,9 +3,11 @@
 class X {};
 
 template<typename T>
-class B3 { // expected-note {{candidate template ignored: could not match 'B3<T>' against 'int'}}
+class B3 { // expected-note {{candidate template ignored: could not match 'B3<T>' against 'int'}} \
+           // expected-note {{implicit deduction guide declared as 'template <typename T> B3(B3<T>) -> B3<T>'}}
   template<X x> B3(T); // expected-warning 2{{non-type template parameter of type 'X' is incompatible with C++ standards before C++20}} \
-                       // expected-note {{candidate template ignored: couldn't infer template argument 'x'}}
+                       // expected-note {{candidate template ignored: couldn't infer template argument 'x'}} \
+                       // expected-note {{implicit deduction guide declared as 'template <typename T, X x> B3(T) -> B3<T>'}}
 };
 B3 b3 = 0; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'B3'}} \
            // expected-note {{while building implicit deduction guide first needed here}}

diff  --git a/clang/test/SemaCXX/invalid-deduction-guide-as-template-candidates.cpp b/clang/test/SemaCXX/invalid-deduction-guide-as-template-candidates.cpp
index e9b362d67cd23..ad7441ff48477 100644
--- a/clang/test/SemaCXX/invalid-deduction-guide-as-template-candidates.cpp
+++ b/clang/test/SemaCXX/invalid-deduction-guide-as-template-candidates.cpp
@@ -1,6 +1,8 @@
 // RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
 
 template <class T> class Foo {}; // expected-note {{candidate template ignored: couldn't infer template argument 'T'}} \
-                                 // expected-note {{candidate function template not viable: requires 1 argument, but 0 were provided}}
+                                 // expected-note {{implicit deduction guide declared as 'template <class T> Foo(Foo<T>) -> Foo<T>'}} \
+                                 // expected-note {{candidate function template not viable: requires 1 argument, but 0 were provided}} \
+                                 // expected-note {{implicit deduction guide declared as 'template <class T> Foo() -> Foo<T>'}}
 Foo(); // expected-error {{deduction guide declaration without trailing return type}}
 Foo vs; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'Foo'}}

diff  --git a/clang/test/SemaCXX/lookup-template-name-extern-CXX.cpp b/clang/test/SemaCXX/lookup-template-name-extern-CXX.cpp
index 93e7fb6199354..f851af7ecec26 100644
--- a/clang/test/SemaCXX/lookup-template-name-extern-CXX.cpp
+++ b/clang/test/SemaCXX/lookup-template-name-extern-CXX.cpp
@@ -3,8 +3,10 @@
 // RUN: %clang_cc1 -std=c++20 %s -fsyntax-only -verify
 extern "C++" {
 template <class T>
-class X {}; // expected-note {{candidate template ignored: couldn't infer template argument 'T'}}
-            // expected-note at -1 {{candidate function template not viable: requires 1 argument, but 0 were provided}}
+class X {}; // expected-note {{candidate template ignored: couldn't infer template argument 'T'}} \
+            // expected-note {{implicit deduction guide declared as 'template <class T> X(X<T>) -> X<T>'}} \
+            // expected-note {{candidate function template not viable: requires 1 argument, but 0 were provided}} \
+            // expected-note {{implicit deduction guide declared as 'template <class T> X() -> X<T>'}}
 }
 
 void foo() {

diff  --git a/clang/test/SemaTemplate/aggregate-deduction-candidate.cpp b/clang/test/SemaTemplate/aggregate-deduction-candidate.cpp
index 5a50332d73307..49afb6b860620 100644
--- a/clang/test/SemaTemplate/aggregate-deduction-candidate.cpp
+++ b/clang/test/SemaTemplate/aggregate-deduction-candidate.cpp
@@ -2,7 +2,7 @@
 // RUN: %clang_cc1 -std=c++20 -verify=expected,cxx20 -ast-dump -ast-dump-decl-types -ast-dump-filter "deduction guide" %s | FileCheck %s --strict-whitespace
 
 namespace Basic {
-  template<class T> struct A { // cxx17-note 6 {{candidate}}
+  template<class T> struct A { // cxx17-note 6 {{candidate}} cxx17-note 6 {{implicit deduction guide}}
     T x;
     T y;
   };
@@ -36,12 +36,14 @@ namespace Basic {
     T y;
   };
 
-  template <typename T> struct C { // cxx20-note 10 {{candidate}} cxx17-note 12 {{candidate}}
+  template <typename T> struct C { // cxx20-note 10 {{candidate}} cxx17-note 12 {{candidate}} \
+                                      cxx20-note 10 {{implicit deduction guide}} cxx17-note 12 {{implicit deduction guide}}
     S<T> s;
     T t;
   };
 
-  template <typename T> struct D { // cxx20-note 6 {{candidate}} cxx17-note 8 {{candidate}}
+  template <typename T> struct D { // cxx20-note 6 {{candidate}} cxx17-note 8 {{candidate}} \
+                                      cxx20-note 6 {{implicit deduction guide}} cxx17-note 8 {{implicit deduction guide}}
     S<int> s;
     T t;
   };
@@ -99,7 +101,7 @@ namespace Basic {
   // CHECK:   |-ClassTemplateSpecialization {{.*}} 'S'
   // CHECK:   `-BuiltinType {{.*}} 'int'
 
-  template <typename T> struct E { // cxx17-note 4 {{candidate}}
+  template <typename T> struct E { // cxx17-note 4 {{candidate}} cxx17-note 4 {{implicit deduction guide}}
     T t;
     decltype(t) t2;
   };
@@ -133,7 +135,7 @@ namespace Basic {
   };
 
   template <typename T>
-  struct F { // cxx17-note 2 {{candidate}}
+  struct F { // cxx17-note 2 {{candidate}} cxx17-note 2 {{implicit deduction guide}}
     typename I<T>::type i;
     T t;
   };
@@ -161,7 +163,8 @@ namespace Basic {
 
 namespace Array {
   typedef unsigned long size_t;
-  template <typename T, size_t N> struct A { // cxx20-note 2 {{candidate}} cxx17-note 14 {{candidate}}
+  template <typename T, size_t N> struct A { // cxx20-note 2 {{candidate}} cxx17-note 14 {{candidate}} \
+                                                cxx20-note 2 {{implicit deduction guide}} cxx17-note 14 {{implicit deduction guide}}
     T array[N];
   };
 
@@ -217,7 +220,7 @@ namespace Array {
 }
 
 namespace BraceElision {
-  template <typename T> struct A { // cxx17-note 4 {{candidate}}
+  template <typename T> struct A { // cxx17-note 4 {{candidate}} cxx17-note 4 {{implicit deduction guide}}
     T array[2];
   };
 
@@ -247,7 +250,7 @@ namespace BraceElision {
 }
 
 namespace TrailingPack {
-  template<typename... T> struct A : T... { // cxx17-note 4 {{candidate}}
+  template<typename... T> struct A : T... { // cxx17-note 4 {{candidate}} cxx17-note 4 {{implicit deduction guide}}
   };
 
   A a1 = { // cxx17-error {{no viable}}
@@ -286,7 +289,7 @@ namespace TrailingPack {
 }
 
 namespace NonTrailingPack {
-  template<typename... T> struct A : T... { // expected-note 4 {{candidate}}
+  template<typename... T> struct A : T... { // expected-note 4 {{candidate}} expected-note 4 {{implicit deduction guide}}
     int a;
   };
 
@@ -303,7 +306,8 @@ namespace NonTrailingPack {
 
 namespace DeduceArity {
   template <typename... T> struct Types {};
-  template <typename... T> struct F : Types<T...>, T... {}; // cxx20-note 12 {{candidate}} cxx17-note 16 {{candidate}}
+  template <typename... T> struct F : Types<T...>, T... {}; // cxx20-note 12 {{candidate}} cxx17-note 16 {{candidate}} \
+                                                               cxx20-note 12 {{implicit deduction guide}} cxx17-note 16 {{implicit deduction guide}}
 
   struct X {};
   struct Y {};

diff  --git a/clang/test/SemaTemplate/class-template-id.cpp b/clang/test/SemaTemplate/class-template-id.cpp
index eade4f6290424..96696f62b78a2 100644
--- a/clang/test/SemaTemplate/class-template-id.cpp
+++ b/clang/test/SemaTemplate/class-template-id.cpp
@@ -45,6 +45,8 @@ typedef N::C<float> c2;
 // PR5655
 template<typename T> struct Foo { }; // precxx17-note {{template is declared here}} \
                                         cxx17-note {{candidate template ignored: couldn't infer template argument 'T'}} \
+                                        cxx17-note {{implicit deduction guide declared as 'template <typename T> Foo() -> Foo<T>'}} \
+                                        cxx17-note {{implicit deduction guide declared as 'template <typename T> Foo(Foo<T>) -> Foo<T>'}} \
                                         cxx17-note {{candidate function template not viable: requires 1 argument, but 0 were provided}}
 
 void f(void) { Foo bar; } // precxx17-error {{use of class template 'Foo' requires template arguments}} \

diff  --git a/clang/test/SemaTemplate/ctad.cpp b/clang/test/SemaTemplate/ctad.cpp
index e981ea8d5ecfb..1bf605f823bbe 100644
--- a/clang/test/SemaTemplate/ctad.cpp
+++ b/clang/test/SemaTemplate/ctad.cpp
@@ -20,8 +20,10 @@ namespace Access {
   protected:
     struct type {};
   };
-  template<typename T> struct D : B { // expected-note {{not viable}}
-    D(T, typename T::type); // expected-note {{private member}}
+  template<typename T> struct D : B { // expected-note {{not viable}} \
+                                         expected-note {{implicit deduction guide declared as 'template <typename T> D(D<T>) -> D<T>'}}
+    D(T, typename T::type); // expected-note {{private member}} \
+                            // expected-note {{implicit deduction guide declared as 'template <typename T> D(T, typename T::type) -> D<T>'}}
   };
   D b = {B(), {}};
 
@@ -58,13 +60,15 @@ Y y(1);
 namespace NoCrashOnGettingDefaultArgLoc {
 template <typename>
 class A {
-  A(int = 1); // expected-note {{candidate template ignored: couldn't infer template argumen}}
+  A(int = 1); // expected-note {{candidate template ignored: couldn't infer template argumen}} \
+              // expected-note {{implicit deduction guide declared as 'template <typename> D(int = <null expr>) -> D<type-parameter-0-0>'}}
 };
 class C : A<int> {
   using A::A;
 };
 template <typename>
-class D : C { // expected-note {{candidate function template not viable: requires 1 argument}}
+class D : C { // expected-note {{candidate function template not viable: requires 1 argument}} \
+                 expected-note {{implicit deduction guide declared as 'template <typename> D(D<type-parameter-0-0>) -> D<type-parameter-0-0>'}}
   using C::C;
 };
 D abc; // expected-error {{no viable constructor or deduction guide}}

diff  --git a/clang/test/SemaTemplate/deduction-crash.cpp b/clang/test/SemaTemplate/deduction-crash.cpp
index 86ec9f7980a7d..e3f97c594aa90 100644
--- a/clang/test/SemaTemplate/deduction-crash.cpp
+++ b/clang/test/SemaTemplate/deduction-crash.cpp
@@ -166,8 +166,9 @@ namespace PR51872_part1 {
   template<int> class T1 { template <struct U1> T1(); };
   // expected-error at -1 {{non-type template parameter has incomplete type 'struct U1'}}
   // expected-note at -2  {{forward declaration of 'PR51872_part1::U1'}}
+  // expected-note at -3  {{implicit deduction guide declared as 'template <int> T1(T1<>) -> T1<>'}}
 
   T1 t1 = 0;
   // expected-error at -1 {{no viable constructor or deduction guide for deduction of template arguments of 'T1'}}
-  // expected-note at -6  {{candidate template ignored: could not match 'T1<>' against 'int'}}
+  // expected-note at -7  {{candidate template ignored: could not match 'T1<>' against 'int'}}
 }

diff  --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp
index 163b36519950f..7b9ca4d83b020 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -123,9 +123,11 @@ using CT = C<int>;
 // CHECK: |   `-TemplateArgument template
 // CHECK: `-TemplateTypeParmType {{.*}} 'type-parameter-0-2' dependent depth 0 index 2
 
-template<typename ...T> struct D { // expected-note {{candidate}}
+template<typename ...T> struct D { // expected-note {{candidate}} \
+                                   // expected-note {{implicit deduction guide declared as 'template <typename ...T> D(D<T...>) -> D<T...>'}}
   template<typename... U> using B = int(int (*...p)(T, U));
-  template<typename U1, typename U2> D(B<U1, U2>*); // expected-note {{candidate}}
+  template<typename U1, typename U2> D(B<U1, U2>*); // expected-note {{candidate}} \
+                                                    // expected-note {{implicit deduction guide declared as 'template <typename ...T, typename U1, typename U2> D(B<type-parameter-0-1, type-parameter-0-2> *) -> D<T...>'}}
 };
 int f(int(int, int), int(int, int));
 // FIXME: We can't deduce this because we can't deduce through a
@@ -166,9 +168,11 @@ using DT = D<int, int>;
 // CHECK-NOT: Subst
 // CHECK:                     `-TemplateTypeParmType
 
-template<int ...N> struct E { // expected-note {{candidate}}
+template<int ...N> struct E { // expected-note {{candidate}} \
+                                 expected-note {{implicit deduction guide declared as 'template <int ...N> E(E<N...>) -> E<N...>'}}
   template<int ...M> using B = Z<X<N, M>...>;
-  template<int M1, int M2> E(B<M1, M2>); // expected-note {{candidate}}
+  template<int M1, int M2> E(B<M1, M2>); // expected-note {{candidate}} \
+                                         // expected-note {{implicit deduction guide declared as 'template <int ...N, int M1, int M2> E(B<M1, M2>) -> E<N...>'}}}}
 };
 // FIXME: We can't deduce this because we can't deduce through a
 // SubstNonTypeTemplateParmPackExpr.

diff  --git a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
index a4ae046ac5274..af3e3358f6138 100644
--- a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
+++ b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
@@ -82,8 +82,11 @@ using NIL = nested_init_list<int>::B<int>;
 // expected-error at +1 {{no viable constructor or deduction guide for deduction of template arguments of 'nested_init_list<int>::concept_fail'}}
 nested_init_list<int>::concept_fail nil_invalid{1, ""};
 // expected-note@#INIT_LIST_INNER_INVALID {{candidate template ignored: substitution failure [with F = const char *]: constraints not satisfied for class template 'concept_fail' [with F = const char *]}}
+// expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail(int, F) -> concept_fail<F>'}}
 // expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 1 argument, but 2 were provided}}
+// expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail(concept_fail<F>) -> concept_fail<F>'}}
 // expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 0 arguments, but 2 were provided}}
+// expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail() -> concept_fail<F>'}}
 
 namespace GH88142 {
 

diff  --git a/clang/test/SemaTemplate/temp_arg.cpp b/clang/test/SemaTemplate/temp_arg.cpp
index 2db4a51d6cccb..538056a4e44c7 100644
--- a/clang/test/SemaTemplate/temp_arg.cpp
+++ b/clang/test/SemaTemplate/temp_arg.cpp
@@ -6,7 +6,9 @@ template<typename T,
   class A; // precxx17-note 3 {{template is declared here}} \
               cxx17-note 2 {{template is declared here}} \
               cxx17-note {{candidate template ignored: couldn't infer template argument 'T'}} \
-              cxx17-note {{candidate function template not viable: requires 1 argument, but 0 were provided}}
+              cxx17-note {{implicit deduction guide declared as 'template <typename T, int I, template <typename> class TT> A(A<T, I, TT>) -> A<T, I, TT>'}} \
+              cxx17-note {{candidate function template not viable: requires 1 argument, but 0 were provided}} \
+              cxx17-note {{implicit deduction guide declared as 'template <typename T, int I, template <typename> class TT> A() -> A<T, I, TT>'}} \
 
 template<typename> class X;
 


        


More information about the cfe-commits mailing list