From: Egas Ribeiro Date: Sun, 7 Dec 2025 23:35:00 +0000 (+0000) Subject: c++: Fix SFINAE for deleted explicit specializations [PR119343] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bae0ed69e1862add152f1b0618148f931611a9ca;p=thirdparty%2Fgcc.git c++: Fix SFINAE for deleted explicit specializations [PR119343] When checking a deleted explicit specialization in a SFINAE context, we were incorrectly selecting a partial specialization because resolve_nondeduced_context was calling mark_used. But resolving an overload to a single function (per DR 115) does not constitute ODR-use, so mark_used shouldn't be called there. Instead callers should call mark_used or mark_single_function on the result to uniformly handle all resolvable overloads (even non-template-id ones). This turns out to fix the below testcase because it causes convert_to_void for void(X::template g<0>) to properly propagate ODR-use failure (due to deleted g<0>) and return error_mark_node instead of returning void_node. PR c++/119343 gcc/cp/ChangeLog: * pt.cc (resolve_nondeduced_context): Remove mark_used call. gcc/testsuite/ChangeLog: * g++.dg/template/sfinae-deleted-pr119343.C: New test. Signed-off-by: Egas Ribeiro Reviewed-by: Patrick Palka --- diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 8498730b6e4..a9b311be9ac 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -24816,8 +24816,6 @@ resolve_nondeduced_context (tree orig_expr, tsubst_flags_t complain) } if (good == 1) { - if (!mark_used (goodfn, complain) && !(complain & tf_error)) - return error_mark_node; expr = goodfn; if (baselink) expr = build_baselink (BASELINK_BINFO (baselink), diff --git a/gcc/testsuite/g++.dg/template/sfinae-deleted-pr119343.C b/gcc/testsuite/g++.dg/template/sfinae-deleted-pr119343.C new file mode 100644 index 00000000000..065ad605637 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/sfinae-deleted-pr119343.C @@ -0,0 +1,31 @@ +// { dg-do compile { target c++11 } } +// PR c++/119343 - No SFINAE for deleted explicit specializations + +struct true_type { static constexpr bool value = true; }; +struct false_type { static constexpr bool value = false; }; + +struct X { + static void f()=delete; + template static void g(); +}; +template<> void X::g<0>()=delete; +struct Y { + static void f(); + template static void g(); +}; + +template +struct has_f : false_type {}; +template +struct has_f : true_type {}; + +static_assert(!has_f::value, ""); +static_assert(has_f::value, ""); + +template +struct has_g0 : false_type {}; +template +struct has_g0))> : true_type {}; + +static_assert(!has_g0::value, ""); +static_assert(has_g0::value, "");