diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ae699ebfc6038..6f7e54252150c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -713,6 +713,9 @@ Bug Fixes to C++ Support - Correctly treat the compound statement of an ``if consteval`` as an immediate context. Fixes (#GH91509). - When partial ordering alias templates against template template parameters, allow pack expansions when the alias has a fixed-size parameter list. Fixes (#GH62529). +- Clang now ignores template parameters only used within the exception specification of candidate function + templates during partial ordering when deducing template arguments from a function declaration or when + taking the address of a function template. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 853c0e1b50619..b5d405111fe4c 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -5453,7 +5453,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, // is used. if (DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, FD2->getType(), FD1->getType(), Info, Deduced, - TDF_None, + TDF_AllowCompatibleFunctionType, /*PartialOrdering=*/true) != TemplateDeductionResult::Success) return false; break; @@ -5485,20 +5485,40 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, switch (TPOC) { case TPOC_Call: for (unsigned I = 0, N = Args2.size(); I != N; ++I) - ::MarkUsedTemplateParameters(S.Context, Args2[I], false, - TemplateParams->getDepth(), - UsedParameters); + ::MarkUsedTemplateParameters(S.Context, Args2[I], /*OnlyDeduced=*/false, + TemplateParams->getDepth(), UsedParameters); break; case TPOC_Conversion: - ::MarkUsedTemplateParameters(S.Context, Proto2->getReturnType(), false, + ::MarkUsedTemplateParameters(S.Context, Proto2->getReturnType(), + /*OnlyDeduced=*/false, TemplateParams->getDepth(), UsedParameters); break; case TPOC_Other: - ::MarkUsedTemplateParameters(S.Context, FD2->getType(), false, - TemplateParams->getDepth(), - UsedParameters); + // We do not deduce template arguments from the exception specification + // when determining the primary template of a function template + // specialization or when taking the address of a function template. + // Therefore, we do not mark template parameters in the exception + // specification as used during partial ordering to prevent the following + // from being ambiguous: + // + // template + // void f(U) noexcept(noexcept(T())); // #1 + // + // template + // void f(T*) noexcept; // #2 + // + // template<> + // void f(int*) noexcept; // explicit specialization of #2 + // + // Although there is no corresponding wording in the standard, this seems + // to be the intended behavior given the definition of + // 'deduction substitution loci' in [temp.deduct]. + ::MarkUsedTemplateParameters( + S.Context, + S.Context.getFunctionTypeWithExceptionSpec(FD2->getType(), EST_None), + /*OnlyDeduced=*/false, TemplateParams->getDepth(), UsedParameters); break; } diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p3.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p3.cpp new file mode 100644 index 0000000000000..cc1d4ecda2ecc --- /dev/null +++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p3.cpp @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +template +struct A { }; + +constexpr A a; +constexpr A b; + +constexpr int* x = nullptr; +constexpr short* y = nullptr; + +namespace ExplicitArgs { + template + constexpr int f(U) noexcept(noexcept(T())) { + return 0; + } + + template + constexpr int f(T*) noexcept { + return 1; + } + + template<> + constexpr int f(int*) noexcept { + return 2; + } + + static_assert(f(1) == 0); + static_assert(f(y) == 1); + static_assert(f(x) == 2); + + template + constexpr int g(U*) noexcept(noexcept(T())) { + return 3; + } + + template + constexpr int g(T) noexcept { + return 4; + } + + template<> + constexpr int g(int*) noexcept { + return 5; + } + + static_assert(g(y) == 3); + static_assert(g(1) == 4); + static_assert(g(x) == 5); +} // namespace ExplicitArgs + +namespace DeducedArgs { + template + constexpr int f(T, A) noexcept(B) { + return 0; + } + + template + constexpr int f(T*, A) noexcept(B && B) { + return 1; + } + + template<> + constexpr int f(int*, A) { + return 2; + } + + static_assert(f(x, a) == 0); + static_assert(f(y, a) == 1); + static_assert(f(x, a) == 2); +} // namespace DeducedArgs