diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/call.cc | 17 | ||||
-rw-r--r-- | gcc/cp/method.cc | 19 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/noexcept81.C | 37 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/is_nothrow_constructible7.C | 20 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/is_nothrow_constructible8.C | 64 |
5 files changed, 143 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); diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept81.C b/gcc/testsuite/g++.dg/cpp0x/noexcept81.C new file mode 100644 index 0000000..8310f7d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept81.C @@ -0,0 +1,37 @@ +// { dg-do compile { target c++11 } } +// PR c++/96090 + +struct yesthrow_t { + yesthrow_t() noexcept(false) = default; + yesthrow_t(const yesthrow_t&) noexcept(false) = default; + yesthrow_t(yesthrow_t&&) noexcept(false) = default; + yesthrow_t& operator=(const yesthrow_t&) noexcept(false) = default; + yesthrow_t& operator=(yesthrow_t&&) noexcept(false) = default; +}; + +yesthrow_t yes; +static_assert(not noexcept(yesthrow_t(static_cast<const yesthrow_t&>(yes))), ""); +static_assert(not noexcept(yesthrow_t(static_cast<yesthrow_t&&>(yes))), ""); +static_assert(not noexcept(yes = static_cast<const yesthrow_t&>(yes)), ""); +static_assert(not noexcept(yes = static_cast<yesthrow_t&&>(yes)), ""); + +// Note: this is value-initialisation, and thus by [dcl.init.general] p9 +// a trivial non-user-provided non-deleted default constructor is not called. +// However, CWG2820 proposes to change this behaviour. +static_assert(noexcept(yesthrow_t()), ""); + +struct nothrow_t { + nothrow_t() noexcept(true) = default; + nothrow_t(const nothrow_t&) noexcept(true) = default; + nothrow_t(nothrow_t&&) noexcept(true) = default; + nothrow_t& operator=(const nothrow_t&) noexcept(true) = default; + nothrow_t& operator=(nothrow_t&&) noexcept(true) = default; +}; + +nothrow_t no; +static_assert(noexcept(nothrow_t()), ""); +static_assert(noexcept(nothrow_t(static_cast<const nothrow_t&>(no))), ""); +static_assert(noexcept(nothrow_t(static_cast<nothrow_t&&>(no))), ""); +static_assert(noexcept(no = static_cast<const nothrow_t&>(no)), ""); +static_assert(noexcept(no = static_cast<nothrow_t&&>(no)), ""); + diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_constructible7.C b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible7.C new file mode 100644 index 0000000..b63b13a --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible7.C @@ -0,0 +1,20 @@ +// { dg-do compile { target c++11 } } +// PR c++/100470 + +struct S1{ + S1(S1&&) noexcept(false); +}; +struct S2{ + S2(S2&&) noexcept(false) = default; +}; +struct S3{ + S3(S3&&) noexcept(false){} +}; +struct S4{ + S4(S4&&) = default; +}; + +static_assert(!__is_nothrow_constructible(S1, S1), ""); +static_assert(!__is_nothrow_constructible(S2, S2), ""); +static_assert(!__is_nothrow_constructible(S3, S3), ""); +static_assert( __is_nothrow_constructible(S4, S4), ""); diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_constructible8.C b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible8.C new file mode 100644 index 0000000..c2a0b93 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible8.C @@ -0,0 +1,64 @@ +// { dg-do compile { target c++11 } } +// PR c++/96090 + +template <typename T> +constexpr bool is_nothrow_default_constructible_v + = __is_nothrow_constructible(T); +template <typename T> +constexpr bool is_nothrow_copy_constructible_v + = __is_nothrow_constructible(T, const T&); +template <typename T> +constexpr bool is_nothrow_move_constructible_v + = __is_nothrow_constructible(T, T&&); +template <typename T> +constexpr bool is_nothrow_copy_assignable_v + = __is_nothrow_assignable(T, const T&); +template <typename T> +constexpr bool is_nothrow_move_assignable_v + = __is_nothrow_assignable(T, T&&); + +struct yesthrow_t { + yesthrow_t() noexcept(false) = default; + yesthrow_t(const yesthrow_t&) noexcept(false) = default; + yesthrow_t(yesthrow_t&&) noexcept(false) = default; + yesthrow_t& operator=(const yesthrow_t&) noexcept(false) = default; + yesthrow_t& operator=(yesthrow_t&&) noexcept(false) = default; +}; + +static_assert(not is_nothrow_copy_constructible_v<yesthrow_t>, ""); +static_assert(not is_nothrow_copy_assignable_v<yesthrow_t>, ""); +static_assert(not is_nothrow_move_constructible_v<yesthrow_t>, ""); +static_assert(not is_nothrow_move_assignable_v<yesthrow_t>, ""); + +// Note: by [meta.unary.prop] p9 this should be value-initialisation, +// and thus by [dcl.init.general] p9 a trivial non-user-provided +// non-deleted default constructor is not called. +// However, CWG2820 proposes to change this behaviour. +static_assert(is_nothrow_default_constructible_v<yesthrow_t>, ""); + +struct nothrow_t { + nothrow_t() noexcept(true) = default; + nothrow_t(const nothrow_t&) noexcept(true) = default; + nothrow_t(nothrow_t&&) noexcept(true) = default; + nothrow_t& operator=(const nothrow_t&) noexcept(true) = default; + nothrow_t& operator=(nothrow_t&&) noexcept(true) = default; +}; + +static_assert(is_nothrow_default_constructible_v<nothrow_t>, ""); +static_assert(is_nothrow_copy_constructible_v<nothrow_t>, ""); +static_assert(is_nothrow_copy_assignable_v<nothrow_t>, ""); +static_assert(is_nothrow_move_constructible_v<nothrow_t>, ""); +static_assert(is_nothrow_move_assignable_v<nothrow_t>, ""); + +struct A { A() noexcept(false) = default; }; +struct B { B(const B&) noexcept(false) = default; }; +struct C { C(C&&) noexcept(false) = default; }; +struct D { D& operator=(const D&) noexcept(false) = default; }; +struct E { E& operator=(E&&) noexcept(false) = default; }; + +static_assert(is_nothrow_default_constructible_v<A>, ""); // see above +static_assert(not is_nothrow_copy_constructible_v<B>, ""); +static_assert(not is_nothrow_move_constructible_v<C>, ""); +static_assert(not is_nothrow_copy_assignable_v<D>, ""); +static_assert(not is_nothrow_move_assignable_v<E>, ""); + |