On Sat, 6 Dec 2025, Egas Ribeiro wrote:

> Removing mark_used from resolve_nondeduced_context as Patrick and Jason
> suggested caused no regressions.
> 
> Regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> 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.
> 
> This patch removes the mark_used call from resolve_nondeduced_context
> and adds error_mark_node checks to mark_used and mark_single_function.
> 
>       PR c++/119343
> 
> gcc/cp/ChangeLog:
> 
>       * pt.cc (resolve_nondeduced_context): Remove mark_used call.
>       * decl2.cc (mark_used): Return false for error_mark_node.
>       (mark_single_function): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/DRs/dr3061.C: Remove cascading error expectation.
>       * g++.dg/cpp0x/initlist31.C: Likewise.
>       * g++.dg/template/sfinae-deleted-pr119343.C: New test.
> 
> Signed-off-by: Egas Ribeiro <[email protected]>
> ---
>  gcc/cp/decl2.cc                               |  7 ++++-
>  gcc/cp/pt.cc                                  |  2 --
>  gcc/testsuite/g++.dg/DRs/dr3061.C             |  2 +-
>  gcc/testsuite/g++.dg/cpp0x/initlist31.C       |  2 +-
>  .../g++.dg/template/sfinae-deleted-pr119343.C | 31 +++++++++++++++++++
>  5 files changed, 39 insertions(+), 5 deletions(-)
>  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..08f39e7ce87 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 (is_overloaded_fn (expr) == 1
>        && !mark_used (expr, complain)
>        && !(complain & tf_error))
> @@ -6340,10 +6343,12 @@ fn_template_being_defined (tree decl)
>  bool
>  mark_used (tree decl, tsubst_flags_t complain /* = tf_warning_or_error */)
>  {
> +  if (decl == error_mark_node)
> +    return false;
>    /* If we're just testing conversions or resolving overloads, we
>       don't want any permanent effects like forcing functions to be
>       output or instantiating templates.  */
> -  if ((complain & tf_conv))
> +  if (complain & tf_conv)
>      return true;
>  
>    /* If DECL is a BASELINK for a single function, then treat it just
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 7a019d33bda..f992bf5c0bb 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -24815,8 +24815,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;

Huh, interestingly this change alone is sufficient to fix the
testcase from the PR because it causes convert_to_void to exit
early, returning error_mark_node instead of ultimately returning
void_cst (TREE_SIDE_EFFECTS is not set on error_mark_node):

      expr = resolve_nondeduced_context (expr, complain);
      if (!mark_single_function (expr, complain))
        return error_mark_node;
      ...
      if (!TREE_SIDE_EFFECTS (expr))
        expr = void_node;
      return expr;

(which seems like another bug, convert_to_void shouldn't be replacing
error_mark_node with void_cst!)

If the resolve_nondeduced_context change is sufficient to fix the PR,
and doesn't cause any other diagnostic changes in the testsuite, I think
we should go with that as the proper fix for the PR.  We should consider
the error_mark_node early exits from mark_used/single_function (along
with the testsuite adjustments) as a separate patch.  Could you split
the patch into two then?

>         expr = goodfn;
>         if (baselink)
>           expr = build_baselink (BASELINK_BINFO (baselink),
> diff --git a/gcc/testsuite/g++.dg/DRs/dr3061.C 
> b/gcc/testsuite/g++.dg/DRs/dr3061.C
> index 728829848f5..bd8b74cdafb 100644
> --- a/gcc/testsuite/g++.dg/DRs/dr3061.C
> +++ b/gcc/testsuite/g++.dg/DRs/dr3061.C
> @@ -12,7 +12,7 @@ foo ()
>    template for (int x : { 1, })              // { dg-warning "'template for' 
> only available with" "" { target c++23_down } }
>      ;
>    for (int x : { , })                        // { dg-error "expected 
> primary-expression before ',' token" }
> -    ;                                        // { dg-error "unable to 
> deduce" "" { target *-*-* } .-1 }
> +    ;
>    template for (int x : { , })               // { dg-warning "'template for' 
> only available with" "" { target c++23_down } }
>      ;                                        // { dg-error "expected 
> primary-expression before ',' token" "" { target *-*-* } .-1 }
>  }
> diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist31.C 
> b/gcc/testsuite/g++.dg/cpp0x/initlist31.C
> index a8a29f9c853..6d88edb397f 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/initlist31.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/initlist31.C
> @@ -9,5 +9,5 @@ void f() {
>    auto y =
>    {
>      string(Equation()) // { dg-error "12:'Equation' was not declared" }
> -  }; // { dg-error "unable to deduce" }
> +  };
>  }
> 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