https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/139066
>From a6ee1af04225063bab4d853611c7a57b1db37aa9 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Thu, 8 May 2025 19:42:51 +0800 Subject: [PATCH 1/4] [Clang] Do not eat SFINAE diagnostics for explicit template arguments --- clang/lib/Sema/SemaOverload.cpp | 19 ++++++++++++++++++- clang/test/AST/ByteCode/builtin-align-cxx.cpp | 3 ++- clang/test/AST/ByteCode/cxx20.cpp | 3 ++- .../basic.namespace/namespace.udecl/p12.cpp | 12 ++++++++---- clang/test/CXX/drs/cwg2xx.cpp | 4 ++++ clang/test/CXX/drs/cwg3xx.cpp | 2 ++ clang/test/CXX/expr/expr.const/p3-0x.cpp | 3 ++- clang/test/CXX/temp/temp.param/p8-cxx20.cpp | 3 ++- .../test/CXX/temp/temp.res/temp.local/p1.cpp | 6 ++++-- clang/test/Modules/cxx-templates.cpp | 2 ++ clang/test/SemaCXX/builtin-align-cxx.cpp | 3 ++- clang/test/SemaCXX/calling-conv-compat.cpp | 3 ++- .../constexpr-function-recovery-crash.cpp | 3 ++- clang/test/SemaCXX/cxx2a-template-lambdas.cpp | 6 ++++-- clang/test/SemaCXX/typo-correction.cpp | 3 ++- .../test/SemaTemplate/concepts-using-decl.cpp | 6 ++++-- .../test/SemaTemplate/overload-candidates.cpp | 10 ++++++---- .../SemaTemplate/temp_arg_nontype_cxx11.cpp | 5 +++-- 18 files changed, 71 insertions(+), 25 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5b224b6c08fef..9b7878434b9ad 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -749,8 +749,16 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, break; case TemplateDeductionResult::Incomplete: + Result.Data = Info.Param.getOpaqueValue(); + break; case TemplateDeductionResult::InvalidExplicitArguments: Result.Data = Info.Param.getOpaqueValue(); + if (Info.hasSFINAEDiagnostic()) { + PartialDiagnosticAt *Diag = new (Result.Diagnostic) PartialDiagnosticAt( + SourceLocation(), PartialDiagnostic::NullDiagnostic()); + Info.takeSFINAEDiagnostic(*Diag); + Result.HasDiagnostic = true; + } break; case TemplateDeductionResult::DeducedMismatch: @@ -822,7 +830,6 @@ void DeductionFailureInfo::Destroy() { case TemplateDeductionResult::Incomplete: case TemplateDeductionResult::TooManyArguments: case TemplateDeductionResult::TooFewArguments: - case TemplateDeductionResult::InvalidExplicitArguments: case TemplateDeductionResult::CUDATargetMismatch: case TemplateDeductionResult::NonDependentConversionFailure: break; @@ -837,6 +844,7 @@ void DeductionFailureInfo::Destroy() { Data = nullptr; break; + case TemplateDeductionResult::InvalidExplicitArguments: case TemplateDeductionResult::SubstitutionFailure: // FIXME: Destroy the template argument list? Data = nullptr; @@ -12166,6 +12174,15 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, diag::note_ovl_candidate_explicit_arg_mismatch_unnamed) << (index + 1); } + + if (PartialDiagnosticAt *PDiag = DeductionFailure.getSFINAEDiagnostic()) { + unsigned DiagID = + S.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Note, "%0"); + SmallString<128> SFINAEArgString; + PDiag->second.EmitToString(S.getDiagnostics(), SFINAEArgString); + S.Diag(Templated->getLocation(), DiagID) << SFINAEArgString; + } + MaybeEmitInheritedConstructorNote(S, Found); return; diff --git a/clang/test/AST/ByteCode/builtin-align-cxx.cpp b/clang/test/AST/ByteCode/builtin-align-cxx.cpp index a1edf307d6c47..973fd1b620525 100644 --- a/clang/test/AST/ByteCode/builtin-align-cxx.cpp +++ b/clang/test/AST/ByteCode/builtin-align-cxx.cpp @@ -4,7 +4,8 @@ // Check that we don't crash when using dependent types in __builtin_align: template <typename a, a b> -void *c(void *d) { // both-note{{candidate template ignored}} +void *c(void *d) { // both-note{{candidate template ignored}} \ +// both-note {{a non-type template parameter cannot have type 'struct x' before C++20}} return __builtin_align_down(d, b); } diff --git a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp index 42e6ae33e92e4..1625f8eee8425 100644 --- a/clang/test/AST/ByteCode/cxx20.cpp +++ b/clang/test/AST/ByteCode/cxx20.cpp @@ -753,7 +753,8 @@ namespace FailingDestructor { } }; template<D d> - void f() {} // both-note {{invalid explicitly-specified argument}} + void f() {} // both-note {{invalid explicitly-specified argument}} \ + // both-note {{non-type template argument is not a constant expression}} void g() { f<D{0, false}>(); // both-error {{no matching function}} diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp index f12e0083fb0c9..ee38418acfb32 100644 --- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp +++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp @@ -113,21 +113,25 @@ namespace test3 { struct Derived1 : Base { using Base::foo; - template <int n> Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} + template <int n> Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} \ + // expected-note {{template argument for non-type template parameter must be an expression}} }; struct Derived2 : Base { - template <int n> Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} + template <int n> Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} \ + // expected-note {{template argument for non-type template parameter must be an expression}} using Base::foo; }; struct Derived3 : Base { using Base::foo; - template <class T> Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} + template <class T> Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} \ + // expected-note {{template argument for template type parameter must be a type}} }; struct Derived4 : Base { - template <class T> Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} + template <class T> Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} \ + // expected-note {{template argument for template type parameter must be a type}} using Base::foo; }; diff --git a/clang/test/CXX/drs/cwg2xx.cpp b/clang/test/CXX/drs/cwg2xx.cpp index b2ae8f88ead74..604a60c9fa0c9 100644 --- a/clang/test/CXX/drs/cwg2xx.cpp +++ b/clang/test/CXX/drs/cwg2xx.cpp @@ -650,14 +650,17 @@ namespace cwg241 { // cwg241: 9 C::f<3>(b); // expected-error@-1 {{no matching function for call to 'f'}} // expected-note@#cwg241-C-f {{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + // expected-note@#cwg241-C-f {{template argument for template type parameter must be a type}} C::g<3>(b); // expected-error@-1 {{no matching function for call to 'g'}} // expected-note@#cwg241-C-g {{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + // expected-note@#cwg241-C-g {{template argument for template type parameter must be a type}} using C::f; using C::g; f<3>(b); // expected-error@-1 {{no matching function for call to 'f'}} // expected-note@#cwg241-C-f {{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + // expected-note@#cwg241-C-f {{template argument for template type parameter must be a type}} // expected-note@#cwg241-A-f {{candidate function template not viable: requires 0 arguments, but 1 was provided}} g<3>(b); } @@ -952,6 +955,7 @@ namespace cwg258 { // cwg258: 2.8 int &x = b.g<int>(0); // expected-error@-1 {{no matching member function for call to 'g'}} // expected-note@#cwg258-B-g {{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} + // expected-note@#cwg258-B-g {{template argument for non-type template parameter must be an expression}} int &y = b.h(); float &z = const_cast<const B&>(b).h(); diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp index 8b035cf6f2370..b1b8d20187dcb 100644 --- a/clang/test/CXX/drs/cwg3xx.cpp +++ b/clang/test/CXX/drs/cwg3xx.cpp @@ -985,7 +985,9 @@ namespace cwg354 { // cwg354: 3.1 c++11 int b1 = both<(int*)0>(); // cxx98-error@-1 {{no matching function for call to 'both'}} // cxx98-note@#cwg354-both-int-ptr {{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} + // cxx98-note@#cwg354-both-int-ptr {{non-type template argument does not refer to any declaration}} // cxx98-note@#cwg354-both-int {{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} + // cxx98-note@#cwg354-both-int {{non-type template argument of type 'int *' must have an integral or enumeration type}} template<int S::*> struct ptr_mem {}; // #cwg354-ptr_mem ptr_mem<0> m0; // #cwg354-m0 diff --git a/clang/test/CXX/expr/expr.const/p3-0x.cpp b/clang/test/CXX/expr/expr.const/p3-0x.cpp index 3eedef3cf7712..c7dafc59599dd 100644 --- a/clang/test/CXX/expr/expr.const/p3-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p3-0x.cpp @@ -107,7 +107,8 @@ void c() { break; } } -template <bool B> int f() { return B; } // expected-note {{candidate template ignored: invalid explicitly-specified argument for template parameter 'B'}} +template <bool B> int f() { return B; } // expected-note {{candidate template ignored: invalid explicitly-specified argument for template parameter 'B'}} \ +// expected-note {{conversion from 'int (S::*)() const' to 'bool' is not allowed in a converted constant expression}} template int f<&S::operator int>(); // expected-error {{does not refer to a function template}} template int f<(bool)&S::operator int>(); diff --git a/clang/test/CXX/temp/temp.param/p8-cxx20.cpp b/clang/test/CXX/temp/temp.param/p8-cxx20.cpp index a3478c0669661..953b613eeef4a 100644 --- a/clang/test/CXX/temp/temp.param/p8-cxx20.cpp +++ b/clang/test/CXX/temp/temp.param/p8-cxx20.cpp @@ -40,7 +40,8 @@ namespace ConstDestruction { }; template<D d> - void f() {} // expected-note 2{{invalid explicitly-specified argument}} + void f() {} // expected-note 2{{invalid explicitly-specified argument}} \ + // expected-note 2{{non-type template argument is not a constant expression}} void g() { f<D{0, true}>(); diff --git a/clang/test/CXX/temp/temp.res/temp.local/p1.cpp b/clang/test/CXX/temp/temp.res/temp.local/p1.cpp index faa85cb5fce30..8a49fc39e2d2b 100644 --- a/clang/test/CXX/temp/temp.res/temp.local/p1.cpp +++ b/clang/test/CXX/temp/temp.res/temp.local/p1.cpp @@ -10,9 +10,11 @@ template<typename> char id; template<typename> struct TempType {}; template<template<typename> class> struct TempTemp {}; -template<typename> void use(int&); // expected-note {{invalid explicitly-specified argument}} expected-note {{no known conversion}} +template<typename> void use(int&); // expected-note {{invalid explicitly-specified argument}} expected-note {{no known conversion}} \ +// expected-note {{use of class template 'B::template C' requires template arguments}} template<template<typename> class> void use(float&); // expected-note 2{{no known conversion}} -template<int> void use(char&); // expected-note 2{{invalid explicitly-specified argument}} +template<int> void use(char&); // expected-note 2{{invalid explicitly-specified argument}} \ +// expected-note 2{{template argument for non-type template parameter must be an expression}} template<typename T> struct A { template<typename> struct C {}; diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp index f587af4beb7ce..dce93f866b15c 100644 --- a/clang/test/Modules/cxx-templates.cpp +++ b/clang/test/Modules/cxx-templates.cpp @@ -43,11 +43,13 @@ void g() { template_param_kinds_2<Tmpl_T_C>(); // expected-error {{no matching function for call}} // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}} + // expected-note@Inputs/cxx-templates-a.h:11 {{too many template arguments for class template 'Tmpl_T_C'}} // expected-note@Inputs/cxx-templates-b.h:11 {{candidate}} template_param_kinds_2<Tmpl_T_I_I>(); // expected-error {{ambiguous}} // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}} // expected-note@Inputs/cxx-templates-b.h:11 {{candidate}} + // expected-note@Inputs/cxx-templates-b.h:11 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}} template_param_kinds_3<Tmpl_T_T_A>(); template_param_kinds_3<Tmpl_T_T_B>(); diff --git a/clang/test/SemaCXX/builtin-align-cxx.cpp b/clang/test/SemaCXX/builtin-align-cxx.cpp index d18bc2bf66551..a680ac2aaa763 100644 --- a/clang/test/SemaCXX/builtin-align-cxx.cpp +++ b/clang/test/SemaCXX/builtin-align-cxx.cpp @@ -3,7 +3,8 @@ // Check that we don't crash when using dependent types in __builtin_align: template <typename a, a b> -void *c(void *d) { // expected-note{{candidate template ignored}} +void *c(void *d) { // expected-note{{candidate template ignored}} \ +// expected-note {{a non-type template parameter cannot have type 'struct x' before C++20}} return __builtin_align_down(d, b); } diff --git a/clang/test/SemaCXX/calling-conv-compat.cpp b/clang/test/SemaCXX/calling-conv-compat.cpp index 9bb448ffef225..8e67528717c5b 100644 --- a/clang/test/SemaCXX/calling-conv-compat.cpp +++ b/clang/test/SemaCXX/calling-conv-compat.cpp @@ -425,6 +425,7 @@ namespace D50526 { void h() { g<void, h>(); } #if !_M_X64 // expected-error@-2 {{no matching function for call to}} - // expected-note@-4 {{invalid explicitly-specified argument}} + // expected-note@-4 {{invalid explicitly-specified argument}} \ + // expected-note@-4 {{non-type template argument of type 'void ()' cannot be converted to a value of type 'void (*)() __attribute__((stdcall))'}} #endif } diff --git a/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp b/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp index 90ee7892b2fc2..086bfa15fe0ea 100644 --- a/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp +++ b/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp @@ -60,7 +60,8 @@ constexpr void test8() { throw "bad"; } -template<int x> constexpr int f(int y) { // expected-note {{candidate template ignored}} +template<int x> constexpr int f(int y) { // expected-note {{candidate template ignored}} \ + // expected-note {{non-type template argument is not a constant expression}} return x * y; } constexpr int test9(int x) { diff --git a/clang/test/SemaCXX/cxx2a-template-lambdas.cpp b/clang/test/SemaCXX/cxx2a-template-lambdas.cpp index 00ba291fbd198..413bf7cd09667 100644 --- a/clang/test/SemaCXX/cxx2a-template-lambdas.cpp +++ b/clang/test/SemaCXX/cxx2a-template-lambdas.cpp @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -std=c++03 -verify -Dstatic_assert=_Static_assert -Wno-c++11-extensions -Wno-c++14-extensions -Wno-c++17-extensions -Wno-c++20-extensions %s // RUN: %clang_cc1 -std=c++11 -verify=expected,cxx11,cxx11-cxx14 -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions %s // RUN: %clang_cc1 -std=c++14 -verify=expected,cxx11-cxx14,cxx14 -Wno-c++20-extensions -Wno-c++17-extensions %s -// RUN: %clang_cc1 -std=c++17 -verify -Wno-c++20-extensions %s -// RUN: %clang_cc1 -std=c++20 -verify %s +// RUN: %clang_cc1 -std=c++17 -verify=expected,cxx17,cxx17-cxx20 -Wno-c++20-extensions %s +// RUN: %clang_cc1 -std=c++20 -verify=expected,cxx20,cxx17-cxx20 %s template<typename, typename> inline const bool is_same = false; @@ -47,6 +47,8 @@ constexpr T outer() { return []<T x>() { return x; }.template operator()<123>(); // expected-error {{no matching member function}} \ expected-note {{candidate template ignored}} \ cxx11-note {{non-literal type '<dependent type>' cannot be used in a constant expression}} \ + cxx11-cxx14-note {{non-type template argument does not refer to any declaration}} \ + cxx17-cxx20-note {{value of type 'int' is not implicitly convertible to 'int *'}} \ cxx14-note {{non-literal type}} } static_assert(outer<int>() == 123); // cxx11-cxx14-error {{not an integral constant expression}} cxx11-cxx14-note {{in call}} diff --git a/clang/test/SemaCXX/typo-correction.cpp b/clang/test/SemaCXX/typo-correction.cpp index 45f42c4260358..c25d01eade890 100644 --- a/clang/test/SemaCXX/typo-correction.cpp +++ b/clang/test/SemaCXX/typo-correction.cpp @@ -614,7 +614,8 @@ int bar() { namespace testIncludeTypeInTemplateArgument { template <typename T, typename U> -void foo(T t = {}, U = {}); // expected-note {{candidate template ignored}} +void foo(T t = {}, U = {}); // expected-note {{candidate template ignored}} \ + // expected-note {{template argument for template type parameter must be a type}} class AddObservation {}; // expected-note {{declared here}} int bar1() { diff --git a/clang/test/SemaTemplate/concepts-using-decl.cpp b/clang/test/SemaTemplate/concepts-using-decl.cpp index fca69dea5c88f..cad160fd585c0 100644 --- a/clang/test/SemaTemplate/concepts-using-decl.cpp +++ b/clang/test/SemaTemplate/concepts-using-decl.cpp @@ -165,8 +165,10 @@ struct base { struct bar : public base { using base::foo; - template <int N> - int foo() { return 2; }; // expected-note {{candidate template ignored: substitution failure: too many template arguments for function template 'foo'}} + template <int N> + int foo() { return 2; }; + // expected-note@-1 {{candidate template ignored: invalid explicitly-specified argument for template parameter 'N'}} \ + // expected-note@-1 {{too many template arguments for function template 'foo'}} }; void func() { diff --git a/clang/test/SemaTemplate/overload-candidates.cpp b/clang/test/SemaTemplate/overload-candidates.cpp index de998d74f9af6..25f0492a71729 100644 --- a/clang/test/SemaTemplate/overload-candidates.cpp +++ b/clang/test/SemaTemplate/overload-candidates.cpp @@ -16,10 +16,12 @@ void test_dyn_cast(int* ptr) { (void)dyn_cast(ptr); // expected-error{{no matching function for call to 'dyn_cast'}} } -template<int I, typename T> - void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for template parameter 'I'}} -template<template<class T> class, typename T> - void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} +template<int I, typename T> + void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for template parameter 'I'}} \ + // expected-note {{template argument for non-type template parameter must be an expression}} +template<template<class T> class, typename T> + void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} \ + // expected-note {{template argument for template template parameter must be a class template}} void test_get(void *ptr) { get<int>(ptr); // expected-error{{no matching function for call to 'get'}} diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp index 5752cbac0291d..44bc5b7642f76 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp @@ -42,8 +42,9 @@ template <int a, unsigned b, int c> void TempFunc() {} void Useage() { - //expected-error@+2 {{no matching function}} - //expected-note@-4 {{candidate template ignored: invalid explicitly-specified argument for template parameter 'b'}} + //expected-error@+3 {{no matching function}} + //expected-note@-4 {{candidate template ignored: invalid explicitly-specified argument for template parameter 'b'}} \ + //expected-note@-4 {{non-type template argument evaluates to -1, which cannot be narrowed to type 'unsigned int'}} TempFunc<1, -1, 1>(); } } >From 9fa53c12cee111d6a219705c917af8261d856a60 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Fri, 9 May 2025 14:32:30 +0800 Subject: [PATCH 2/4] Fix tests --- clang/test/Modules/cxx-templates.cpp | 2 +- clang/test/SemaTemplate/concepts-using-decl.cpp | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp index dce93f866b15c..cc3ce41fbdf61 100644 --- a/clang/test/Modules/cxx-templates.cpp +++ b/clang/test/Modules/cxx-templates.cpp @@ -43,7 +43,7 @@ void g() { template_param_kinds_2<Tmpl_T_C>(); // expected-error {{no matching function for call}} // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}} - // expected-note@Inputs/cxx-templates-a.h:11 {{too many template arguments for class template 'Tmpl_T_C'}} + // expected-note@Inputs/cxx-templates-a.h:11 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}} // expected-note@Inputs/cxx-templates-b.h:11 {{candidate}} template_param_kinds_2<Tmpl_T_I_I>(); // expected-error {{ambiguous}} diff --git a/clang/test/SemaTemplate/concepts-using-decl.cpp b/clang/test/SemaTemplate/concepts-using-decl.cpp index cad160fd585c0..6e9c21dab70bc 100644 --- a/clang/test/SemaTemplate/concepts-using-decl.cpp +++ b/clang/test/SemaTemplate/concepts-using-decl.cpp @@ -166,9 +166,7 @@ struct base { struct bar : public base { using base::foo; template <int N> - int foo() { return 2; }; - // expected-note@-1 {{candidate template ignored: invalid explicitly-specified argument for template parameter 'N'}} \ - // expected-note@-1 {{too many template arguments for function template 'foo'}} + int foo() { return 2; }; // expected-note {{candidate template ignored: substitution failure: too many template arguments for function template 'foo'}} }; void func() { >From a007101158976d957e9d63330f3a8723dc1467a0 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Sat, 10 May 2025 18:59:03 +0800 Subject: [PATCH 3/4] [Clang] Don't ditch typo-corrected lookup result For a member function call like 'foo.bar<int>()', there are two typo-correction points after parsing the dot. The first occurs in ParseOptionalCXXScopeSpecifier, which tries to annotate the template name following any scope specifiers. If the template name bar is not found within 'foo', the parser was previously instructed to drop any function templates found outside of the scope. This was intended to prevent ambiguity in expressions like 'foo->bar < 7', as explained in commit 50a3cddd. However, it's unnecessary to discard typo-corrected results that were strictly resolved within the scope 'foo'. We won't perform a second typo-correction in ParseUnqualifiedId after the name being annotated. --- clang/docs/ReleaseNotes.rst | 3 +++ clang/lib/Sema/SemaTemplate.cpp | 3 +++ .../basic/basic.lookup/basic.lookup.classref/p1.cpp | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5ccd346a93b4f..246e10a0bc953 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -412,6 +412,9 @@ Improvements to Clang's diagnostics the ``-Wc99-designator`` diagnostic group, as they also are about the behavior of the C99 feature as it was introduced into C++20. Fixes #GH47037 +- Fixed a duplicate diagnostic when performing typo correction on function template + calls with explicit template arguments. Fixes #GH139226. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 894f072d84989..af1556059f09f 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -523,6 +523,9 @@ bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, if (Found.isAmbiguous()) { Found.clear(); } else if (!Found.empty()) { + // Do not erase the typo-corrected result to avoid duplicating the typo + // correction in future. + AllowFunctionTemplatesInLookup = true; Found.setLookupName(Corrected.getCorrection()); if (LookupCtx) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp index e3599db18350b..3633ef1c293e2 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp @@ -98,3 +98,16 @@ namespace PR11856 { } } } + +namespace GH139226 { + +struct Foo { + template <class T> void LookupWithID(); // expected-note {{declared here}} +}; + +void test(Foo &f) { + f.LookupWithId<int>(); + // expected-error@-1 {{did you mean 'LookupWithID'}} +} + +} >From 6d88e7bd6f578f091f2c73aa6fa6ac6d75cecd69 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Wed, 23 Jul 2025 18:57:27 +0800 Subject: [PATCH 4/4] TODO --- clang/lib/Sema/SemaOverload.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 15a40fb20cc3f..c27cd2e3e7dbc 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -12320,12 +12320,13 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, << (index + 1); } + // TODO: Nested diagnostics might help avoid 'EmitToString' things. if (PartialDiagnosticAt *PDiag = DeductionFailure.getSFINAEDiagnostic()) { unsigned DiagID = S.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Note, "%0"); - SmallString<128> SFINAEArgString; - PDiag->second.EmitToString(S.getDiagnostics(), SFINAEArgString); - S.Diag(Templated->getLocation(), DiagID) << SFINAEArgString; + SmallString<128> DiagContent; + PDiag->second.EmitToString(S.getDiagnostics(), DiagContent); + S.Diag(Templated->getLocation(), DiagID) << DiagContent; } MaybeEmitInheritedConstructorNote(S, Found); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits