public inbox for libstdc++-cvs@sourceware.org help / color / mirror / Atom feed
From: Ville Voutilainen <ville@gcc.gnu.org> To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r11-4386] c++: Implement __is_nothrow_constructible and __is_nothrow_assignable Date: Mon, 26 Oct 2020 13:37:00 +0000 (GMT) [thread overview] Message-ID: <20201026133700.0DB513894C2C@sourceware.org> (raw) https://gcc.gnu.org/g:9e2256dcd481ffe3a8c79b65eba19fbb14b7ff8d commit r11-4386-g9e2256dcd481ffe3a8c79b65eba19fbb14b7ff8d Author: Ville Voutilainen <ville.voutilainen@gmail.com> Date: Mon Oct 26 15:36:24 2020 +0200 c++: Implement __is_nothrow_constructible and __is_nothrow_assignable gcc/c-family/ChangeLog: * c-common.c (__is_nothrow_assignable): New. (__is_nothrow_constructible): Likewise. * c-common.h (RID_IS_NOTHROW_ASSIGNABLE): New. (RID_IS_NOTHROW_CONSTRUCTIBLE): Likewise. gcc/cp/ChangeLog: * cp-tree.h (CPTK_IS_NOTHROW_ASSIGNABLE): New. (CPTK_IS_NOTHROW_CONSTRUCTIBLE): Likewise. (is_nothrow_xible): Likewise. * method.c (is_nothrow_xible): New. (is_trivially_xible): Tweak. * parser.c (cp_parser_primary_expression): Handle the new RID_*. (cp_parser_trait_expr): Likewise. * semantics.c (trait_expr_value): Handle the new RID_*. (finish_trait_expr): Likewise. libstdc++-v3/ChangeLog: * include/std/type_traits (__is_nt_constructible_impl): Remove. (__is_nothrow_constructible_impl): Adjust. (is_nothrow_default_constructible): Likewise. (__is_nt_assignable_impl): Remove. (__is_nothrow_assignable_impl): Adjust. Diff: --- gcc/c-family/c-common.c | 2 + gcc/c-family/c-common.h | 1 + gcc/cp/cp-tree.h | 5 +- gcc/cp/method.c | 17 +++++-- gcc/cp/parser.c | 10 ++++ gcc/cp/semantics.c | 8 ++++ .../g++.dg/ext/is_nothrow_constructible1.C | 48 ++++++++++++++++++++ .../g++.dg/ext/is_nothrow_constructible2.C | 15 ++++++ .../g++.dg/ext/is_nothrow_constructible3.C | 8 ++++ .../g++.dg/ext/is_nothrow_constructible4.C | 11 +++++ .../g++.dg/ext/is_nothrow_constructible5.C | 12 +++++ .../g++.dg/ext/is_nothrow_constructible6.C | 11 +++++ libstdc++-v3/include/std/type_traits | 53 ++-------------------- 13 files changed, 148 insertions(+), 53 deletions(-) diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 1787dfdb1d8..d56238aeb01 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -527,6 +527,8 @@ const struct c_common_resword c_common_reswords[] = { "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 }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index bb38e6c76a4..18b489d55a3 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -176,6 +176,7 @@ enum rid 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, diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 5c06ac3789e..1ce20989e13 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1323,7 +1323,9 @@ enum cp_trait_kind 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. */ @@ -6752,6 +6754,7 @@ extern void use_thunk (tree, bool); 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); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 6e4c5f7e83b..16e76351943 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1924,15 +1924,26 @@ is_xible_helper (enum tree_code code, tree to, tree from, bool trivial) 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. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7ec7d42773c..cce3d0a679e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -5637,6 +5637,8 @@ cp_parser_primary_expression (cp_parser *parser, 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 @@ -10501,6 +10503,14 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) 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 (); } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 1e42cd799c2..ac488478f36 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -10133,6 +10133,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) 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; @@ -10213,6 +10219,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) 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; diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_constructible1.C b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible1.C new file mode 100644 index 00000000000..472acf9f88f --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible1.C @@ -0,0 +1,48 @@ +// { 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)); diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_constructible2.C b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible2.C new file mode 100644 index 00000000000..86b9668da6e --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible2.C @@ -0,0 +1,15 @@ +// { 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)); diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_constructible3.C b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible3.C new file mode 100644 index 00000000000..220ee0bb89e --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible3.C @@ -0,0 +1,8 @@ +// { 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>(); diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_constructible4.C b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible4.C new file mode 100644 index 00000000000..9448c2d31e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible4.C @@ -0,0 +1,11 @@ +// { 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)); +} diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_constructible5.C b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible5.C new file mode 100644 index 00000000000..b8471130481 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible5.C @@ -0,0 +1,12 @@ +// PR c++/80991 +// { dg-do compile { target c++11 } } + +template<bool> void foo() +{ + static_assert(__is_nothrow_constructible(int, int), ""); +} + +void bar() +{ + foo<true>(); +} diff --git a/gcc/testsuite/g++.dg/ext/is_nothrow_constructible6.C b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible6.C new file mode 100644 index 00000000000..bdfdfb99de2 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_nothrow_constructible6.C @@ -0,0 +1,11 @@ +// { 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>); diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 9994c9ae3d7..e9a0f55dd4a 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -963,47 +963,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION "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> @@ -1017,7 +979,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// 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"); @@ -1118,15 +1080,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; 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>
reply other threads:[~2020-10-26 13:37 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20201026133700.0DB513894C2C@sourceware.org \ --to=ville@gcc.gnu.org \ --cc=gcc-cvs@gcc.gnu.org \ --cc=libstdc++-cvs@gcc.gnu.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).