* [C++ PATCH, RFC] Implement new C++ intrinsics __is_assignable and __is_constructible.
@ 2017-05-12 10:43 Ville Voutilainen
2017-05-12 11:07 ` Daniel Krügler
0 siblings, 1 reply; 8+ messages in thread
From: Ville Voutilainen @ 2017-05-12 10:43 UTC (permalink / raw)
To: gcc-patches, libstdc++
[-- Attachment #1: Type: text/plain, Size: 3044 bytes --]
I have tested this with the full suite on Linux-PPC64. It works otherwise fine,
but there's one snag: 20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc
fails, and it looks like the trait ends up instantiating the definition
of a destructor, which then ends up being hard-error ill-formed.
That is, we have
struct C { };
void swap(C&, C&) = delete;
static_assert( !std::is_swappable_v<std::unique_ptr<int, C>> );
struct D { D(D&&) = delete; };
static_assert( !std::is_swappable_v<std::unique_ptr<int, D>> );
The destructor definitions of unique_ptr<int, C> and unique_ptr<int D>
are not valid because that destructor will try to call an operator()
on those deleters, and they don't have that operator.
The existing library implementation of is_constructible doesn't
instantiate the destructor definitions, or if it does, they don't cause
a hard error. This intrinsic trait approach behaves differently, and I would
welcome any help fixing that problem.
2017-05-12 Ville Voutilainen <ville.voutilainen@gmail.com>
c-family/
Implement new C++ intrinsics __is_assignable and __is_constructible.
* c-common.c (__is_assignable, __is_constructible): New.
* c-common.h (RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE): Likewise.
cp/
Implement new C++ intrinsics __is_assignable and __is_constructible.
* cp-tree.h (CPTK_IS_ASSIGNABLE, CPTK_IS_CONSTRUCTIBLE): New.
(is_xible): New.
* cxx-pretty-print.c (pp_cxx_trait_expression): Handle
CPTK_IS_ASSIGNABLE and CPTK_IS_CONSTRUCTIBLE.
* method.c (is_xible_helper): New.
(is_trivially_xible): Adjust.
(is_xible): New.
* parser.c (cp_parser_primary_expression): Handle
RID_IS_ASSIGNABLE and RID_IS_CONSTRUCTIBLE.
(cp_parser_trait_expr): Likewise.
* semantics.c (trait_expr_value): Handle
CPTK_IS_ASSIGNABLE and CPTK_IS_CONSTRUCTIBLE.
libstdc++-v3/
Implement new C++ intrinsics __is_assignable and __is_constructible.
* include/std/type_traits (__do_is_static_castable_impl): Remove.
(__is_static_castable_impl, __is_static_castable_safe): Likewise.
(__is_static_castable, __do_is_direct_constructible_impl): Likewise.
(__is_direct_constructible_impl): Likewise.
(__is_direct_constructible_new_safe): Likewise.
(__is_base_to_derived_ref, __is_lvalue_to_rvalue_ref): Likewise.
(__is_direct_constructible_ref_cast): Likewise.
(__is_direct_constructible_new, __is_direct_constructible): Likewise.
(__do_is_nary_constructible_impl): Likewise.
(__is_nary_constructible_impl, __is_nary_constructible): Likewise.
(__is_constructible_impl): Likewise.
(is_constructible): Call the intrinsic.
(__is_assignable_helper): Remove.
(is_assignable): Call the intrinsic.
(is_trivially_constructible): Likewise.
(is_trivially_assignable): Likewise.
(testsuite/20_util/declval/requirements/1_neg.cc): Adjust.
(testsuite/20_util/make_signed/requirements/typedefs_neg.cc): Likewise.
(testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc):
Likewise.
[-- Attachment #2: is_constructible.diff --]
[-- Type: text/plain, Size: 17598 bytes --]
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index ad686d2..369e112 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -514,6 +514,8 @@ const struct c_common_resword c_common_reswords[] =
{ "volatile", RID_VOLATILE, 0 },
{ "wchar_t", RID_WCHAR, D_CXXONLY },
{ "while", RID_WHILE, 0 },
+ { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY },
+ { "__is_constructible", RID_IS_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 9e3982d..a986056 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -172,6 +172,7 @@ enum rid
RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE,
RID_IS_TRIVIALLY_COPYABLE,
RID_IS_UNION, RID_UNDERLYING_TYPE,
+ RID_IS_ASSIGNABLE, RID_IS_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 09b1364..154ba3c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -927,7 +927,9 @@ enum cp_trait_kind
CPTK_IS_TRIVIALLY_CONSTRUCTIBLE,
CPTK_IS_TRIVIALLY_COPYABLE,
CPTK_IS_UNION,
- CPTK_UNDERLYING_TYPE
+ CPTK_UNDERLYING_TYPE,
+ CPTK_IS_ASSIGNABLE,
+ CPTK_IS_CONSTRUCTIBLE
};
/* The types that we are processing. */
@@ -6112,6 +6114,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_xible (enum tree_code, tree, tree);
extern tree get_defaulted_eh_spec (tree);
extern tree unevaluated_noexcept_spec (void);
extern void after_nsdmi_defaulted_late_checks (tree);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index f76c30a..71d149a 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -2634,6 +2634,12 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
case CPTK_IS_LITERAL_TYPE:
pp_cxx_ws_string (pp, "__is_literal_type");
break;
+ case CPTK_IS_ASSIGNABLE:
+ pp_cxx_ws_string (pp, "__is_assignable");
+ break;
+ case CPTK_IS_CONSTRUCTIBLE:
+ pp_cxx_ws_string (pp, "__is_constructible");
+ break;
default:
gcc_unreachable ();
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 99e98cc..a377321 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1200,22 +1200,36 @@ constructible_expr (tree to, tree from)
return expr;
}
-/* Returns true iff TO is trivially assignable (if CODE is MODIFY_EXPR) or
+/* Returns a tree 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. */
-bool
-is_trivially_xible (enum tree_code code, tree to, tree from)
+static tree
+is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
{
- if (VOID_TYPE_P (to))
- return false;
+ if (VOID_TYPE_P (to) || ABSTRACT_CLASS_TYPE_P (to)
+ || (from && FUNC_OR_METHOD_TYPE_P (from)
+ && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))))
+ return error_mark_node;
tree expr;
if (code == MODIFY_EXPR)
expr = assignable_expr (to, from);
- else if (from && TREE_CHAIN (from))
- return false; // only 0- and 1-argument ctors can be trivial
+ else if (trivial && from && TREE_CHAIN (from))
+ return error_mark_node; // only 0- and 1-argument ctors can be trivial
else
expr = constructible_expr (to, from);
+ return expr;
+}
+
+/* Returns true iff TO is trivially 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_trivially_xible (enum tree_code code, tree to, tree from)
+{
+ tree expr;
+ expr = is_xible_helper (code, to, from, /*trivial*/true);
if (expr == error_mark_node)
return false;
@@ -1223,6 +1237,19 @@ is_trivially_xible (enum tree_code code, tree to, tree from)
return !nt;
}
+/* 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. */
+
+bool
+is_xible (enum tree_code code, tree to, tree from)
+{
+ tree expr = is_xible_helper (code, to, from, /*trivial*/false);
+ if (expr == error_mark_node)
+ return false;
+ return !!expr;
+}
+
/* Subroutine of synthesized_method_walk. Update SPEC_P, TRIVIAL_P and
DELETED_P or give an error message MSG with argument ARG. */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 17d2679..5986dd9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5135,6 +5135,8 @@ cp_parser_primary_expression (cp_parser *parser,
case RID_IS_TRIVIALLY_CONSTRUCTIBLE:
case RID_IS_TRIVIALLY_COPYABLE:
case RID_IS_UNION:
+ case RID_IS_ASSIGNABLE:
+ case RID_IS_CONSTRUCTIBLE:
return cp_parser_trait_expr (parser, token->keyword);
// C++ concepts
@@ -9686,6 +9688,14 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
case RID_DIRECT_BASES:
kind = CPTK_DIRECT_BASES;
break;
+ case RID_IS_ASSIGNABLE:
+ kind = CPTK_IS_ASSIGNABLE;
+ binary = true;
+ break;
+ case RID_IS_CONSTRUCTIBLE:
+ kind = CPTK_IS_CONSTRUCTIBLE;
+ variadic = true;
+ break;
default:
gcc_unreachable ();
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7b2c101..f9f402e 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -9209,6 +9209,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_UNION:
return type_code1 == UNION_TYPE;
+ case CPTK_IS_ASSIGNABLE:
+ return is_xible (MODIFY_EXPR, type1, type2);
+
+ case CPTK_IS_CONSTRUCTIBLE:
+ return is_xible (INIT_EXPR, type1, type2);
+
default:
gcc_unreachable ();
return false;
@@ -9282,6 +9288,10 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
return error_mark_node;
break;
+ case CPTK_IS_ASSIGNABLE:
+ case CPTK_IS_CONSTRUCTIBLE:
+ break;
+
case CPTK_IS_TRIVIALLY_ASSIGNABLE:
case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
if (!check_trait_type (type1)
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index aac7cff..00f647b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -924,213 +924,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public __is_default_constructible_safe<_Tp>::type
{ };
-
- // Implementation of is_constructible.
-
- // The hardest part of this trait is the binary direct-initialization
- // case, because we hit into a functional cast of the form T(arg).
- // This implementation uses different strategies depending on the
- // target type to reduce the test overhead as much as possible:
- //
- // a) For a reference target type, we use a static_cast expression
- // modulo its extra cases.
- //
- // b) For a non-reference target type we use a ::new expression.
- struct __do_is_static_castable_impl
- {
- template<typename _From, typename _To, typename
- = decltype(static_cast<_To>(declval<_From>()))>
- static true_type __test(int);
-
- template<typename, typename>
- static false_type __test(...);
- };
-
- template<typename _From, typename _To>
- struct __is_static_castable_impl
- : public __do_is_static_castable_impl
- {
- typedef decltype(__test<_From, _To>(0)) type;
- };
-
- template<typename _From, typename _To>
- struct __is_static_castable_safe
- : public __is_static_castable_impl<_From, _To>::type
- { };
-
- // __is_static_castable
- template<typename _From, typename _To>
- struct __is_static_castable
- : public integral_constant<bool, (__is_static_castable_safe<
- _From, _To>::value)>
- { };
-
- // Implementation for non-reference types. To meet the proper
- // variable definition semantics, we also need to test for
- // is_destructible in this case.
- // This form should be simplified by a single expression:
- // ::delete ::new _Tp(declval<_Arg>()), see c++/51222.
- struct __do_is_direct_constructible_impl
- {
- template<typename _Tp, typename _Arg, typename
- = decltype(::new _Tp(declval<_Arg>()))>
- static true_type __test(int);
-
- template<typename, typename>
- static false_type __test(...);
- };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_impl
- : public __do_is_direct_constructible_impl
- {
- typedef decltype(__test<_Tp, _Arg>(0)) type;
- };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_new_safe
- : public __and_<is_destructible<_Tp>,
- __is_direct_constructible_impl<_Tp, _Arg>>
- { };
-
- template<typename, typename>
- struct is_same;
-
- template<typename, typename>
- struct is_base_of;
-
- template<typename>
- struct remove_reference;
-
- template<typename _From, typename _To, bool
- = __not_<__or_<is_void<_From>,
- is_function<_From>>>::value>
- struct __is_base_to_derived_ref;
-
- template<typename _Tp, typename... _Args>
- struct is_constructible;
-
- // Detect whether we have a downcast situation during
- // reference binding.
- template<typename _From, typename _To>
- struct __is_base_to_derived_ref<_From, _To, true>
- {
- typedef typename remove_cv<typename remove_reference<_From
- >::type>::type __src_t;
- typedef typename remove_cv<typename remove_reference<_To
- >::type>::type __dst_t;
- typedef __and_<__not_<is_same<__src_t, __dst_t>>,
- is_base_of<__src_t, __dst_t>,
- __not_<is_constructible<__dst_t, _From>>> type;
- static constexpr bool value = type::value;
- };
-
- template<typename _From, typename _To>
- struct __is_base_to_derived_ref<_From, _To, false>
- : public false_type
- { };
-
- template<typename _From, typename _To, bool
- = __and_<is_lvalue_reference<_From>,
- is_rvalue_reference<_To>>::value>
- struct __is_lvalue_to_rvalue_ref;
-
- // Detect whether we have an lvalue of non-function type
- // bound to a reference-compatible rvalue-reference.
- template<typename _From, typename _To>
- struct __is_lvalue_to_rvalue_ref<_From, _To, true>
- {
- typedef typename remove_cv<typename remove_reference<
- _From>::type>::type __src_t;
- typedef typename remove_cv<typename remove_reference<
- _To>::type>::type __dst_t;
- typedef __and_<__not_<is_function<__src_t>>,
- __or_<is_same<__src_t, __dst_t>,
- is_base_of<__dst_t, __src_t>>> type;
- static constexpr bool value = type::value;
- };
-
- template<typename _From, typename _To>
- struct __is_lvalue_to_rvalue_ref<_From, _To, false>
- : public false_type
- { };
-
- // Here we handle direct-initialization to a reference type as
- // equivalent to a static_cast modulo overshooting conversions.
- // These are restricted to the following conversions:
- // a) A base class value to a derived class reference
- // b) An lvalue to an rvalue-reference of reference-compatible
- // types that are not functions
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_ref_cast
- : public __and_<__is_static_castable<_Arg, _Tp>,
- __not_<__or_<__is_base_to_derived_ref<_Arg, _Tp>,
- __is_lvalue_to_rvalue_ref<_Arg, _Tp>
- >>>
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_new
- : public conditional<is_reference<_Tp>::value,
- __is_direct_constructible_ref_cast<_Tp, _Arg>,
- __is_direct_constructible_new_safe<_Tp, _Arg>
- >::type
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible
- : public __is_direct_constructible_new<_Tp, _Arg>::type
- { };
-
- // Since default-construction and binary direct-initialization have
- // been handled separately, the implementation of the remaining
- // n-ary construction cases is rather straightforward. We can use
- // here a functional cast, because array types are excluded anyway
- // and this form is never interpreted as a C cast.
- struct __do_is_nary_constructible_impl
- {
- template<typename _Tp, typename... _Args, typename
- = decltype(_Tp(declval<_Args>()...))>
- static true_type __test(int);
-
- template<typename, typename...>
- static false_type __test(...);
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_nary_constructible_impl
- : public __do_is_nary_constructible_impl
- {
- typedef decltype(__test<_Tp, _Args...>(0)) type;
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_nary_constructible
- : public __is_nary_constructible_impl<_Tp, _Args...>::type
- {
- static_assert(sizeof...(_Args) > 1,
- "Only useful for > 1 arguments");
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_constructible_impl
- : public __is_nary_constructible<_Tp, _Args...>
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_constructible_impl<_Tp, _Arg>
- : public __is_direct_constructible<_Tp, _Arg>
- { };
-
- template<typename _Tp>
- struct __is_constructible_impl<_Tp>
- : public is_default_constructible<_Tp>
- { };
-
/// is_constructible
template<typename _Tp, typename... _Args>
struct is_constructible
- : public __is_constructible_impl<_Tp, _Args...>::type
+ : public __bool_constant<__is_constructible(_Tp, _Args...)>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1255,26 +1052,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public __is_nothrow_move_constructible_impl<_Tp>
{ };
- template<typename _Tp, typename _Up>
- class __is_assignable_helper
- {
- template<typename _Tp1, typename _Up1,
- typename = decltype(declval<_Tp1>() = declval<_Up1>())>
- static true_type
- __test(int);
-
- template<typename, typename>
- static false_type
- __test(...);
-
- public:
- typedef decltype(__test<_Tp, _Up>(0)) type;
- };
-
/// is_assignable
template<typename _Tp, typename _Up>
struct is_assignable
- : public __is_assignable_helper<_Tp, _Up>::type
+ : public __bool_constant<__is_assignable(_Tp, _Up)>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1364,8 +1145,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// is_trivially_constructible
template<typename _Tp, typename... _Args>
struct is_trivially_constructible
- : public __and_<is_constructible<_Tp, _Args...>, integral_constant<bool,
- __is_trivially_constructible(_Tp, _Args...)>>
+ : public __bool_constant<__is_trivially_constructible(_Tp, _Args...)>
{ };
/// is_trivially_default_constructible
@@ -1423,9 +1203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// is_trivially_assignable
template<typename _Tp, typename _Up>
struct is_trivially_assignable
- : public __and_<is_assignable<_Tp, _Up>,
- integral_constant<bool,
- __is_trivially_assignable(_Tp, _Up)>>
+ : public __bool_constant<__is_trivially_assignable(_Tp, _Up)>
{ };
/// is_trivially_copy_assignable
diff --git a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
index dc9daeb..0c5599d 100644
--- a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
@@ -18,7 +18,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-error "static assertion failed" "" { target *-*-* } 2259 }
+// { dg-error "static assertion failed" "" { target *-*-* } 2037 }
#include <utility>
diff --git a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
index 664fb70..4b83764 100644
--- a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
@@ -47,4 +47,4 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 39 }
// { dg-error "required from here" "" { target *-*-* } 41 }
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1924 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1702 }
diff --git a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
index 6d64717..d77b023 100644
--- a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
@@ -47,5 +47,5 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 39 }
// { dg-error "required from here" "" { target *-*-* } 41 }
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1820 }
-// { dg-error "declaration of" "" { target *-*-* } 1777 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1598 }
+// { dg-error "declaration of" "" { target *-*-* } 1555 }
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [C++ PATCH, RFC] Implement new C++ intrinsics __is_assignable and __is_constructible.
2017-05-12 10:43 [C++ PATCH, RFC] Implement new C++ intrinsics __is_assignable and __is_constructible Ville Voutilainen
@ 2017-05-12 11:07 ` Daniel Krügler
2017-05-12 11:27 ` Ville Voutilainen
0 siblings, 1 reply; 8+ messages in thread
From: Daniel Krügler @ 2017-05-12 11:07 UTC (permalink / raw)
To: Ville Voutilainen; +Cc: gcc-patches, libstdc++
2017-05-12 12:39 GMT+02:00 Ville Voutilainen <ville.voutilainen@gmail.com>:
> I have tested this with the full suite on Linux-PPC64. It works otherwise fine,
> but there's one snag: 20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc
> fails, and it looks like the trait ends up instantiating the definition
> of a destructor, which then ends up being hard-error ill-formed.
I'm pretty sure that the library-based implementation does not
instantiate the destructor definition.
Your description sounds remotely similar to me to the current problem
of __is_trivially_constructible intrinsic, which seems to instantiate
the copy constructor definition albeit it (IMO) shouldn't:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80654
Could there be a similar cause?
- Daniel
> That is, we have
>
> struct C { };
> void swap(C&, C&) = delete;
> static_assert( !std::is_swappable_v<std::unique_ptr<int, C>> );
>
> struct D { D(D&&) = delete; };
> static_assert( !std::is_swappable_v<std::unique_ptr<int, D>> );
>
> The destructor definitions of unique_ptr<int, C> and unique_ptr<int D>
> are not valid because that destructor will try to call an operator()
> on those deleters, and they don't have that operator.
>
> The existing library implementation of is_constructible doesn't
> instantiate the destructor definitions, or if it does, they don't cause
> a hard error. This intrinsic trait approach behaves differently, and I would
> welcome any help fixing that problem.
>
> 2017-05-12 Ville Voutilainen <ville.voutilainen@gmail.com>
>
> c-family/
>
> Implement new C++ intrinsics __is_assignable and __is_constructible.
> * c-common.c (__is_assignable, __is_constructible): New.
> * c-common.h (RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE): Likewise.
>
> cp/
>
> Implement new C++ intrinsics __is_assignable and __is_constructible.
> * cp-tree.h (CPTK_IS_ASSIGNABLE, CPTK_IS_CONSTRUCTIBLE): New.
> (is_xible): New.
> * cxx-pretty-print.c (pp_cxx_trait_expression): Handle
> CPTK_IS_ASSIGNABLE and CPTK_IS_CONSTRUCTIBLE.
> * method.c (is_xible_helper): New.
> (is_trivially_xible): Adjust.
> (is_xible): New.
> * parser.c (cp_parser_primary_expression): Handle
> RID_IS_ASSIGNABLE and RID_IS_CONSTRUCTIBLE.
> (cp_parser_trait_expr): Likewise.
> * semantics.c (trait_expr_value): Handle
> CPTK_IS_ASSIGNABLE and CPTK_IS_CONSTRUCTIBLE.
>
> libstdc++-v3/
>
> Implement new C++ intrinsics __is_assignable and __is_constructible.
> * include/std/type_traits (__do_is_static_castable_impl): Remove.
> (__is_static_castable_impl, __is_static_castable_safe): Likewise.
> (__is_static_castable, __do_is_direct_constructible_impl): Likewise.
> (__is_direct_constructible_impl): Likewise.
> (__is_direct_constructible_new_safe): Likewise.
> (__is_base_to_derived_ref, __is_lvalue_to_rvalue_ref): Likewise.
> (__is_direct_constructible_ref_cast): Likewise.
> (__is_direct_constructible_new, __is_direct_constructible): Likewise.
> (__do_is_nary_constructible_impl): Likewise.
> (__is_nary_constructible_impl, __is_nary_constructible): Likewise.
> (__is_constructible_impl): Likewise.
> (is_constructible): Call the intrinsic.
> (__is_assignable_helper): Remove.
> (is_assignable): Call the intrinsic.
> (is_trivially_constructible): Likewise.
> (is_trivially_assignable): Likewise.
> (testsuite/20_util/declval/requirements/1_neg.cc): Adjust.
> (testsuite/20_util/make_signed/requirements/typedefs_neg.cc): Likewise.
> (testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc):
> Likewise.
--
________________________________
SavedURI :Show URLShow URLSavedURI :
SavedURI :Hide URLHide URLSavedURI :
https://mail.google.com/_/scs/mail-static/_/js/k=gmail.main.de.LEt2fN4ilLE.O/m=m_i,t,it/am=OCMOBiHj9kJxhnelj6j997_NLil29vVAOBGeBBRgJwD-m_0_8B_AD-qOEw/rt=h/d=1/rs=AItRSTODy9wv1JKZMABIG3Ak8ViC4kuOWA?random=1395770800154https://mail.google.com/_/scs/mail-static/_/js/k=gmail.main.de.LEt2fN4ilLE.O/m=m_i,t,it/am=OCMOBiHj9kJxhnelj6j997_NLil29vVAOBGeBBRgJwD-m_0_8B_AD-qOEw/rt=h/d=1/rs=AItRSTODy9wv1JKZMABIG3Ak8ViC4kuOWA?random=1395770800154
________________________________
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [C++ PATCH, RFC] Implement new C++ intrinsics __is_assignable and __is_constructible.
2017-05-12 11:07 ` Daniel Krügler
@ 2017-05-12 11:27 ` Ville Voutilainen
2017-05-12 18:34 ` Ville Voutilainen
0 siblings, 1 reply; 8+ messages in thread
From: Ville Voutilainen @ 2017-05-12 11:27 UTC (permalink / raw)
To: Daniel Krügler, Jason Merrill; +Cc: gcc-patches, libstdc++
On 12 May 2017 at 14:06, Daniel Krügler <daniel.kruegler@gmail.com> wrote:
> 2017-05-12 12:39 GMT+02:00 Ville Voutilainen <ville.voutilainen@gmail.com>:
>> I have tested this with the full suite on Linux-PPC64. It works otherwise fine,
>> but there's one snag: 20_util/unique_ptr/specialized_algorithms/swap_cxx17.cc
>> fails, and it looks like the trait ends up instantiating the definition
>> of a destructor, which then ends up being hard-error ill-formed.
>
> I'm pretty sure that the library-based implementation does not
> instantiate the destructor definition.
>
> Your description sounds remotely similar to me to the current problem
> of __is_trivially_constructible intrinsic, which seems to instantiate
> the copy constructor definition albeit it (IMO) shouldn't:
>
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80654
>
> Could there be a similar cause?
Seems quite plausible to me. I would be happy to fix that bug in the
same go, but I'm a bit
lost as to what exactly causes the problem. constructible_expr in method.c does
build_special_member_call for the constructor and the destructor, so
perhaps there
are some flags that could make it behave.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [C++ PATCH, RFC] Implement new C++ intrinsics __is_assignable and __is_constructible.
2017-05-12 11:27 ` Ville Voutilainen
@ 2017-05-12 18:34 ` Ville Voutilainen
2017-05-15 11:10 ` Jonathan Wakely
2017-05-16 18:46 ` Jason Merrill
0 siblings, 2 replies; 8+ messages in thread
From: Ville Voutilainen @ 2017-05-12 18:34 UTC (permalink / raw)
To: Daniel Krügler, Jason Merrill; +Cc: gcc-patches, libstdc++
[-- Attachment #1: Type: text/plain, Size: 3218 bytes --]
On 12 May 2017 at 14:15, Ville Voutilainen <ville.voutilainen@gmail.com> wrote:
> On 12 May 2017 at 14:06, Daniel Krügler <daniel.kruegler@gmail.com> wrote:
>> Your description sounds remotely similar to me to the current problem
>> of __is_trivially_constructible intrinsic, which seems to instantiate
>> the copy constructor definition albeit it (IMO) shouldn't:
>>
>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80654
>>
>> Could there be a similar cause?
>
>
> Seems quite plausible to me. I would be happy to fix that bug in the
> same go, but I'm a bit
> lost as to what exactly causes the problem. constructible_expr in method.c does
> build_special_member_call for the constructor and the destructor, so
> perhaps there
> are some flags that could make it behave.
Well, now that Jason pointed out that cp_unevaluated_operand is the
trick, here's a new
patch that fixes that bug and passes the full testsuite on Linux-x64.
2017-05-12 Ville Voutilainen <ville.voutilainen@gmail.com>
c-family/
Implement new C++ intrinsics __is_assignable and __is_constructible.
* c-common.c (__is_assignable, __is_constructible): New.
* c-common.h (RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE): Likewise.
cp/
PR c++/80654
PR c++/80682
Implement new C++ intrinsics __is_assignable and __is_constructible.
* cp-tree.h (CPTK_IS_ASSIGNABLE, CPTK_IS_CONSTRUCTIBLE): New.
(is_xible): New.
* cxx-pretty-print.c (pp_cxx_trait_expression): Handle
CPTK_IS_ASSIGNABLE and CPTK_IS_CONSTRUCTIBLE.
* method.c (constructible_expr): Set cp_unevaluated.
(is_xible_helper): New.
(is_trivially_xible): Adjust.
(is_xible): New.
* parser.c (cp_parser_primary_expression): Handle
RID_IS_ASSIGNABLE and RID_IS_CONSTRUCTIBLE.
(cp_parser_trait_expr): Likewise.
* semantics.c (trait_expr_value): Handle
CPTK_IS_ASSIGNABLE and CPTK_IS_CONSTRUCTIBLE.
testsuite/
* g++.dg/ext/80654.C: New.
libstdc++-v3/
Implement new C++ intrinsics __is_assignable and __is_constructible.
* include/std/type_traits (__do_is_static_castable_impl): Remove.
(__is_static_castable_impl, __is_static_castable_safe): Likewise.
(__is_static_castable, __do_is_direct_constructible_impl): Likewise.
(__is_direct_constructible_impl): Likewise.
(__is_direct_constructible_new_safe): Likewise.
(__is_base_to_derived_ref, __is_lvalue_to_rvalue_ref): Likewise.
(__is_direct_constructible_ref_cast): Likewise.
(__is_direct_constructible_new, __is_direct_constructible): Likewise.
(__do_is_nary_constructible_impl): Likewise.
(__is_nary_constructible_impl, __is_nary_constructible): Likewise.
(__is_constructible_impl): Likewise.
(is_constructible): Call the intrinsic.
(__is_assignable_helper): Remove.
(is_assignable): Call the intrinsic.
(is_trivially_constructible): Likewise.
(is_trivially_assignable): Likewise.
(testsuite/20_util/declval/requirements/1_neg.cc): Adjust.
(testsuite/20_util/make_signed/requirements/typedefs_neg.cc): Likewise.
(testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc):
Likewise.
[-- Attachment #2: is_constructible.diff --]
[-- Type: text/plain, Size: 18426 bytes --]
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index ad686d2..369e112 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -514,6 +514,8 @@ const struct c_common_resword c_common_reswords[] =
{ "volatile", RID_VOLATILE, 0 },
{ "wchar_t", RID_WCHAR, D_CXXONLY },
{ "while", RID_WHILE, 0 },
+ { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY },
+ { "__is_constructible", RID_IS_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 9e3982d..a986056 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -172,6 +172,7 @@ enum rid
RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE,
RID_IS_TRIVIALLY_COPYABLE,
RID_IS_UNION, RID_UNDERLYING_TYPE,
+ RID_IS_ASSIGNABLE, RID_IS_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 09b1364..154ba3c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -927,7 +927,9 @@ enum cp_trait_kind
CPTK_IS_TRIVIALLY_CONSTRUCTIBLE,
CPTK_IS_TRIVIALLY_COPYABLE,
CPTK_IS_UNION,
- CPTK_UNDERLYING_TYPE
+ CPTK_UNDERLYING_TYPE,
+ CPTK_IS_ASSIGNABLE,
+ CPTK_IS_CONSTRUCTIBLE
};
/* The types that we are processing. */
@@ -6112,6 +6114,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_xible (enum tree_code, tree, tree);
extern tree get_defaulted_eh_spec (tree);
extern tree unevaluated_noexcept_spec (void);
extern void after_nsdmi_defaulted_late_checks (tree);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index f76c30a..71d149a 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -2634,6 +2634,12 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
case CPTK_IS_LITERAL_TYPE:
pp_cxx_ws_string (pp, "__is_literal_type");
break;
+ case CPTK_IS_ASSIGNABLE:
+ pp_cxx_ws_string (pp, "__is_assignable");
+ break;
+ case CPTK_IS_CONSTRUCTIBLE:
+ pp_cxx_ws_string (pp, "__is_constructible");
+ break;
default:
gcc_unreachable ();
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 99e98cc..1fb1076 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1164,6 +1164,7 @@ constructible_expr (tree to, tree from)
{
tree ctype = to;
vec<tree, va_gc> *args = NULL;
+ cp_unevaluated cp_uneval_guard;
if (TREE_CODE (to) != REFERENCE_TYPE)
to = cp_build_reference_type (to, /*rval*/false);
tree ob = build_stub_object (to);
@@ -1200,22 +1201,36 @@ constructible_expr (tree to, tree from)
return expr;
}
-/* Returns true iff TO is trivially assignable (if CODE is MODIFY_EXPR) or
+/* Returns a tree 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. */
-bool
-is_trivially_xible (enum tree_code code, tree to, tree from)
+static tree
+is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
{
- if (VOID_TYPE_P (to))
- return false;
+ if (VOID_TYPE_P (to) || ABSTRACT_CLASS_TYPE_P (to)
+ || (from && FUNC_OR_METHOD_TYPE_P (from)
+ && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))))
+ return error_mark_node;
tree expr;
if (code == MODIFY_EXPR)
expr = assignable_expr (to, from);
- else if (from && TREE_CHAIN (from))
- return false; // only 0- and 1-argument ctors can be trivial
+ else if (trivial && from && TREE_CHAIN (from))
+ return error_mark_node; // only 0- and 1-argument ctors can be trivial
else
expr = constructible_expr (to, from);
+ return expr;
+}
+
+/* Returns true iff TO is trivially 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_trivially_xible (enum tree_code code, tree to, tree from)
+{
+ tree expr;
+ expr = is_xible_helper (code, to, from, /*trivial*/true);
if (expr == error_mark_node)
return false;
@@ -1223,6 +1238,19 @@ is_trivially_xible (enum tree_code code, tree to, tree from)
return !nt;
}
+/* 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. */
+
+bool
+is_xible (enum tree_code code, tree to, tree from)
+{
+ tree expr = is_xible_helper (code, to, from, /*trivial*/false);
+ if (expr == error_mark_node)
+ return false;
+ return !!expr;
+}
+
/* Subroutine of synthesized_method_walk. Update SPEC_P, TRIVIAL_P and
DELETED_P or give an error message MSG with argument ARG. */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 17d2679..5986dd9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5135,6 +5135,8 @@ cp_parser_primary_expression (cp_parser *parser,
case RID_IS_TRIVIALLY_CONSTRUCTIBLE:
case RID_IS_TRIVIALLY_COPYABLE:
case RID_IS_UNION:
+ case RID_IS_ASSIGNABLE:
+ case RID_IS_CONSTRUCTIBLE:
return cp_parser_trait_expr (parser, token->keyword);
// C++ concepts
@@ -9686,6 +9688,14 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
case RID_DIRECT_BASES:
kind = CPTK_DIRECT_BASES;
break;
+ case RID_IS_ASSIGNABLE:
+ kind = CPTK_IS_ASSIGNABLE;
+ binary = true;
+ break;
+ case RID_IS_CONSTRUCTIBLE:
+ kind = CPTK_IS_CONSTRUCTIBLE;
+ variadic = true;
+ break;
default:
gcc_unreachable ();
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7b2c101..f9f402e 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -9209,6 +9209,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_UNION:
return type_code1 == UNION_TYPE;
+ case CPTK_IS_ASSIGNABLE:
+ return is_xible (MODIFY_EXPR, type1, type2);
+
+ case CPTK_IS_CONSTRUCTIBLE:
+ return is_xible (INIT_EXPR, type1, type2);
+
default:
gcc_unreachable ();
return false;
@@ -9282,6 +9288,10 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
return error_mark_node;
break;
+ case CPTK_IS_ASSIGNABLE:
+ case CPTK_IS_CONSTRUCTIBLE:
+ break;
+
case CPTK_IS_TRIVIALLY_ASSIGNABLE:
case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
if (!check_trait_type (type1)
diff --git a/gcc/testsuite/g++.dg/ext/80654.C b/gcc/testsuite/g++.dg/ext/80654.C
new file mode 100644
index 0000000..8679613
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/80654.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++11 } }
+
+template <class T> struct wrap
+{
+ T t;
+ wrap(const wrap& other) : t(other.t) {}
+};
+
+struct nocopy {
+ nocopy (const nocopy&) = delete;
+};
+
+int main ()
+{
+ static_assert(!__is_trivially_constructible(wrap<nocopy>,
+ const wrap<nocopy>&), "");
+ return 0;
+}
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index aac7cff..00f647b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -924,213 +924,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public __is_default_constructible_safe<_Tp>::type
{ };
-
- // Implementation of is_constructible.
-
- // The hardest part of this trait is the binary direct-initialization
- // case, because we hit into a functional cast of the form T(arg).
- // This implementation uses different strategies depending on the
- // target type to reduce the test overhead as much as possible:
- //
- // a) For a reference target type, we use a static_cast expression
- // modulo its extra cases.
- //
- // b) For a non-reference target type we use a ::new expression.
- struct __do_is_static_castable_impl
- {
- template<typename _From, typename _To, typename
- = decltype(static_cast<_To>(declval<_From>()))>
- static true_type __test(int);
-
- template<typename, typename>
- static false_type __test(...);
- };
-
- template<typename _From, typename _To>
- struct __is_static_castable_impl
- : public __do_is_static_castable_impl
- {
- typedef decltype(__test<_From, _To>(0)) type;
- };
-
- template<typename _From, typename _To>
- struct __is_static_castable_safe
- : public __is_static_castable_impl<_From, _To>::type
- { };
-
- // __is_static_castable
- template<typename _From, typename _To>
- struct __is_static_castable
- : public integral_constant<bool, (__is_static_castable_safe<
- _From, _To>::value)>
- { };
-
- // Implementation for non-reference types. To meet the proper
- // variable definition semantics, we also need to test for
- // is_destructible in this case.
- // This form should be simplified by a single expression:
- // ::delete ::new _Tp(declval<_Arg>()), see c++/51222.
- struct __do_is_direct_constructible_impl
- {
- template<typename _Tp, typename _Arg, typename
- = decltype(::new _Tp(declval<_Arg>()))>
- static true_type __test(int);
-
- template<typename, typename>
- static false_type __test(...);
- };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_impl
- : public __do_is_direct_constructible_impl
- {
- typedef decltype(__test<_Tp, _Arg>(0)) type;
- };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_new_safe
- : public __and_<is_destructible<_Tp>,
- __is_direct_constructible_impl<_Tp, _Arg>>
- { };
-
- template<typename, typename>
- struct is_same;
-
- template<typename, typename>
- struct is_base_of;
-
- template<typename>
- struct remove_reference;
-
- template<typename _From, typename _To, bool
- = __not_<__or_<is_void<_From>,
- is_function<_From>>>::value>
- struct __is_base_to_derived_ref;
-
- template<typename _Tp, typename... _Args>
- struct is_constructible;
-
- // Detect whether we have a downcast situation during
- // reference binding.
- template<typename _From, typename _To>
- struct __is_base_to_derived_ref<_From, _To, true>
- {
- typedef typename remove_cv<typename remove_reference<_From
- >::type>::type __src_t;
- typedef typename remove_cv<typename remove_reference<_To
- >::type>::type __dst_t;
- typedef __and_<__not_<is_same<__src_t, __dst_t>>,
- is_base_of<__src_t, __dst_t>,
- __not_<is_constructible<__dst_t, _From>>> type;
- static constexpr bool value = type::value;
- };
-
- template<typename _From, typename _To>
- struct __is_base_to_derived_ref<_From, _To, false>
- : public false_type
- { };
-
- template<typename _From, typename _To, bool
- = __and_<is_lvalue_reference<_From>,
- is_rvalue_reference<_To>>::value>
- struct __is_lvalue_to_rvalue_ref;
-
- // Detect whether we have an lvalue of non-function type
- // bound to a reference-compatible rvalue-reference.
- template<typename _From, typename _To>
- struct __is_lvalue_to_rvalue_ref<_From, _To, true>
- {
- typedef typename remove_cv<typename remove_reference<
- _From>::type>::type __src_t;
- typedef typename remove_cv<typename remove_reference<
- _To>::type>::type __dst_t;
- typedef __and_<__not_<is_function<__src_t>>,
- __or_<is_same<__src_t, __dst_t>,
- is_base_of<__dst_t, __src_t>>> type;
- static constexpr bool value = type::value;
- };
-
- template<typename _From, typename _To>
- struct __is_lvalue_to_rvalue_ref<_From, _To, false>
- : public false_type
- { };
-
- // Here we handle direct-initialization to a reference type as
- // equivalent to a static_cast modulo overshooting conversions.
- // These are restricted to the following conversions:
- // a) A base class value to a derived class reference
- // b) An lvalue to an rvalue-reference of reference-compatible
- // types that are not functions
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_ref_cast
- : public __and_<__is_static_castable<_Arg, _Tp>,
- __not_<__or_<__is_base_to_derived_ref<_Arg, _Tp>,
- __is_lvalue_to_rvalue_ref<_Arg, _Tp>
- >>>
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_new
- : public conditional<is_reference<_Tp>::value,
- __is_direct_constructible_ref_cast<_Tp, _Arg>,
- __is_direct_constructible_new_safe<_Tp, _Arg>
- >::type
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible
- : public __is_direct_constructible_new<_Tp, _Arg>::type
- { };
-
- // Since default-construction and binary direct-initialization have
- // been handled separately, the implementation of the remaining
- // n-ary construction cases is rather straightforward. We can use
- // here a functional cast, because array types are excluded anyway
- // and this form is never interpreted as a C cast.
- struct __do_is_nary_constructible_impl
- {
- template<typename _Tp, typename... _Args, typename
- = decltype(_Tp(declval<_Args>()...))>
- static true_type __test(int);
-
- template<typename, typename...>
- static false_type __test(...);
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_nary_constructible_impl
- : public __do_is_nary_constructible_impl
- {
- typedef decltype(__test<_Tp, _Args...>(0)) type;
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_nary_constructible
- : public __is_nary_constructible_impl<_Tp, _Args...>::type
- {
- static_assert(sizeof...(_Args) > 1,
- "Only useful for > 1 arguments");
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_constructible_impl
- : public __is_nary_constructible<_Tp, _Args...>
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_constructible_impl<_Tp, _Arg>
- : public __is_direct_constructible<_Tp, _Arg>
- { };
-
- template<typename _Tp>
- struct __is_constructible_impl<_Tp>
- : public is_default_constructible<_Tp>
- { };
-
/// is_constructible
template<typename _Tp, typename... _Args>
struct is_constructible
- : public __is_constructible_impl<_Tp, _Args...>::type
+ : public __bool_constant<__is_constructible(_Tp, _Args...)>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1255,26 +1052,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public __is_nothrow_move_constructible_impl<_Tp>
{ };
- template<typename _Tp, typename _Up>
- class __is_assignable_helper
- {
- template<typename _Tp1, typename _Up1,
- typename = decltype(declval<_Tp1>() = declval<_Up1>())>
- static true_type
- __test(int);
-
- template<typename, typename>
- static false_type
- __test(...);
-
- public:
- typedef decltype(__test<_Tp, _Up>(0)) type;
- };
-
/// is_assignable
template<typename _Tp, typename _Up>
struct is_assignable
- : public __is_assignable_helper<_Tp, _Up>::type
+ : public __bool_constant<__is_assignable(_Tp, _Up)>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1364,8 +1145,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// is_trivially_constructible
template<typename _Tp, typename... _Args>
struct is_trivially_constructible
- : public __and_<is_constructible<_Tp, _Args...>, integral_constant<bool,
- __is_trivially_constructible(_Tp, _Args...)>>
+ : public __bool_constant<__is_trivially_constructible(_Tp, _Args...)>
{ };
/// is_trivially_default_constructible
@@ -1423,9 +1203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// is_trivially_assignable
template<typename _Tp, typename _Up>
struct is_trivially_assignable
- : public __and_<is_assignable<_Tp, _Up>,
- integral_constant<bool,
- __is_trivially_assignable(_Tp, _Up)>>
+ : public __bool_constant<__is_trivially_assignable(_Tp, _Up)>
{ };
/// is_trivially_copy_assignable
diff --git a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
index dc9daeb..0c5599d 100644
--- a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
@@ -18,7 +18,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-error "static assertion failed" "" { target *-*-* } 2259 }
+// { dg-error "static assertion failed" "" { target *-*-* } 2037 }
#include <utility>
diff --git a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
index 664fb70..4b83764 100644
--- a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
@@ -47,4 +47,4 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 39 }
// { dg-error "required from here" "" { target *-*-* } 41 }
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1924 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1702 }
diff --git a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
index 6d64717..d77b023 100644
--- a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
@@ -47,5 +47,5 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 39 }
// { dg-error "required from here" "" { target *-*-* } 41 }
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1820 }
-// { dg-error "declaration of" "" { target *-*-* } 1777 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1598 }
+// { dg-error "declaration of" "" { target *-*-* } 1555 }
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [C++ PATCH, RFC] Implement new C++ intrinsics __is_assignable and __is_constructible.
2017-05-12 18:34 ` Ville Voutilainen
@ 2017-05-15 11:10 ` Jonathan Wakely
2017-05-16 18:46 ` Jason Merrill
1 sibling, 0 replies; 8+ messages in thread
From: Jonathan Wakely @ 2017-05-15 11:10 UTC (permalink / raw)
To: Ville Voutilainen
Cc: Daniel Krügler, Jason Merrill, gcc-patches, libstdc++
On 12/05/17 21:33 +0300, Ville Voutilainen wrote:
> libstdc++-v3/
>
> Implement new C++ intrinsics __is_assignable and __is_constructible.
> * include/std/type_traits (__do_is_static_castable_impl): Remove.
> (__is_static_castable_impl, __is_static_castable_safe): Likewise.
> (__is_static_castable, __do_is_direct_constructible_impl): Likewise.
> (__is_direct_constructible_impl): Likewise.
> (__is_direct_constructible_new_safe): Likewise.
> (__is_base_to_derived_ref, __is_lvalue_to_rvalue_ref): Likewise.
> (__is_direct_constructible_ref_cast): Likewise.
> (__is_direct_constructible_new, __is_direct_constructible): Likewise.
> (__do_is_nary_constructible_impl): Likewise.
> (__is_nary_constructible_impl, __is_nary_constructible): Likewise.
> (__is_constructible_impl): Likewise.
> (is_constructible): Call the intrinsic.
> (__is_assignable_helper): Remove.
> (is_assignable): Call the intrinsic.
> (is_trivially_constructible): Likewise.
> (is_trivially_assignable): Likewise.
> (testsuite/20_util/declval/requirements/1_neg.cc): Adjust.
> (testsuite/20_util/make_signed/requirements/typedefs_neg.cc): Likewise.
> (testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc):
> Likewise.
The libstdc++ parts make me happy. I have fairly high confidence in
our tests for is_constructible and is_assignable (thanks, Daniel!) so
would be happy to approve the library parts.
I'll try the patch against the libc++ testsuite too.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [C++ PATCH, RFC] Implement new C++ intrinsics __is_assignable and __is_constructible.
2017-05-12 18:34 ` Ville Voutilainen
2017-05-15 11:10 ` Jonathan Wakely
@ 2017-05-16 18:46 ` Jason Merrill
2017-05-17 12:20 ` Ville Voutilainen
1 sibling, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2017-05-16 18:46 UTC (permalink / raw)
To: Ville Voutilainen; +Cc: Daniel Krügler, gcc-patches, libstdc++
On Fri, May 12, 2017 at 2:33 PM, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
> On 12 May 2017 at 14:15, Ville Voutilainen <ville.voutilainen@gmail.com> wrote:
>> On 12 May 2017 at 14:06, Daniel Krügler <daniel.kruegler@gmail.com> wrote:
>>> Your description sounds remotely similar to me to the current problem
>>> of __is_trivially_constructible intrinsic, which seems to instantiate
>>> the copy constructor definition albeit it (IMO) shouldn't:
>>>
>>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80654
>>>
>>> Could there be a similar cause?
>>
>>
>> Seems quite plausible to me. I would be happy to fix that bug in the
>> same go, but I'm a bit
>> lost as to what exactly causes the problem. constructible_expr in method.c does
>> build_special_member_call for the constructor and the destructor, so
>> perhaps there
>> are some flags that could make it behave.
>
> Well, now that Jason pointed out that cp_unevaluated_operand is the
> trick, here's a new
> patch that fixes that bug and passes the full testsuite on Linux-x64.
OK, thanks.
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [C++ PATCH, RFC] Implement new C++ intrinsics __is_assignable and __is_constructible.
2017-05-16 18:46 ` Jason Merrill
@ 2017-05-17 12:20 ` Ville Voutilainen
2017-05-17 13:46 ` Jonathan Wakely
0 siblings, 1 reply; 8+ messages in thread
From: Ville Voutilainen @ 2017-05-17 12:20 UTC (permalink / raw)
To: Jason Merrill; +Cc: Daniel Krügler, gcc-patches, libstdc++
[-- Attachment #1: Type: text/plain, Size: 3531 bytes --]
On 16 May 2017 at 21:44, Jason Merrill <jason@redhat.com> wrote:
>> Well, now that Jason pointed out that cp_unevaluated_operand is the
>> trick, here's a new
>> patch that fixes that bug and passes the full testsuite on Linux-x64.
>
> OK, thanks.
One more round. This patch doesn't change any of the compiler bits,
but the llvm testsuite revealed
that we didn't handle things like
is_trivially_copy_constructible<void> properly, so I needed to adjust
the library implementation of the triviality-traits. Now we pass the
llvm testsuite for these traits,
and this patch passes our full testsuite.
Jonathan, ok for trunk?
2017-05-17 Ville Voutilainen <ville.voutilainen@gmail.com>
c-family/
Implement new C++ intrinsics __is_assignable and __is_constructible.
* c-common.c (__is_assignable, __is_constructible): New.
* c-common.h (RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE): Likewise.
cp/
PR c++/80654
PR c++/80682
Implement new C++ intrinsics __is_assignable and __is_constructible.
* cp-tree.h (CPTK_IS_ASSIGNABLE, CPTK_IS_CONSTRUCTIBLE): New.
(is_xible): New.
* cxx-pretty-print.c (pp_cxx_trait_expression): Handle
CPTK_IS_ASSIGNABLE and CPTK_IS_CONSTRUCTIBLE.
* method.c (constructible_expr): Set cp_unevaluated.
(is_xible_helper): New.
(is_trivially_xible): Adjust.
(is_xible): New.
* parser.c (cp_parser_primary_expression): Handle
RID_IS_ASSIGNABLE and RID_IS_CONSTRUCTIBLE.
(cp_parser_trait_expr): Likewise.
* semantics.c (trait_expr_value): Handle
CPTK_IS_ASSIGNABLE and CPTK_IS_CONSTRUCTIBLE.
testsuite/
* g++.dg/ext/80654.C: New.
libstdc++-v3/
Implement new C++ intrinsics __is_assignable and __is_constructible.
* include/std/type_traits (__do_is_static_castable_impl): Remove.
(__is_static_castable_impl, __is_static_castable_safe): Likewise.
(__is_static_castable, __do_is_direct_constructible_impl): Likewise.
(__is_direct_constructible_impl): Likewise.
(__is_direct_constructible_new_safe): Likewise.
(__is_base_to_derived_ref, __is_lvalue_to_rvalue_ref): Likewise.
(__is_direct_constructible_ref_cast): Likewise.
(__is_direct_constructible_new, __is_direct_constructible): Likewise.
(__do_is_nary_constructible_impl): Likewise.
(__is_nary_constructible_impl, __is_nary_constructible): Likewise.
(__is_constructible_impl): Likewise.
(is_constructible): Call the intrinsic.
(__is_assignable_helper): Remove.
(is_assignable): Call the intrinsic.
(is_trivially_constructible): Likewise.
(__is_trivially_copy_constructible_impl): New.
(is_trivially_copy_constructible): Use it.
(__is_trivially_move_constructible_impl): New.
(is_trivially_move_constructible): Use it.
(is_trivially_assignable): Call the intrinsic.
(__is_trivially_copy_assignable_impl): New.
(is_trivially_copy_assignable): Use it.
(__is_trivially_move_assignable_impl): New.
(is_trivially_move_assignable): Use it.
(testsuite/20_util/declval/requirements/1_neg.cc): Adjust.
(testsuite/20_util/is_trivially_copy_assignable/value.cc):
Add test for void.
(testsuite/20_util/is_trivially_copy_constructible/value.cc): Likewise.
(testsuite/20_util/is_trivially_move_assignable/value.cc): Likewise.
(testsuite/20_util/is_trivially_move_constructible/value.cc): Likewise.
(testsuite/20_util/make_signed/requirements/typedefs_neg.cc): Adjust.
(testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc):
Likewise.
[-- Attachment #2: is_constructible.diff --]
[-- Type: text/plain, Size: 23467 bytes --]
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index ad686d2..369e112 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -514,6 +514,8 @@ const struct c_common_resword c_common_reswords[] =
{ "volatile", RID_VOLATILE, 0 },
{ "wchar_t", RID_WCHAR, D_CXXONLY },
{ "while", RID_WHILE, 0 },
+ { "__is_assignable", RID_IS_ASSIGNABLE, D_CXXONLY },
+ { "__is_constructible", RID_IS_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 9e3982d..a986056 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -172,6 +172,7 @@ enum rid
RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE,
RID_IS_TRIVIALLY_COPYABLE,
RID_IS_UNION, RID_UNDERLYING_TYPE,
+ RID_IS_ASSIGNABLE, RID_IS_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 09b1364..154ba3c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -927,7 +927,9 @@ enum cp_trait_kind
CPTK_IS_TRIVIALLY_CONSTRUCTIBLE,
CPTK_IS_TRIVIALLY_COPYABLE,
CPTK_IS_UNION,
- CPTK_UNDERLYING_TYPE
+ CPTK_UNDERLYING_TYPE,
+ CPTK_IS_ASSIGNABLE,
+ CPTK_IS_CONSTRUCTIBLE
};
/* The types that we are processing. */
@@ -6112,6 +6114,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_xible (enum tree_code, tree, tree);
extern tree get_defaulted_eh_spec (tree);
extern tree unevaluated_noexcept_spec (void);
extern void after_nsdmi_defaulted_late_checks (tree);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index f76c30a..71d149a 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -2634,6 +2634,12 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
case CPTK_IS_LITERAL_TYPE:
pp_cxx_ws_string (pp, "__is_literal_type");
break;
+ case CPTK_IS_ASSIGNABLE:
+ pp_cxx_ws_string (pp, "__is_assignable");
+ break;
+ case CPTK_IS_CONSTRUCTIBLE:
+ pp_cxx_ws_string (pp, "__is_constructible");
+ break;
default:
gcc_unreachable ();
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 99e98cc..1fb1076 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1164,6 +1164,7 @@ constructible_expr (tree to, tree from)
{
tree ctype = to;
vec<tree, va_gc> *args = NULL;
+ cp_unevaluated cp_uneval_guard;
if (TREE_CODE (to) != REFERENCE_TYPE)
to = cp_build_reference_type (to, /*rval*/false);
tree ob = build_stub_object (to);
@@ -1200,22 +1201,36 @@ constructible_expr (tree to, tree from)
return expr;
}
-/* Returns true iff TO is trivially assignable (if CODE is MODIFY_EXPR) or
+/* Returns a tree 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. */
-bool
-is_trivially_xible (enum tree_code code, tree to, tree from)
+static tree
+is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
{
- if (VOID_TYPE_P (to))
- return false;
+ if (VOID_TYPE_P (to) || ABSTRACT_CLASS_TYPE_P (to)
+ || (from && FUNC_OR_METHOD_TYPE_P (from)
+ && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))))
+ return error_mark_node;
tree expr;
if (code == MODIFY_EXPR)
expr = assignable_expr (to, from);
- else if (from && TREE_CHAIN (from))
- return false; // only 0- and 1-argument ctors can be trivial
+ else if (trivial && from && TREE_CHAIN (from))
+ return error_mark_node; // only 0- and 1-argument ctors can be trivial
else
expr = constructible_expr (to, from);
+ return expr;
+}
+
+/* Returns true iff TO is trivially 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_trivially_xible (enum tree_code code, tree to, tree from)
+{
+ tree expr;
+ expr = is_xible_helper (code, to, from, /*trivial*/true);
if (expr == error_mark_node)
return false;
@@ -1223,6 +1238,19 @@ is_trivially_xible (enum tree_code code, tree to, tree from)
return !nt;
}
+/* 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. */
+
+bool
+is_xible (enum tree_code code, tree to, tree from)
+{
+ tree expr = is_xible_helper (code, to, from, /*trivial*/false);
+ if (expr == error_mark_node)
+ return false;
+ return !!expr;
+}
+
/* Subroutine of synthesized_method_walk. Update SPEC_P, TRIVIAL_P and
DELETED_P or give an error message MSG with argument ARG. */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 17d2679..5986dd9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5135,6 +5135,8 @@ cp_parser_primary_expression (cp_parser *parser,
case RID_IS_TRIVIALLY_CONSTRUCTIBLE:
case RID_IS_TRIVIALLY_COPYABLE:
case RID_IS_UNION:
+ case RID_IS_ASSIGNABLE:
+ case RID_IS_CONSTRUCTIBLE:
return cp_parser_trait_expr (parser, token->keyword);
// C++ concepts
@@ -9686,6 +9688,14 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
case RID_DIRECT_BASES:
kind = CPTK_DIRECT_BASES;
break;
+ case RID_IS_ASSIGNABLE:
+ kind = CPTK_IS_ASSIGNABLE;
+ binary = true;
+ break;
+ case RID_IS_CONSTRUCTIBLE:
+ kind = CPTK_IS_CONSTRUCTIBLE;
+ variadic = true;
+ break;
default:
gcc_unreachable ();
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7b2c101..f9f402e 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -9209,6 +9209,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_UNION:
return type_code1 == UNION_TYPE;
+ case CPTK_IS_ASSIGNABLE:
+ return is_xible (MODIFY_EXPR, type1, type2);
+
+ case CPTK_IS_CONSTRUCTIBLE:
+ return is_xible (INIT_EXPR, type1, type2);
+
default:
gcc_unreachable ();
return false;
@@ -9282,6 +9288,10 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
return error_mark_node;
break;
+ case CPTK_IS_ASSIGNABLE:
+ case CPTK_IS_CONSTRUCTIBLE:
+ break;
+
case CPTK_IS_TRIVIALLY_ASSIGNABLE:
case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
if (!check_trait_type (type1)
diff --git a/gcc/testsuite/g++.dg/ext/80654.C b/gcc/testsuite/g++.dg/ext/80654.C
new file mode 100644
index 0000000..8679613
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/80654.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++11 } }
+
+template <class T> struct wrap
+{
+ T t;
+ wrap(const wrap& other) : t(other.t) {}
+};
+
+struct nocopy {
+ nocopy (const nocopy&) = delete;
+};
+
+int main ()
+{
+ static_assert(!__is_trivially_constructible(wrap<nocopy>,
+ const wrap<nocopy>&), "");
+ return 0;
+}
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index aac7cff..390b6f4 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -924,213 +924,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public __is_default_constructible_safe<_Tp>::type
{ };
-
- // Implementation of is_constructible.
-
- // The hardest part of this trait is the binary direct-initialization
- // case, because we hit into a functional cast of the form T(arg).
- // This implementation uses different strategies depending on the
- // target type to reduce the test overhead as much as possible:
- //
- // a) For a reference target type, we use a static_cast expression
- // modulo its extra cases.
- //
- // b) For a non-reference target type we use a ::new expression.
- struct __do_is_static_castable_impl
- {
- template<typename _From, typename _To, typename
- = decltype(static_cast<_To>(declval<_From>()))>
- static true_type __test(int);
-
- template<typename, typename>
- static false_type __test(...);
- };
-
- template<typename _From, typename _To>
- struct __is_static_castable_impl
- : public __do_is_static_castable_impl
- {
- typedef decltype(__test<_From, _To>(0)) type;
- };
-
- template<typename _From, typename _To>
- struct __is_static_castable_safe
- : public __is_static_castable_impl<_From, _To>::type
- { };
-
- // __is_static_castable
- template<typename _From, typename _To>
- struct __is_static_castable
- : public integral_constant<bool, (__is_static_castable_safe<
- _From, _To>::value)>
- { };
-
- // Implementation for non-reference types. To meet the proper
- // variable definition semantics, we also need to test for
- // is_destructible in this case.
- // This form should be simplified by a single expression:
- // ::delete ::new _Tp(declval<_Arg>()), see c++/51222.
- struct __do_is_direct_constructible_impl
- {
- template<typename _Tp, typename _Arg, typename
- = decltype(::new _Tp(declval<_Arg>()))>
- static true_type __test(int);
-
- template<typename, typename>
- static false_type __test(...);
- };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_impl
- : public __do_is_direct_constructible_impl
- {
- typedef decltype(__test<_Tp, _Arg>(0)) type;
- };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_new_safe
- : public __and_<is_destructible<_Tp>,
- __is_direct_constructible_impl<_Tp, _Arg>>
- { };
-
- template<typename, typename>
- struct is_same;
-
- template<typename, typename>
- struct is_base_of;
-
- template<typename>
- struct remove_reference;
-
- template<typename _From, typename _To, bool
- = __not_<__or_<is_void<_From>,
- is_function<_From>>>::value>
- struct __is_base_to_derived_ref;
-
- template<typename _Tp, typename... _Args>
- struct is_constructible;
-
- // Detect whether we have a downcast situation during
- // reference binding.
- template<typename _From, typename _To>
- struct __is_base_to_derived_ref<_From, _To, true>
- {
- typedef typename remove_cv<typename remove_reference<_From
- >::type>::type __src_t;
- typedef typename remove_cv<typename remove_reference<_To
- >::type>::type __dst_t;
- typedef __and_<__not_<is_same<__src_t, __dst_t>>,
- is_base_of<__src_t, __dst_t>,
- __not_<is_constructible<__dst_t, _From>>> type;
- static constexpr bool value = type::value;
- };
-
- template<typename _From, typename _To>
- struct __is_base_to_derived_ref<_From, _To, false>
- : public false_type
- { };
-
- template<typename _From, typename _To, bool
- = __and_<is_lvalue_reference<_From>,
- is_rvalue_reference<_To>>::value>
- struct __is_lvalue_to_rvalue_ref;
-
- // Detect whether we have an lvalue of non-function type
- // bound to a reference-compatible rvalue-reference.
- template<typename _From, typename _To>
- struct __is_lvalue_to_rvalue_ref<_From, _To, true>
- {
- typedef typename remove_cv<typename remove_reference<
- _From>::type>::type __src_t;
- typedef typename remove_cv<typename remove_reference<
- _To>::type>::type __dst_t;
- typedef __and_<__not_<is_function<__src_t>>,
- __or_<is_same<__src_t, __dst_t>,
- is_base_of<__dst_t, __src_t>>> type;
- static constexpr bool value = type::value;
- };
-
- template<typename _From, typename _To>
- struct __is_lvalue_to_rvalue_ref<_From, _To, false>
- : public false_type
- { };
-
- // Here we handle direct-initialization to a reference type as
- // equivalent to a static_cast modulo overshooting conversions.
- // These are restricted to the following conversions:
- // a) A base class value to a derived class reference
- // b) An lvalue to an rvalue-reference of reference-compatible
- // types that are not functions
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_ref_cast
- : public __and_<__is_static_castable<_Arg, _Tp>,
- __not_<__or_<__is_base_to_derived_ref<_Arg, _Tp>,
- __is_lvalue_to_rvalue_ref<_Arg, _Tp>
- >>>
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible_new
- : public conditional<is_reference<_Tp>::value,
- __is_direct_constructible_ref_cast<_Tp, _Arg>,
- __is_direct_constructible_new_safe<_Tp, _Arg>
- >::type
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_direct_constructible
- : public __is_direct_constructible_new<_Tp, _Arg>::type
- { };
-
- // Since default-construction and binary direct-initialization have
- // been handled separately, the implementation of the remaining
- // n-ary construction cases is rather straightforward. We can use
- // here a functional cast, because array types are excluded anyway
- // and this form is never interpreted as a C cast.
- struct __do_is_nary_constructible_impl
- {
- template<typename _Tp, typename... _Args, typename
- = decltype(_Tp(declval<_Args>()...))>
- static true_type __test(int);
-
- template<typename, typename...>
- static false_type __test(...);
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_nary_constructible_impl
- : public __do_is_nary_constructible_impl
- {
- typedef decltype(__test<_Tp, _Args...>(0)) type;
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_nary_constructible
- : public __is_nary_constructible_impl<_Tp, _Args...>::type
- {
- static_assert(sizeof...(_Args) > 1,
- "Only useful for > 1 arguments");
- };
-
- template<typename _Tp, typename... _Args>
- struct __is_constructible_impl
- : public __is_nary_constructible<_Tp, _Args...>
- { };
-
- template<typename _Tp, typename _Arg>
- struct __is_constructible_impl<_Tp, _Arg>
- : public __is_direct_constructible<_Tp, _Arg>
- { };
-
- template<typename _Tp>
- struct __is_constructible_impl<_Tp>
- : public is_default_constructible<_Tp>
- { };
-
/// is_constructible
template<typename _Tp, typename... _Args>
struct is_constructible
- : public __is_constructible_impl<_Tp, _Args...>::type
+ : public __bool_constant<__is_constructible(_Tp, _Args...)>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1255,26 +1052,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public __is_nothrow_move_constructible_impl<_Tp>
{ };
- template<typename _Tp, typename _Up>
- class __is_assignable_helper
- {
- template<typename _Tp1, typename _Up1,
- typename = decltype(declval<_Tp1>() = declval<_Up1>())>
- static true_type
- __test(int);
-
- template<typename, typename>
- static false_type
- __test(...);
-
- public:
- typedef decltype(__test<_Tp, _Up>(0)) type;
- };
-
/// is_assignable
template<typename _Tp, typename _Up>
struct is_assignable
- : public __is_assignable_helper<_Tp, _Up>::type
+ : public __bool_constant<__is_assignable(_Tp, _Up)>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
@@ -1364,8 +1145,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// is_trivially_constructible
template<typename _Tp, typename... _Args>
struct is_trivially_constructible
- : public __and_<is_constructible<_Tp, _Args...>, integral_constant<bool,
- __is_trivially_constructible(_Tp, _Args...)>>
+ : public __bool_constant<__is_trivially_constructible(_Tp, _Args...)>
{ };
/// is_trivially_default_constructible
@@ -1405,45 +1185,95 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ };
/// is_trivially_copy_constructible
+
+ template<typename _Tp, bool = __is_referenceable<_Tp>::value>
+ struct __is_trivially_copy_constructible_impl;
+
template<typename _Tp>
- struct is_trivially_copy_constructible
+ struct __is_trivially_copy_constructible_impl<_Tp, false>
+ : public false_type { };
+
+ template<typename _Tp>
+ struct __is_trivially_copy_constructible_impl<_Tp, true>
: public __and_<is_copy_constructible<_Tp>,
integral_constant<bool,
__is_trivially_constructible(_Tp, const _Tp&)>>
{ };
+ template<typename _Tp>
+ struct is_trivially_copy_constructible
+ : public __is_trivially_copy_constructible_impl<_Tp>
+ { };
+
/// is_trivially_move_constructible
+
+ template<typename _Tp, bool = __is_referenceable<_Tp>::value>
+ struct __is_trivially_move_constructible_impl;
+
template<typename _Tp>
- struct is_trivially_move_constructible
+ struct __is_trivially_move_constructible_impl<_Tp, false>
+ : public false_type { };
+
+ template<typename _Tp>
+ struct __is_trivially_move_constructible_impl<_Tp, true>
: public __and_<is_move_constructible<_Tp>,
integral_constant<bool,
__is_trivially_constructible(_Tp, _Tp&&)>>
{ };
+ template<typename _Tp>
+ struct is_trivially_move_constructible
+ : public __is_trivially_move_constructible_impl<_Tp>
+ { };
+
/// is_trivially_assignable
template<typename _Tp, typename _Up>
struct is_trivially_assignable
- : public __and_<is_assignable<_Tp, _Up>,
- integral_constant<bool,
- __is_trivially_assignable(_Tp, _Up)>>
+ : public __bool_constant<__is_trivially_assignable(_Tp, _Up)>
{ };
/// is_trivially_copy_assignable
+
+ template<typename _Tp, bool = __is_referenceable<_Tp>::value>
+ struct __is_trivially_copy_assignable_impl;
+
template<typename _Tp>
- struct is_trivially_copy_assignable
+ struct __is_trivially_copy_assignable_impl<_Tp, false>
+ : public false_type { };
+
+ template<typename _Tp>
+ struct __is_trivially_copy_assignable_impl<_Tp, true>
: public __and_<is_copy_assignable<_Tp>,
integral_constant<bool,
__is_trivially_assignable(_Tp&, const _Tp&)>>
{ };
+ template<typename _Tp>
+ struct is_trivially_copy_assignable
+ : public __is_trivially_copy_assignable_impl<_Tp>
+ { };
+
/// is_trivially_move_assignable
+
+ template<typename _Tp, bool = __is_referenceable<_Tp>::value>
+ struct __is_trivially_move_assignable_impl;
+
template<typename _Tp>
- struct is_trivially_move_assignable
+ struct __is_trivially_move_assignable_impl<_Tp, false>
+ : public false_type { };
+
+ template<typename _Tp>
+ struct __is_trivially_move_assignable_impl<_Tp, true>
: public __and_<is_move_assignable<_Tp>,
integral_constant<bool,
__is_trivially_assignable(_Tp&, _Tp&&)>>
{ };
+ template<typename _Tp>
+ struct is_trivially_move_assignable
+ : public __is_trivially_move_assignable_impl<_Tp>
+ { };
+
/// is_trivially_destructible
template<typename _Tp>
struct is_trivially_destructible
diff --git a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
index dc9daeb..4e254e8 100644
--- a/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/declval/requirements/1_neg.cc
@@ -18,7 +18,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-error "static assertion failed" "" { target *-*-* } 2259 }
+// { dg-error "static assertion failed" "" { target *-*-* } 2089 }
#include <utility>
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_copy_assignable/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_copy_assignable/value.cc
index b002246..902aa5e 100644
--- a/libstdc++-v3/testsuite/20_util/is_trivially_copy_assignable/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_copy_assignable/value.cc
@@ -88,4 +88,6 @@ void test01()
MoveOnly>(false), "");
static_assert(test_property<is_trivially_copy_assignable,
MoveOnly2>(false), "");
+ static_assert(test_property<is_trivially_copy_assignable,
+ void>(false), "");
}
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_copy_constructible/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_copy_constructible/value.cc
index 845e058..627410b 100644
--- a/libstdc++-v3/testsuite/20_util/is_trivially_copy_constructible/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_copy_constructible/value.cc
@@ -82,4 +82,6 @@ void test01()
MoveOnly>(false), "");
static_assert(test_property<is_trivially_copy_constructible,
MoveOnly2>(false), "");
+ static_assert(test_property<is_trivially_copy_constructible,
+ void>(false), "");
}
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_move_assignable/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_move_assignable/value.cc
index 68833b6..2210483 100644
--- a/libstdc++-v3/testsuite/20_util/is_trivially_move_assignable/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_move_assignable/value.cc
@@ -88,4 +88,6 @@ void test01()
MoveOnly>(true), "");
static_assert(test_property<is_trivially_move_assignable,
MoveOnly2>(false), "");
+ static_assert(test_property<is_trivially_move_assignable,
+ void>(false), "");
}
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_move_constructible/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_move_constructible/value.cc
index ad6045b..9a21b6e 100644
--- a/libstdc++-v3/testsuite/20_util/is_trivially_move_constructible/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_move_constructible/value.cc
@@ -82,4 +82,6 @@ void test01()
MoveOnly>(true), "");
static_assert(test_property<is_trivially_move_constructible,
MoveOnly2>(false), "");
+ static_assert(test_property<is_trivially_move_constructible,
+ void>(false), "");
}
diff --git a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
index 664fb70..e3e80f9 100644
--- a/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/make_signed/requirements/typedefs_neg.cc
@@ -47,4 +47,4 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 39 }
// { dg-error "required from here" "" { target *-*-* } 41 }
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1924 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1754 }
diff --git a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
index 6d64717..86b0c2d 100644
--- a/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc
@@ -47,5 +47,5 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 39 }
// { dg-error "required from here" "" { target *-*-* } 41 }
-// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1820 }
-// { dg-error "declaration of" "" { target *-*-* } 1777 }
+// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1650 }
+
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [C++ PATCH, RFC] Implement new C++ intrinsics __is_assignable and __is_constructible.
2017-05-17 12:20 ` Ville Voutilainen
@ 2017-05-17 13:46 ` Jonathan Wakely
0 siblings, 0 replies; 8+ messages in thread
From: Jonathan Wakely @ 2017-05-17 13:46 UTC (permalink / raw)
To: Ville Voutilainen
Cc: Jason Merrill, Daniel Krügler, gcc-patches, libstdc++
On 17/05/17 15:15 +0300, Ville Voutilainen wrote:
>One more round. This patch doesn't change any of the compiler bits,
>but the llvm testsuite revealed
>that we didn't handle things like
>is_trivially_copy_constructible<void> properly, so I needed to adjust
>the library implementation of the triviality-traits. Now we pass the
>llvm testsuite for these traits,
>and this patch passes our full testsuite.
>
>Jonathan, ok for trunk?
Yes OK, thanks.
A few observations ...
>@@ -1405,45 +1185,95 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> { };
>
> /// is_trivially_copy_constructible
>+
>+ template<typename _Tp, bool = __is_referenceable<_Tp>::value>
>+ struct __is_trivially_copy_constructible_impl;
>+
> template<typename _Tp>
>- struct is_trivially_copy_constructible
>+ struct __is_trivially_copy_constructible_impl<_Tp, false>
>+ : public false_type { };
>+
>+ template<typename _Tp>
>+ struct __is_trivially_copy_constructible_impl<_Tp, true>
> : public __and_<is_copy_constructible<_Tp>,
> integral_constant<bool,
> __is_trivially_constructible(_Tp, const _Tp&)>>
> { };
This could use __bool_constant, and there doesn't seem to be any
advantage to using __and_ here, because there's nothing to
short-circuit. So:
: public __bool_constant<is_copy_constructible<_Tp>::value
&& __is_trivially_constructible(_Tp, const _Tp&)>
But that was pre-existing, so let's deal with that
separately.
>+ template<typename _Tp>
>+ struct __is_trivially_move_constructible_impl<_Tp, true>
> : public __and_<is_move_constructible<_Tp>,
> integral_constant<bool,
> __is_trivially_constructible(_Tp, _Tp&&)>>
> { };
Ditto.
>+ template<typename _Tp>
>+ struct __is_trivially_copy_assignable_impl<_Tp, true>
> : public __and_<is_copy_assignable<_Tp>,
> integral_constant<bool,
> __is_trivially_assignable(_Tp&, const _Tp&)>>
> { };
Ditto.
>+ template<typename _Tp>
>+ struct __is_trivially_move_assignable_impl<_Tp, true>
> : public __and_<is_move_assignable<_Tp>,
> integral_constant<bool,
> __is_trivially_assignable(_Tp&, _Tp&&)>>
Ditto.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2017-05-17 13:46 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-12 10:43 [C++ PATCH, RFC] Implement new C++ intrinsics __is_assignable and __is_constructible Ville Voutilainen
2017-05-12 11:07 ` Daniel Krügler
2017-05-12 11:27 ` Ville Voutilainen
2017-05-12 18:34 ` Ville Voutilainen
2017-05-15 11:10 ` Jonathan Wakely
2017-05-16 18:46 ` Jason Merrill
2017-05-17 12:20 ` Ville Voutilainen
2017-05-17 13:46 ` Jonathan Wakely
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).