[clang] [Clang] Clarify diagnostic notes for implicitly generated deduction guides (PR #96084)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 25 19:54:22 PDT 2024
https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/96084
>From 23844cd8b8fad07bce0c34f58430322090c5a793 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Wed, 19 Jun 2024 23:25:13 +0800
Subject: [PATCH 1/7] [Clang] Add diagnostic notes for implcitly generated
deduction guides
---
clang/docs/ReleaseNotes.rst | 3 ++
.../clang/Basic/DiagnosticSemaKinds.td | 1 +
clang/lib/Sema/SemaOverload.cpp | 30 +++++++++++++++++++
clang/test/CXX/drs/cwg26xx.cpp | 3 ++
.../CXX/expr/expr.post/expr.type.conv/p1.cpp | 2 +-
.../over.match.class.deduct/p2.cpp | 2 +-
.../temp.deduct/temp.deduct.call/p3-0x.cpp | 4 +--
clang/test/Modules/template_name_lookup.cpp | 2 ++
clang/test/PCH/cxx-explicit-specifier.cpp | 2 +-
clang/test/Sema/tls_alignment.cpp | 4 ++-
...xx1z-class-template-argument-deduction.cpp | 6 ++--
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 17 +++++++++--
clang/test/SemaCXX/cxx2a-explicit-bool.cpp | 2 ++
clang/test/SemaCXX/gh65522.cpp | 3 +-
...deduction-guide-as-template-candidates.cpp | 4 ++-
.../lookup-template-name-extern-CXX.cpp | 6 ++--
.../aggregate-deduction-candidate.cpp | 24 ++++++++-------
clang/test/SemaTemplate/class-template-id.cpp | 2 ++
clang/test/SemaTemplate/ctad.cpp | 6 ++--
clang/test/SemaTemplate/deduction-crash.cpp | 3 +-
clang/test/SemaTemplate/deduction-guide.cpp | 6 ++--
.../nested-implicit-deduction-guides.cpp | 3 ++
clang/test/SemaTemplate/temp_arg.cpp | 4 ++-
23 files changed, 108 insertions(+), 31 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 69aea6c21ad39..423f1e9198948 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -580,6 +580,9 @@ Improvements to Clang's diagnostics
- Clang no longer emits a "declared here" note for a builtin function that has no declaration in source.
Fixes #GH93369.
+- Clang now emits implicit deduction guides corresponding to non-user-defined constructors while at a failure
+ of overload resolution.
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ab223f2b806d5..a65491b0c4399 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2405,6 +2405,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 fb4ff72e42eb5..31b908eb3cc3c 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"
@@ -12114,6 +12115,35 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return;
}
+ // If this is an implicit deduction guide against a non-user-defined
+ // constructor, add a note for it. These deduction guides nor their
+ // corresponding constructors are not explicitly spelled in the source code,
+ // and simply producing a deduction failure note around the heading of the
+ // enclosing RecordDecl is confusing.
+ //
+ // We prefer adding such notes at the end of the last deduction failure
+ // reason because duplicate code snippets appearing in the diagnostic
+ // are likely becoming noisy.
+ auto _ = llvm::make_scope_exit([&] {
+ auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
+ if (!DG || !DG->isImplicit() || DG->getCorrespondingConstructor())
+ return;
+ std::string FunctionProto;
+ llvm::raw_string_ostream OS(FunctionProto);
+ FunctionTemplateDecl *Template = DG->getDescribedFunctionTemplate();
+ // This also could be an instantiation. Find out the primary template.
+ if (!Template) {
+ FunctionDecl *Pattern = DG->getTemplateInstantiationPattern();
+ assert(Pattern && Pattern->getDescribedFunctionTemplate() &&
+ "Cannot find the associated function template of "
+ "CXXDeductionGuideDecl?");
+ Template = Pattern->getDescribedFunctionTemplate();
+ }
+ Template->print(OS);
+ S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
+ << FunctionProto;
+ });
+
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 2b17c8101438d..95dfa229530fb 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -194,8 +194,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..aa3c022e9b134 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}} {{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..4bcf4ee2e3fe7 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,7 +35,7 @@ namespace std {
}
namespace p0702r1 {
- template<typename T> struct X { // expected-note {{candidate}}
+ 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'}}
};
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..2e39697a1f07f 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,7 +6,7 @@
#if __cplusplus > 201402L
namespace ClassTemplateParamNotForwardingRef {
// This is not a forwarding reference.
- template<typename T> struct A { // expected-note {{candidate}}
+ template<typename T> struct A { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
A(T&&); // expected-note {{expects an rvalue}}
};
int n;
@@ -75,7 +75,7 @@ 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}}
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..68dfc911164c5 100644
--- a/clang/test/PCH/cxx-explicit-specifier.cpp
+++ b/clang/test/PCH/cxx-explicit-specifier.cpp
@@ -79,7 +79,7 @@ struct A {
B<true> b_true;
B<false> b_false;
#else
-//expected-note at -8 {{candidate template ignored}}
+//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 -15+ {{candidate constructor}}
//expected-note at -8+ {{explicit conversion function 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..0a296b32cfb6f 100644
--- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -139,7 +139,8 @@ 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;
};
@@ -564,7 +565,8 @@ namespace PR47175 {
// Ensure we don't crash when CTAD fails.
template <typename T1, typename T2>
-struct Foo { // 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}}
};
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index b71dfc6ccaf4f..901f64434bbee 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -108,8 +108,11 @@ struct Foo {
Foo(T const (&)[N]);
};
+// FIXME: Clarify that __is_deducible constraints are unsatisfied. For example, GCC currently prints the code snippet around constructors
+// FIXME: Prefer non-canonical template arguments in the deduction guide?
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> Bar(Foo<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 +140,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> 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> 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> 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 +198,7 @@ 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> Bar(Foo<double, K>) -> Foo<double, K>'}}
double abc[3];
Bar s2 = {abc}; // expected-error {{no viable constructor or deduction guide for deduction }}
} // namespace test14
@@ -204,6 +211,7 @@ 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 {{implicit deduction guide declared as 'template <class V> BFoo(Foo<type-parameter-0-0 *>) -> Foo<type-parameter-0-0 *>'}} \
// expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}}
int i = 0;
AFoo a1(&i); // OK, deduce Foo<int *>
@@ -256,7 +264,9 @@ 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 {{candidate template ignored: constraints not satisfied}} \
- // expected-note {{candidate function template not viable}}
+ // expected-note {{candidate function template not viable}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename U> Bar() -> Foo<type-parameter-0-0>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename U> Bar(Foo<type-parameter-0-0>) -> 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 +294,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> 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..13b5ff1d59b31 100644
--- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
+++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -394,6 +394,7 @@ 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}}
@@ -678,6 +679,7 @@ 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}}
diff --git a/clang/test/SemaCXX/gh65522.cpp b/clang/test/SemaCXX/gh65522.cpp
index 2d6331b0372a3..bfc3a1e12fe76 100644
--- a/clang/test/SemaCXX/gh65522.cpp
+++ b/clang/test/SemaCXX/gh65522.cpp
@@ -3,7 +3,8 @@
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'}}
};
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..c5e467a8d7724 100644
--- a/clang/test/SemaTemplate/ctad.cpp
+++ b/clang/test/SemaTemplate/ctad.cpp
@@ -20,7 +20,8 @@ namespace Access {
protected:
struct type {};
};
- template<typename T> struct D : B { // expected-note {{not viable}}
+ 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}}
};
D b = {B(), {}};
@@ -64,7 +65,8 @@ 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..54420be9ee969 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -123,7 +123,8 @@ 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}}
};
@@ -166,7 +167,8 @@ 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}}
};
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;
>From 68a06465fc2385e8bd8a29eb5c353f1ae5cc916d Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 21 Jun 2024 11:25:47 +0800
Subject: [PATCH 2/7] Apply suggestions from Sirraide
Co-authored-by: Sirraide <aeternalmail at gmail.com>
---
clang/docs/ReleaseNotes.rst | 4 ++--
clang/lib/Sema/SemaOverload.cpp | 10 +++++-----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 423f1e9198948..558792fb82e7e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -580,8 +580,8 @@ Improvements to Clang's diagnostics
- Clang no longer emits a "declared here" note for a builtin function that has no declaration in source.
Fixes #GH93369.
-- Clang now emits implicit deduction guides corresponding to non-user-defined constructors while at a failure
- of overload resolution.
+- Clang now shows implicit deduction guides corresponding to implcitly defined constructors when
+ diagnosing overload resolution failure.
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 31b908eb3cc3c..38e52581ab5af 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12115,15 +12115,15 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return;
}
- // If this is an implicit deduction guide against a non-user-defined
- // constructor, add a note for it. These deduction guides nor their
- // corresponding constructors are not explicitly spelled in the source code,
+ // If this is an implicit deduction guide against an implicitly defined
+ // constructor, add a note for it. Neither these deduction guides nor their
+ // corresponding constructors are explicitly spelled in the source code,
// and simply producing a deduction failure note around the heading of the
- // enclosing RecordDecl is confusing.
+ // enclosing RecordDecl would be confusing.
//
// We prefer adding such notes at the end of the last deduction failure
// reason because duplicate code snippets appearing in the diagnostic
- // are likely becoming noisy.
+ // would likely become noisy.
auto _ = llvm::make_scope_exit([&] {
auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
if (!DG || !DG->isImplicit() || DG->getCorrespondingConstructor())
>From 616da22375b870090215e2318f1c98ffc3a23a5a Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 21 Jun 2024 11:28:12 +0800
Subject: [PATCH 3/7] Fix tests
---
clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 aa3c022e9b134..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}} {{implicit deduction guide}}
+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'}}
>From a468b7ccad1f70e9db3fc4c1f1c6f6478479bd93 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Tue, 25 Jun 2024 19:53:33 +0800
Subject: [PATCH 4/7] Address Hokein's feedback
---
clang/docs/ReleaseNotes.rst | 2 +-
clang/lib/Sema/SemaOverload.cpp | 25 ++++++++++++-------
.../over.match.class.deduct/p2.cpp | 3 ++-
.../temp.deduct/temp.deduct.call/p3-0x.cpp | 8 +++---
clang/test/PCH/cxx-explicit-specifier.cpp | 2 +-
...xx1z-class-template-argument-deduction.cpp | 12 +++++----
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 6 ++++-
clang/test/SemaCXX/cxx2a-explicit-bool.cpp | 2 ++
clang/test/SemaCXX/gh65522.cpp | 3 ++-
clang/test/SemaTemplate/ctad.cpp | 6 +++--
clang/test/SemaTemplate/deduction-guide.cpp | 8 +++---
11 files changed, 50 insertions(+), 27 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4c9f2b76a5e15..71ed84a9fff4a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -610,7 +610,7 @@ Improvements to Clang's diagnostics
The check is now stricter to prevent crashes for some unsupported declarations (Fixes #GH95495).
- Clang now shows implicit deduction guides corresponding to implcitly defined constructors when
- diagnosing overload resolution failure.
+ diagnosing overload resolution failure. #GH92393.
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 38e52581ab5af..4214c0041da56 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12115,18 +12115,25 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return;
}
- // If this is an implicit deduction guide against an implicitly defined
- // constructor, add a note for it. Neither these deduction guides nor their
- // corresponding constructors are explicitly spelled in the source code,
- // and simply producing a deduction failure note around the heading of the
- // enclosing RecordDecl would be confusing.
+ // 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 last deduction failure
- // reason because duplicate code snippets appearing in the diagnostic
- // would likely become noisy.
+ // 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([&] {
auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
- if (!DG || !DG->isImplicit() || DG->getCorrespondingConstructor())
+ if (!DG)
+ return;
+ // We want to always print synthesized deduction guides for type aliases.
+ // They would retain the explicit bit of the corresponding constructor.
+ if (TemplateDecl *OriginTemplate =
+ DG->getDeclName().getCXXDeductionGuideTemplate();
+ !DG->isImplicit() &&
+ (!OriginTemplate || !OriginTemplate->isTypeAlias()))
return;
std::string FunctionProto;
llvm::raw_string_ostream OS(FunctionProto);
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 4bcf4ee2e3fe7..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
@@ -36,7 +36,8 @@ namespace std {
namespace p0702r1 {
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'}}
+ 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 2e39697a1f07f..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
@@ -7,7 +7,7 @@
namespace ClassTemplateParamNotForwardingRef {
// This is not a forwarding reference.
template<typename T> struct A { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
- A(T&&); // expected-note {{expects an rvalue}}
+ 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}}
@@ -77,8 +77,10 @@ namespace std_example {
#if __cplusplus > 201402L
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/PCH/cxx-explicit-specifier.cpp b/clang/test/PCH/cxx-explicit-specifier.cpp
index 68dfc911164c5..84548faf48810 100644
--- a/clang/test/PCH/cxx-explicit-specifier.cpp
+++ b/clang/test/PCH/cxx-explicit-specifier.cpp
@@ -80,7 +80,7 @@ B<true> b_true;
B<false> b_false;
#else
//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 {{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/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 0a296b32cfb6f..9ef5303a9c4df 100644
--- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -140,11 +140,12 @@ namespace look_into_current_instantiation {
A<float> &r = a;
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>'}}
+ // 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}}
@@ -565,9 +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}} \
- 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}}
+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 901f64434bbee..4cd53e10e74c5 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -113,6 +113,7 @@ 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> 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> 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>'}}
@@ -199,6 +200,7 @@ 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> Bar(Foo<double, K>) -> Foo<double, K>'}}
+// expected-note at -3 {{implicit deduction guide declared as 'template <int 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
@@ -211,6 +213,7 @@ 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 {{implicit deduction guide declared as 'template <class V> BFoo(type-parameter-0-0 *) -> Foo<type-parameter-0-0 *>'}} \
// expected-note {{implicit deduction guide declared as 'template <class V> BFoo(Foo<type-parameter-0-0 *>) -> Foo<type-parameter-0-0 *>'}} \
// expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}}
int i = 0;
@@ -266,7 +269,8 @@ using Bar = Foo<U>; // expected-note {{could not match '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 U> Bar() -> Foo<type-parameter-0-0>'}} \
- // expected-note {{implicit deduction guide declared as 'template <typename U> Bar(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}}
+ // expected-note {{implicit deduction guide declared as 'template <typename U> Bar(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename T> Bar(type-parameter-0-0) -> Foo<int>'}}
Bar s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
} // namespace test18
diff --git a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
index 13b5ff1d59b31..03799c52654a5 100644
--- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
+++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -398,6 +398,7 @@ struct A {
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>
@@ -684,6 +685,7 @@ struct A {
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 bfc3a1e12fe76..80281248c6d49 100644
--- a/clang/test/SemaCXX/gh65522.cpp
+++ b/clang/test/SemaCXX/gh65522.cpp
@@ -6,7 +6,8 @@ template<typename T>
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/SemaTemplate/ctad.cpp b/clang/test/SemaTemplate/ctad.cpp
index c5e467a8d7724..1bf605f823bbe 100644
--- a/clang/test/SemaTemplate/ctad.cpp
+++ b/clang/test/SemaTemplate/ctad.cpp
@@ -22,7 +22,8 @@ namespace Access {
};
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}}
+ 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(), {}};
@@ -59,7 +60,8 @@ 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;
diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp
index 54420be9ee969..7b9ca4d83b020 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -124,9 +124,10 @@ using CT = C<int>;
// CHECK: `-TemplateTypeParmType {{.*}} 'type-parameter-0-2' dependent depth 0 index 2
template<typename ...T> struct D { // expected-note {{candidate}} \
- expected-note {{implicit deduction guide declared as 'template <typename ...T> D(D<T...>) -> D<T...>'}}
+ // 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
@@ -170,7 +171,8 @@ using DT = D<int, int>;
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.
>From 34b665e55ceded46da20c492a99179b9a41a15b6 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Tue, 25 Jun 2024 20:17:52 +0800
Subject: [PATCH 5/7] Remove an unnecessary FIXME
---
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 4cd53e10e74c5..761648926f99b 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -108,7 +108,6 @@ struct Foo {
Foo(T const (&)[N]);
};
-// FIXME: Clarify that __is_deducible constraints are unsatisfied. For example, GCC currently prints the code snippet around constructors
// FIXME: Prefer non-canonical template arguments in the deduction guide?
template <typename X, int Y>
using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \
>From 8ef907675dc2448aca68182d6729dba4c53acbba Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Wed, 26 Jun 2024 10:51:55 +0800
Subject: [PATCH 6/7] Move the function out-of-line and adapt to #96686
---
clang/lib/Sema/SemaOverload.cpp | 59 +++++++++++++++++++++------------
1 file changed, 38 insertions(+), 21 deletions(-)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 4214c0041da56..8165ede26f1f4 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12058,6 +12058,43 @@ static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
<< (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange());
}
+static void maybeNoteImplicitDeductionGuide(Sema &S,
+ CXXDeductionGuideDecl *DG) {
+ // We want to always print synthesized deduction guides for type aliases.
+ // They would retain the explicit bit of the corresponding constructor.
+ TemplateDecl *OriginTemplate =
+ DG->getDeclName().getCXXDeductionGuideTemplate();
+ 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() &&
+ "Only deduction guides for type aliases can have no template Decls");
+ 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.
///
@@ -12128,27 +12165,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
if (!DG)
return;
- // We want to always print synthesized deduction guides for type aliases.
- // They would retain the explicit bit of the corresponding constructor.
- if (TemplateDecl *OriginTemplate =
- DG->getDeclName().getCXXDeductionGuideTemplate();
- !DG->isImplicit() &&
- (!OriginTemplate || !OriginTemplate->isTypeAlias()))
- return;
- std::string FunctionProto;
- llvm::raw_string_ostream OS(FunctionProto);
- FunctionTemplateDecl *Template = DG->getDescribedFunctionTemplate();
- // This also could be an instantiation. Find out the primary template.
- if (!Template) {
- FunctionDecl *Pattern = DG->getTemplateInstantiationPattern();
- assert(Pattern && Pattern->getDescribedFunctionTemplate() &&
- "Cannot find the associated function template of "
- "CXXDeductionGuideDecl?");
- Template = Pattern->getDescribedFunctionTemplate();
- }
- Template->print(OS);
- S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
- << FunctionProto;
+ maybeNoteImplicitDeductionGuide(S, DG);
});
switch (Cand->FailureKind) {
>From bb0b8364228474d0a9734bdfc60f696c692f2d9e Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Wed, 26 Jun 2024 10:54:02 +0800
Subject: [PATCH 7/7] Format
---
clang/lib/Sema/SemaOverload.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 8165ede26f1f4..64d7294a6bf29 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12079,8 +12079,9 @@ static void maybeNoteImplicitDeductionGuide(Sema &S,
// aliases.
// FIXME: Add a test once https://github.com/llvm/llvm-project/pull/96686
// gets merged.
- assert(OriginTemplate->isTypeAlias() &&
- "Only deduction guides for type aliases can have no template Decls");
+ assert(
+ OriginTemplate->isTypeAlias() &&
+ "Only deduction guides for type aliases can have no template Decls");
DG->print(OS);
S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
<< FunctionProto;
More information about the cfe-commits
mailing list