[v3] c++: Fix SFINAE for deleted explicit specializations [PR119343]

Message ID 20251207233459.1078265-2-egas.g.ribeiro@tecnico.ulisboa.pt
State Committed
Commit bae0ed69e1862add152f1b0618148f931611a9ca
Headers
Series [v3] c++: Fix SFINAE for deleted explicit specializations [PR119343] |

Commit Message

Egas Ribeiro Dec. 7, 2025, 11:35 p.m. UTC
  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.

	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 <egas.g.ribeiro@tecnico.ulisboa.pt>
---
 gcc/cp/pt.cc                                  |  2 --
 .../g++.dg/template/sfinae-deleted-pr119343.C | 31 +++++++++++++++++++
 2 files changed, 31 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/sfinae-deleted-pr119343.C
  

Comments

Patrick Palka Dec. 8, 2025, 5:19 p.m. UTC | #1
On Sun, 7 Dec 2025, Egas Ribeiro wrote:

> 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.

Thanks, looks good!  Pushed as r16-5967 (with a short note of how this
change impacts convert_to_void to the commit msg for my sake :))

> 
> 	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 <egas.g.ribeiro@tecnico.ulisboa.pt>
> ---
>  gcc/cp/pt.cc                                  |  2 --
>  .../g++.dg/template/sfinae-deleted-pr119343.C | 31 +++++++++++++++++++
>  2 files changed, 31 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/template/sfinae-deleted-pr119343.C
> 
> 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<int> static void g();
> +};
> +template<> void X::g<0>()=delete;
> +struct Y {
> +  static void f();
> +  template<int> static void g();
> +};
> +
> +template<class T,class=void>
> +struct has_f : false_type {};
> +template<class T>
> +struct has_f<T,decltype(void(T::f))> : true_type {};
> +
> +static_assert(!has_f<X>::value, "");
> +static_assert(has_f<Y>::value, "");
> +
> +template<class T,class=void>
> +struct has_g0 : false_type {};
> +template<class T>
> +struct has_g0<T,decltype(void(T::template g<0>))> : true_type {};
> +
> +static_assert(!has_g0<X>::value, "");
> +static_assert(has_g0<Y>::value, "");
> -- 
> 2.52.0
> 
>
  

Patch

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<int> static void g();
+};
+template<> void X::g<0>()=delete;
+struct Y {
+  static void f();
+  template<int> static void g();
+};
+
+template<class T,class=void>
+struct has_f : false_type {};
+template<class T>
+struct has_f<T,decltype(void(T::f))> : true_type {};
+
+static_assert(!has_f<X>::value, "");
+static_assert(has_f<Y>::value, "");
+
+template<class T,class=void>
+struct has_g0 : false_type {};
+template<class T>
+struct has_g0<T,decltype(void(T::template g<0>))> : true_type {};
+
+static_assert(!has_g0<X>::value, "");
+static_assert(has_g0<Y>::value, "");