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(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)); J j = { "ghi" }; // since-cxx20-error@-1 {{no viable constructor or deduction guide}} // since-cxx20-note@#cwg2681-J {{candidate template ignored: could not match 'J' against 'const char *'}} +// since-cxx20-note@#cwg2681-J {{implicit deduction guide declared as 'template J(J) -> J'}} // 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 J(const unsigned char (&)[N]) -> J'}} // 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 J() -> J'}} #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 struct A { // expected-note 2{{candidate}} +template struct A { // expected-note 2{{candidate}} expected-note 2{{implicit deduction guide}} T t, u; }; template A(T, T) -> A; // 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 struct X { // expected-note {{candidate}} - X(std::initializer_list); // expected-note {{candidate template ignored: could not match 'std::initializer_list' against 'Z'}} + template struct X { // expected-note {{candidate}} expected-note {{implicit deduction guide}} + X(std::initializer_list); // expected-note {{candidate template ignored: could not match 'std::initializer_list' against 'Z'}} \ + // expected-note {{implicit deduction guide declared as 'template X(std::initializer_list) -> X'}} }; 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 struct A { // expected-note {{candidate}} - A(T&&); // expected-note {{expects an rvalue}} + template 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 struct A { // expected-note {{candidate}} + template struct A { // expected-note {{candidate}} expected-note {{implicit deduction guide}} template - 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 A(T &&, type-parameter-0-1 &&, int *) -> A'}} + A(T &&, int *); // expected-note {{requires 2}} \ + // expected-note {{implicit deduction guide declared as 'template A(T &&, int *) -> A'}} }; template A(T &&, int *) -> A; // 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@Inputs/template_name_lookup/foo.cppm:3 {{candidate template ignored: couldn't infer template argument 'T'}} + // expected-note@Inputs/template_name_lookup/foo.cppm:3 {{implicit deduction guide declared as 'template X(X) -> X'}} // expected-note@Inputs/template_name_lookup/foo.cppm:3 {{candidate function template not viable: requires 1 argument, but 0 were provided}} + // expected-note@Inputs/template_name_lookup/foo.cppm:3 {{implicit deduction guide declared as 'template X() -> X'}} } 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 b_true; B b_false; #else -//expected-note@-8 {{candidate template ignored}} -//expected-note@-8 {{explicit constructor declared here}} +//expected-note@-8 {{candidate template ignored}} expected-note@-8 {{implicit deduction guide declared as 'template A(A) -> A'}} +//expected-note@-8 {{explicit constructor declared here}} expected-note@-8 {{implicit deduction guide declared as 'template explicit(b) A(B) -> A'}} //expected-note@-15+ {{candidate constructor}} //expected-note@-8+ {{explicit conversion function is not a candidate (explicit specifier}} //expected-note@-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 struct templated_struct {}; // expected-note@-1{{candidate template ignored: couldn't infer template argument ''}} -// expected-note@-2{{candidate function template not viable: requires 1 argument, but 0 were provided}} +// expected-note@-2{{implicit deduction guide declared as 'template templated_struct() -> templated_struct'}} +// expected-note@-3{{candidate function template not viable: requires 1 argument, but 0 were provided}} +// expected-note@-4{{implicit deduction guide declared as 'template templated_struct(templated_struct) -> templated_struct'}} // 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 &r = a; - template struct B { // expected-note {{could not match 'B' against 'int'}} + template struct B { // expected-note {{could not match 'B' against 'int'}} \ + // expected-note {{implicit deduction guide declared as 'template B(B) -> B'}} 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 B(typename X::type) -> B'}} }; B b = 0; // expected-error {{no viable}} @@ -564,8 +566,10 @@ namespace PR47175 { // Ensure we don't crash when CTAD fails. template -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 Foo(Foo) -> Foo'}} + Foo(T1, T2); // expected-note {{candidate function template not viable}} \ + // expected-note {{implicit deduction guide declared as 'template Foo(T1, T2) -> Foo'}} }; template 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 using Bar = Foo; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \ + // expected-note {{implicit deduction guide declared as 'template requires __is_deducible(test9::Bar, Foo) Bar(Foo) -> Foo'}} \ + // expected-note {{implicit deduction guide declared as 'template requires __is_deducible(test9::Bar, Foo) Bar(const type-parameter-0-0 (&)[sizeof(type-parameter-0-0)]) -> Foo'}} \ // expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \ // expected-note {{cannot deduce template arguments for 'Bar' from 'Foo'}} @@ -137,9 +139,12 @@ struct A {}; template struct Foo { T c; }; template using AFoo = Foo; // expected-note {{candidate template ignored: could not match 'Foo' against 'int'}} \ + // expected-note {{implicit deduction guide declared as 'template requires __is_deducible(test11::AFoo, Foo) AFoo(Foo) -> Foo'}} \ // expected-note {{candidate template ignored: constraints not satisfied [with Y = int]}} \ // expected-note {{cannot deduce template arguments for 'AFoo' from 'Foo'}} \ - // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} + // expected-note {{implicit deduction guide declared as 'template requires __is_deducible(test11::AFoo, Foo) AFoo(type-parameter-0-0) -> Foo'}} \ + // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \ + // expected-note {{implicit deduction guide declared as 'template requires __is_deducible(test11::AFoo, Foo) AFoo() -> Foo'}} 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 using Bar = Foo; // expected-note {{constraints not satisfied for class template 'Foo'}} // expected-note@-1 {{candidate template ignored: could not match}} +// expected-note@-2 {{implicit deduction guide declared as 'template requires __is_deducible(test14::Bar, Foo) Bar(Foo) -> Foo'}} +// expected-note@-3 {{implicit deduction guide declared as 'template requires __is_deducible(test14::Bar, Foo) Bar(const double (&)[K]) -> Foo'}} double abc[3]; Bar s2 = {abc}; // expected-error {{no viable constructor or deduction guide for deduction }} } // namespace test14 @@ -204,7 +211,9 @@ template concept False = false; template using BFoo = AFoo; // expected-note {{candidate template ignored: constraints not satisfied [with V = int]}} \ // expected-note {{cannot deduce template arguments for 'BFoo' from 'Foo'}} \ - // expected-note {{candidate template ignored: could not match 'Foo' against 'int *'}} + // expected-note {{implicit deduction guide declared as 'template requires __is_deducible(AFoo, Foo) && __is_deducible(test15::BFoo, Foo) BFoo(type-parameter-0-0 *) -> Foo}} \ + // expected-note {{candidate template ignored: could not match 'Foo' against 'int *'}} \ + // expected-note {{template requires __is_deducible(AFoo, Foo) && __is_deducible(test15::BFoo, Foo) BFoo(Foo) -> Foo}} int i = 0; AFoo a1(&i); // OK, deduce Foo @@ -255,8 +264,11 @@ Foo(T) -> Foo; template using Bar = Foo; // expected-note {{could not match 'Foo' against 'int'}} \ + // expected-note {{implicit deduction guide declared as 'template requires __is_deducible(test18::Bar, Foo) Bar(Foo) -> Foo'}} \ // expected-note {{candidate template ignored: constraints not satisfied}} \ - // expected-note {{candidate function template not viable}} + // expected-note {{implicit deduction guide declared as 'template requires False && __is_deducible(test18::Bar, Foo) Bar(type-parameter-0-0) -> Foo'}} \ + // expected-note {{candidate function template not viable}} \ + // expected-note {{implicit deduction guide declared as 'template requires __is_deducible(test18::Bar, Foo) Bar() -> Foo'}} 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 typename TTP> -using Bar = Foo>; // expected-note {{candidate template ignored: could not match 'Foo>' against 'int'}} +using Bar = Foo>; // expected-note {{candidate template ignored: could not match 'Foo>' against 'int'}} \ + // expected-note {{implicit deduction guide declared as 'template