Hi Egas, thanks for tackling this bug!

On Sun, 30 Nov 2025, Egas Ribeiro wrote:

> Regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> When checking a deleted explicit specialization in a SFINAE context,
> we were failing to propagate the error from mark_used.  The call to
> resolve_nondeduced_context in convert_to_void correctly returned
> error_mark_node,

I wonder actually whether resolve_nondeduced_context is correct to
return error_mark_node in this case.  Sure the single X::g<0>
overload selected by resolve_nondeduced_context is deleted, but
should that imply an ODR-use of the overload?  Maybe it should be the
responsibility of the caller to call mark_used, and we should remove the
mark_used in resolve_nondeduced_context.

Note that resolve_nondeduced_context does not call mark_used when
the overload set is _not_ a template-id.  So the caller will likely
have to call mark_used anyway to uniformly handle template-id and
non-template-id overloads.

Jason, what do you think?

> but mark_single_function didn't check for this,
> causing the error to be lost and the partial specialization to be
> incorrectly selected.
> 
>       PR c++/119343
> 
> gcc/cp/ChangeLog:
> 
>       * decl2.cc (mark_single_function): Return false for error_mark_node.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/template/sfinae-deleted-pr119343.C: New test.
> 
> Signed-off-by: Egas Ribeiro <[email protected]>
> ---
> 
>  gcc/cp/decl2.cc                               |  3 ++
>  .../g++.dg/template/sfinae-deleted-pr119343.C | 31 +++++++++++++++++++
>  2 files changed, 34 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/template/sfinae-deleted-pr119343.C
> 
> diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
> index 9e135af41b3..17d905ab5b1 100644
> --- a/gcc/cp/decl2.cc
> +++ b/gcc/cp/decl2.cc
> @@ -6298,6 +6298,9 @@ mark_single_function (tree expr, tsubst_flags_t 
> complain)
>    expr = maybe_undo_parenthesized_ref (expr);
>    expr = tree_strip_any_location_wrapper (expr);
>  
> +  if (expr == error_mark_node)
> +    return false;

If the above approach doesn't sound right then I agree that
mark_single_function as well as mark_used should return false
for error_mark_node.

> +
>    if (is_overloaded_fn (expr) == 1
>        && !mark_used (expr, complain)
>        && !(complain & tf_error))
> 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
> 
> 

Reply via email to