/* 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)];
{
tree expr;
cp_unevaluated cp_uneval_guard;
+ const int len = TREE_VEC_LENGTH (from);
if (CLASS_TYPE_P (to))
{
tree ctype = to;
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
}
else
{
- const int len = TREE_VEC_LENGTH (from);
if (len == 0)
return build_value_init (strip_array_types (to), tf_none);
if (len > 1)
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);
--- /dev/null
+// { 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)), "");
+
--- /dev/null
+// { 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), "");
--- /dev/null
+// { 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>, "");
+