{ "while", RID_WHILE, 0 },
{ "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY },
{ "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY },
+ { "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY },
+ { "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY },
/* C++ transactional memory. */
{ "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
RID_IS_TRIVIALLY_COPYABLE,
RID_IS_UNION, RID_UNDERLYING_TYPE,
RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE,
+ RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE,
/* C++11 */
RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
CPTK_IS_UNION,
CPTK_UNDERLYING_TYPE,
CPTK_IS_ASSIGNABLE,
- CPTK_IS_CONSTRUCTIBLE
+ CPTK_IS_CONSTRUCTIBLE,
+ CPTK_IS_NOTHROW_ASSIGNABLE,
+ CPTK_IS_NOTHROW_CONSTRUCTIBLE
};
/* The types that we are processing. */
extern bool trivial_fn_p (tree);
extern tree forward_parm (tree);
extern bool is_trivially_xible (enum tree_code, tree, tree);
+extern bool is_nothrow_xible (enum tree_code, tree, tree);
extern bool is_xible (enum tree_code, tree, tree);
extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error);
extern bool maybe_explain_implicit_delete (tree);
bool
is_trivially_xible (enum tree_code code, tree to, tree from)
{
- tree expr;
- expr = is_xible_helper (code, to, from, /*trivial*/true);
-
+ tree expr = is_xible_helper (code, to, from, /*trivial*/true);
if (expr == NULL_TREE || expr == error_mark_node)
return false;
tree nt = cp_walk_tree_without_duplicates (&expr, check_nontriv, NULL);
return !nt;
}
+/* Returns true iff TO is nothrow assignable (if CODE is MODIFY_EXPR) or
+ constructible (otherwise) from FROM, which is a single type for
+ assignment or a list of types for construction. */
+
+bool
+is_nothrow_xible (enum tree_code code, tree to, tree from)
+{
+ tree expr = is_xible_helper (code, to, from, /*trivial*/false);
+ if (expr == NULL_TREE || expr == error_mark_node)
+ return false;
+ return expr_noexcept_p (expr, tf_none);
+}
+
/* Returns true iff TO is assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
assignment or a list of types for construction. */
case RID_IS_UNION:
case RID_IS_ASSIGNABLE:
case RID_IS_CONSTRUCTIBLE:
+ case RID_IS_NOTHROW_ASSIGNABLE:
+ case RID_IS_NOTHROW_CONSTRUCTIBLE:
return cp_parser_trait_expr (parser, token->keyword);
// C++ concepts
kind = CPTK_IS_CONSTRUCTIBLE;
variadic = true;
break;
+ case RID_IS_NOTHROW_ASSIGNABLE:
+ kind = CPTK_IS_NOTHROW_ASSIGNABLE;
+ binary = true;
+ break;
+ case RID_IS_NOTHROW_CONSTRUCTIBLE:
+ kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE;
+ variadic = true;
+ break;
default:
gcc_unreachable ();
}
case CPTK_IS_CONSTRUCTIBLE:
return is_xible (INIT_EXPR, type1, type2);
+ case CPTK_IS_NOTHROW_ASSIGNABLE:
+ return is_nothrow_xible (MODIFY_EXPR, type1, type2);
+
+ case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+ return is_nothrow_xible (INIT_EXPR, type1, type2);
+
default:
gcc_unreachable ();
return false;
case CPTK_IS_TRIVIALLY_ASSIGNABLE:
case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+ case CPTK_IS_NOTHROW_ASSIGNABLE:
+ case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
if (!check_trait_type (type1)
|| !check_trait_type (type2))
return error_mark_node;
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+struct A { };
+struct B { B(); operator int(); };
+struct C {
+ C() = default;
+ C(const C&);
+ C(C&&) = default;
+ C& operator=(C&&);
+ C& operator= (const C&) = default;
+};
+struct D { ~D() noexcept(false) {} };
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_nothrow_constructible(A));
+SA(__is_nothrow_constructible(A,A));
+SA(!__is_nothrow_constructible(B));
+SA(__is_nothrow_constructible(B,B));
+
+SA(!__is_nothrow_constructible(A,B));
+SA(!__is_nothrow_constructible(B,A));
+
+SA(__is_nothrow_constructible(C));
+SA(__is_nothrow_constructible(C,C));
+SA(!__is_nothrow_constructible(C,C&));
+SA(__is_nothrow_assignable(C,C&));
+SA(!__is_nothrow_assignable(C,C));
+SA(!__is_nothrow_assignable(C,C&&));
+SA(!__is_nothrow_assignable(void,int));
+SA(!__is_nothrow_assignable(const void,int));
+SA(!__is_nothrow_assignable(volatile void,int));
+SA(!__is_nothrow_assignable(const volatile void,int));
+
+SA(__is_nothrow_constructible(int,int));
+SA(__is_nothrow_constructible(int,double));
+SA(!__is_nothrow_constructible(int,B));
+SA(!__is_nothrow_constructible(void,int));
+SA(!__is_nothrow_constructible(const void,int));
+SA(!__is_nothrow_constructible(volatile void,int));
+SA(!__is_nothrow_constructible(const volatile void,int));
+SA(!__is_nothrow_constructible(int, void*));
+SA(!__is_nothrow_constructible(int, int*));
+SA(!__is_nothrow_constructible(int, const int*));
+SA(!__is_nothrow_constructible(int*, void*));
+SA(!__is_nothrow_constructible(int*, const int*));
+
+SA(!__is_nothrow_constructible(D));
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+struct X {
+ X() = default;
+ template<class... U> X(U...) noexcept;
+};
+
+struct Y {
+ template<class... U> Y(U...);
+};
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_nothrow_constructible(X));
+SA(!__is_nothrow_constructible(Y));
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+template <class T, class... Args> void bar() {
+ static_assert(__is_nothrow_constructible(T, Args...), "");
+}
+
+template void bar<int>();
+template void bar<int,int>();
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+void f()
+{
+ int x;
+ auto l = [=]{ return x; };
+ typedef decltype(l) C;
+ SA(__is_nothrow_constructible(C,C));
+}
--- /dev/null
+// PR c++/80991
+// { dg-do compile { target c++11 } }
+
+template<bool> void foo()
+{
+ static_assert(__is_nothrow_constructible(int, int), "");
+}
+
+void bar()
+{
+ foo<true>();
+}
--- /dev/null
+// { dg-do compile { target c++11 } }
+// PR c++/81589
+
+template <typename k>
+struct z {
+ z() noexcept {
+ k::error;
+ }
+};
+
+int x = __is_nothrow_constructible(z<int>);
"template argument must be a complete class or an unbounded array");
};
- template<bool, typename _Tp, typename... _Args>
- struct __is_nt_constructible_impl
- : public false_type
- { };
-
- template<typename _Tp, typename... _Args>
- struct __is_nt_constructible_impl<true, _Tp, _Args...>
- : public __bool_constant<noexcept(_Tp(std::declval<_Args>()...))>
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_nt_constructible_impl<true, _Tp, _Arg>
- : public __bool_constant<noexcept(static_cast<_Tp>(std::declval<_Arg>()))>
- { };
-
- template<typename _Tp>
- struct __is_nt_constructible_impl<true, _Tp>
- : public __bool_constant<noexcept(_Tp())>
- { };
-
- template<typename _Tp, size_t _Num>
- struct __is_nt_constructible_impl<true, _Tp[_Num]>
- : public __bool_constant<noexcept(typename remove_all_extents<_Tp>::type())>
- { };
-
-#if __cpp_aggregate_paren_init
- template<typename _Tp, size_t _Num, typename _Arg>
- struct __is_nt_constructible_impl<true, _Tp[_Num], _Arg>
- : public __is_nt_constructible_impl<true, _Tp, _Arg>
- { };
-
- template<typename _Tp, size_t _Num, typename... _Args>
- struct __is_nt_constructible_impl<true, _Tp[_Num], _Args...>
- : public __and_<__is_nt_constructible_impl<true, _Tp, _Args>...>
- { };
-#endif
-
template<typename _Tp, typename... _Args>
using __is_nothrow_constructible_impl
- = __is_nt_constructible_impl<__is_constructible(_Tp, _Args...),
- _Tp, _Args...>;
+ = __bool_constant<__is_nothrow_constructible(_Tp, _Args...)>;
/// is_nothrow_constructible
template<typename _Tp, typename... _Args>
/// is_nothrow_default_constructible
template<typename _Tp>
struct is_nothrow_default_constructible
- : public __is_nothrow_constructible_impl<_Tp>::type
+ : public __bool_constant<__is_nothrow_constructible(_Tp)>
{
static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
"template argument must be a complete class or an unbounded array");
};
template<typename _Tp, typename _Up>
- struct __is_nt_assignable_impl
- : public integral_constant<bool, noexcept(declval<_Tp>() = declval<_Up>())>
- { };
-
- template<typename _Tp, typename _Up>
- struct __is_nothrow_assignable_impl
- : public __and_<__bool_constant<__is_assignable(_Tp, _Up)>,
- __is_nt_assignable_impl<_Tp, _Up>>
- { };
+ using __is_nothrow_assignable_impl
+ = __bool_constant<__is_nothrow_assignable(_Tp, _Up)>;
/// is_nothrow_assignable
template<typename _Tp, typename _Up>