diff options
author | Nathaniel Shead <nathanieloshead@gmail.com> | 2023-10-28 16:04:52 +1100 |
---|---|---|
committer | Nathaniel Shead <nathanieloshead@gmail.com> | 2023-12-11 13:33:52 +1100 |
commit | 4719b6f5ae4d758f193a17bbd5fb6cbacd702a23 (patch) | |
tree | 8a49b8ba5c0727564bcb0743b825ce1c91cb10ba /gcc/cp | |
parent | ab3daffcbf35566d468c3028e48068a481048baf (diff) | |
download | gcc-4719b6f5ae4d758f193a17bbd5fb6cbacd702a23.zip gcc-4719b6f5ae4d758f193a17bbd5fb6cbacd702a23.tar.gz gcc-4719b6f5ae4d758f193a17bbd5fb6cbacd702a23.tar.bz2 |
c++: Fix noexcept checking for trivial operations [PR96090]
This patch stops eager folding of trivial operations (construction and
assignment) from occurring when checking for noexceptness. This was
previously done in PR c++/53025, but only for copy/move construction,
and the __is_nothrow_xible builtins did not receive the same treatment
when they were added.
To handle `is_nothrow_default_constructible`, the patch also ensures
that when no parameters are passed we do value initialisation instead of
just building the constructor call: in particular, value-initialisation
doesn't necessarily actually invoke the constructor for trivial default
constructors, and so we need to handle this case as well.
This is contrary to the proposed resolution of CWG2820; for now we just
ensure it matches the behaviour of the `noexcept` operator and create
testcases formalising this, and if that issue gets accepted we can
revisit.
PR c++/96090
PR c++/100470
gcc/cp/ChangeLog:
* call.cc (build_over_call): Prevent folding of trivial special
members when checking for noexcept.
* method.cc (constructible_expr): Perform value-initialisation
for empty parameter lists.
(is_nothrow_xible): Treat as noexcept operator.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/noexcept81.C: New test.
* g++.dg/ext/is_nothrow_constructible7.C: New test.
* g++.dg/ext/is_nothrow_constructible8.C: New test.
Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/call.cc | 17 | ||||
-rw-r--r-- | gcc/cp/method.cc | 19 |
2 files changed, 22 insertions, 14 deletions
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index c7efc5b..4f0abf8 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -10247,15 +10247,16 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) /* Avoid actually calling copy constructors and copy assignment operators, if possible. */ - if (! flag_elide_constructors && !force_elide) + if (!force_elide + && (!flag_elide_constructors + /* It's unsafe to elide the operation when handling + a noexcept-expression, it may evaluate to the wrong + value (c++/53025, c++/96090). */ + || cp_noexcept_operand != 0)) /* Do things the hard way. */; - else if (cand->num_convs == 1 - && (DECL_COPY_CONSTRUCTOR_P (fn) - || DECL_MOVE_CONSTRUCTOR_P (fn)) - /* It's unsafe to elide the constructor when handling - a noexcept-expression, it may evaluate to the wrong - value (c++/53025). */ - && (force_elide || cp_noexcept_operand == 0)) + else if (cand->num_convs == 1 + && (DECL_COPY_CONSTRUCTOR_P (fn) + || DECL_MOVE_CONSTRUCTOR_P (fn))) { tree targ; tree arg = argarray[num_artificial_parms_for (fn)]; diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index a70dd5d..26e6eb7 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -2091,6 +2091,7 @@ constructible_expr (tree to, tree from) { tree expr; cp_unevaluated cp_uneval_guard; + const int len = TREE_VEC_LENGTH (from); if (CLASS_TYPE_P (to)) { tree ctype = to; @@ -2098,11 +2099,16 @@ constructible_expr (tree to, tree from) if (!TYPE_REF_P (to)) to = cp_build_reference_type (to, /*rval*/false); tree ob = build_stub_object (to); - vec_alloc (args, TREE_VEC_LENGTH (from)); - for (tree arg : tree_vec_range (from)) - args->quick_push (build_stub_object (arg)); - expr = build_special_member_call (ob, complete_ctor_identifier, &args, - ctype, LOOKUP_NORMAL, tf_none); + if (len == 0) + expr = build_value_init (ctype, tf_none); + else + { + vec_alloc (args, len); + for (tree arg : tree_vec_range (from)) + args->quick_push (build_stub_object (arg)); + expr = build_special_member_call (ob, complete_ctor_identifier, &args, + ctype, LOOKUP_NORMAL, tf_none); + } if (expr == error_mark_node) return error_mark_node; /* The current state of the standard vis-a-vis LWG 2116 is that @@ -2120,7 +2126,6 @@ constructible_expr (tree to, tree from) } else { - const int len = TREE_VEC_LENGTH (from); if (len == 0) return build_value_init (strip_array_types (to), tf_none); if (len > 1) @@ -2216,7 +2221,9 @@ is_trivially_xible (enum tree_code code, tree to, tree from) bool is_nothrow_xible (enum tree_code code, tree to, tree from) { + ++cp_noexcept_operand; tree expr = is_xible_helper (code, to, from, /*trivial*/false); + --cp_noexcept_operand; if (expr == NULL_TREE || expr == error_mark_node) return false; return expr_noexcept_p (expr, tf_none); |