diff options
author | Patrick Palka <ppalka@redhat.com> | 2022-02-06 10:47:48 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2022-02-06 10:47:48 -0500 |
commit | 8eb329e963593342855b6072e5692659107337b7 (patch) | |
tree | b861c67b6cd3240eb26404f2152626924f5cbbf9 /gcc | |
parent | f9e900ce9b17dc7d3a3809d0b0648ebe529a87c5 (diff) | |
download | gcc-8eb329e963593342855b6072e5692659107337b7.zip gcc-8eb329e963593342855b6072e5692659107337b7.tar.gz gcc-8eb329e963593342855b6072e5692659107337b7.tar.bz2 |
c++: dependent noexcept-spec on defaulted comparison op [PR96242]
Here we're failing to instantiate the defaulted comparison op's
explicit dependent noexcept-spec. The problem is ultimately that
mark_used relies on maybe_instantiate_noexcept to synthesize a defaulted
comparison op, but the relevant DECL_MAYBE_DELETED fn handling in m_i_n
is intended for such functions whose noexcept-spec wasn't explicitly
provided (and is therefore determined via synthesis), so m_i_n just
exits early afterwards, without considering that the synthesized fn may
have an explicit noexcept-spec that needs instantiating.
This patch fixes this issue by making mark_used directly synthesize a
DECL_MAYBE_DELETED fn before calling maybe_instantiate_noexcept. And
in turn, we can properly restrict the DECL_MAYBE_DELETED fn synthesis
in m_i_n to only those without an explicit noexcept-spec.
PR c++/96242
gcc/cp/ChangeLog:
* decl2.cc (mark_used): Directly synthesize a DECL_MAYBE_DELETED
fn by calling maybe_synthesize_method instead of relying on
maybe_instantiate_noexcept. Move call to m_i_n after the
DECL_DELETED_FN handling.
* pt.cc (maybe_instantiate_noexcept): Restrict DECL_MAYBE_DELETED
fn synthesis to only those with an implicit noexcept-spec, and
return !DECL_DELETED_FN instead of !DECL_MAYBE_DELETED afterwards.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/spaceship-synth15.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/decl2.cc | 43 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 11 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/spaceship-synth15.C | 22 |
3 files changed, 53 insertions, 23 deletions
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index a2aa5f1..7890833 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -5772,27 +5772,34 @@ mark_used (tree decl, tsubst_flags_t complain) if (TREE_CODE (decl) == CONST_DECL) used_types_insert (DECL_CONTEXT (decl)); - if (TREE_CODE (decl) == FUNCTION_DECL - && !DECL_DELETED_FN (decl) - && !maybe_instantiate_noexcept (decl, complain)) - return false; + if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (DECL_MAYBE_DELETED (decl)) + { + ++function_depth; + maybe_synthesize_method (decl); + --function_depth; + } - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_DELETED_FN (decl)) - { - if (DECL_ARTIFICIAL (decl) - && DECL_CONV_FN_P (decl) - && LAMBDA_TYPE_P (DECL_CONTEXT (decl))) - /* We mark a lambda conversion op as deleted if we can't - generate it properly; see maybe_add_lambda_conv_op. */ - sorry ("converting lambda that uses %<...%> to function pointer"); - else if (complain & tf_error) + if (DECL_DELETED_FN (decl)) { - error ("use of deleted function %qD", decl); - if (!maybe_explain_implicit_delete (decl)) - inform (DECL_SOURCE_LOCATION (decl), "declared here"); + if (DECL_ARTIFICIAL (decl) + && DECL_CONV_FN_P (decl) + && LAMBDA_TYPE_P (DECL_CONTEXT (decl))) + /* We mark a lambda conversion op as deleted if we can't + generate it properly; see maybe_add_lambda_conv_op. */ + sorry ("converting lambda that uses %<...%> to function pointer"); + else if (complain & tf_error) + { + error ("use of deleted function %qD", decl); + if (!maybe_explain_implicit_delete (decl)) + inform (DECL_SOURCE_LOCATION (decl), "declared here"); + } + return false; } - return false; + + if (!maybe_instantiate_noexcept (decl, complain)) + return false; } if (VAR_OR_FUNCTION_DECL_P (decl) && DECL_LOCAL_DECL_P (decl)) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index f640612..c7af471 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -25981,7 +25981,11 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) && (!flag_noexcept_type || type_dependent_expression_p (fn))) return true; - if (DECL_MAYBE_DELETED (fn)) + tree fntype = TREE_TYPE (fn); + tree spec = TYPE_RAISES_EXCEPTIONS (fntype); + + if ((!spec || UNEVALUATED_NOEXCEPT_SPEC_P (spec)) + && DECL_MAYBE_DELETED (fn)) { if (fn == current_function_decl) /* We're in start_preparsed_function, keep going. */ @@ -25990,12 +25994,9 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) ++function_depth; maybe_synthesize_method (fn); --function_depth; - return !DECL_MAYBE_DELETED (fn); + return !DECL_DELETED_FN (fn); } - tree fntype = TREE_TYPE (fn); - tree spec = TYPE_RAISES_EXCEPTIONS (fntype); - if (!spec || !TREE_PURPOSE (spec)) return true; diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth15.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth15.C new file mode 100644 index 0000000..00ea6c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth15.C @@ -0,0 +1,22 @@ +// PR c++/96242 +// { dg-do compile { target c++20 } } + +#include <compare> + +template<bool B> +struct X { + auto operator<=>(const X&) const noexcept(B) = default; + bool operator==(const X&) const noexcept(!B) = default; +}; + +X<true> x_t; +static_assert(noexcept(x_t <=> x_t)); +static_assert(noexcept(x_t < x_t)); +static_assert(!noexcept(x_t == x_t)); +static_assert(!noexcept(x_t != x_t)); + +X<false> x_f; +static_assert(!noexcept(x_f <=> x_f)); +static_assert(!noexcept(x_f < x_f)); +static_assert(noexcept(x_f == x_f)); +static_assert(noexcept(x_f != x_f)); |