[libcxx] r276084 - Reimplement is_constructible fallback implementation. Fixes PR21574.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 19 22:01:25 PDT 2016


Author: ericwf
Date: Wed Jul 20 00:01:24 2016
New Revision: 276084

URL: http://llvm.org/viewvc/llvm-project?rev=276084&view=rev
Log:
Reimplement is_constructible fallback implementation. Fixes PR21574.

The previous implementation relied highly on specializations to handle
special cases. This new implementation lets the compiler do the work when possible.

Modified:
    libcxx/trunk/include/type_traits
    libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp
    libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_default_constructible.pass.cpp

Modified: libcxx/trunk/include/type_traits
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=276084&r1=276083&r2=276084&view=diff
==============================================================================
--- libcxx/trunk/include/type_traits (original)
+++ libcxx/trunk/include/type_traits Wed Jul 20 00:01:24 2016
@@ -2913,119 +2913,75 @@ struct _LIBCPP_TYPE_VIS_ONLY is_construc
 
 //      main is_constructible test
 
-template <class _Tp, class ..._Args>
-typename __select_2nd<decltype(_VSTD::move(_Tp(_VSTD::declval<_Args>()...))), true_type>::type
-__is_constructible_test(_Tp&&, _Args&& ...);
-
-template <class ..._Args>
-false_type
-__is_constructible_test(__any, _Args&& ...);
-
-template <bool, class _Tp, class... _Args>
-struct __libcpp_is_constructible // false, _Tp is not a scalar
-    : public common_type
-             <
-                 decltype(__is_constructible_test(declval<_Tp>(), declval<_Args>()...))
-             >::type
-    {};
-
-//      function types are not constructible
-
-template <class _Rp, class... _A1, class... _A2>
-struct __libcpp_is_constructible<false, _Rp(_A1...), _A2...>
-    : public false_type
-    {};
 
-//      handle scalars and reference types
+struct __is_constructible_helper
+{
+    template <class _Tp>
+    static true_type __test_ref(_Tp);
+    template <class>
+    static false_type __test_ref(...);
+
+    template <class _Tp, class ..._Args,
+        class = decltype(_Tp(_VSTD::declval<_Args>()...))>
+    static true_type __test_nary(int);
+    template <class _Tp, class...>
+    static false_type __test_nary(...);
+
+    template <class _Tp, class _A0, class = decltype(::new _Tp(_VSTD::declval<_A0>()))>
+    static is_destructible<_Tp> __test_unary(int);
+    template <class, class>
+    static false_type __test_unary(...);
+};
 
-//      Scalars are default constructible, references are not
+template <class _Tp, bool = is_void<_Tp>::value>
+struct __is_default_constructible
+    : decltype(__is_constructible_helper::__test_nary<_Tp>(0))
+{};
 
 template <class _Tp>
-struct __libcpp_is_constructible<true, _Tp>
-    : public is_scalar<_Tp>
-    {};
-
-//      Scalars and references are constructible from one arg if that arg is
-//          implicitly convertible to the scalar or reference.
+struct __is_default_constructible<_Tp, true> : false_type {};
 
 template <class _Tp>
-struct __is_constructible_ref
-{
-    true_type static __lxx(_Tp);
-    false_type static __lxx(...);
-};
+struct __is_default_constructible<_Tp[], false> : false_type {};
 
-template <class _Tp, class _A0>
-struct __libcpp_is_constructible<true, _Tp, _A0>
-    : public common_type
-             <
-                 decltype(__is_constructible_ref<_Tp>::__lxx(declval<_A0>()))
-             >::type
-    {};
-
-//      Scalars and references are not constructible from multiple args.
-
-template <class _Tp, class _A0, class ..._Args>
-struct __libcpp_is_constructible<true, _Tp, _A0, _Args...>
-    : public false_type
-    {};
-
-//      Treat scalars and reference types separately
-
-template <bool, class _Tp, class... _Args>
-struct __is_constructible_void_check
-    : public __libcpp_is_constructible<is_scalar<_Tp>::value || is_reference<_Tp>::value,
-                                _Tp, _Args...>
-    {};
-
-//      If any of T or Args is void, is_constructible should be false
+template <class _Tp, size_t _Nx>
+struct __is_default_constructible<_Tp[_Nx], false>
+    : __is_default_constructible<typename remove_all_extents<_Tp>::type>  {};
 
 template <class _Tp, class... _Args>
-struct __is_constructible_void_check<true, _Tp, _Args...>
-    : public false_type
-    {};
+struct __libcpp_is_constructible
+{
+  static_assert(sizeof...(_Args) > 1, "Wrong specialization");
+  typedef decltype(__is_constructible_helper::__test_nary<_Tp, _Args...>(0))
+      type;
+};
 
-template <class ..._Args> struct __contains_void;
+template <class _Tp>
+struct __libcpp_is_constructible<_Tp> : __is_default_constructible<_Tp> {};
 
-template <> struct __contains_void<> : false_type {};
+template <class _Tp, class _A0>
+struct __libcpp_is_constructible<_Tp, _A0>
+    : public decltype(__is_constructible_helper::__test_unary<_Tp, _A0>(0))
+{};
 
-template <class _A0, class ..._Args>
-struct __contains_void<_A0, _Args...>
-{
-    static const bool value = is_void<_A0>::value ||
-                              __contains_void<_Args...>::value;
-};
+template <class _Tp, class _A0>
+struct __libcpp_is_constructible<_Tp&, _A0>
+    : public decltype(__is_constructible_helper::
+    __test_ref<_Tp&>(_VSTD::declval<_A0>()))
+{};
+
+template <class _Tp, class _A0>
+struct __libcpp_is_constructible<_Tp&&, _A0>
+    : public decltype(__is_constructible_helper::
+    __test_ref<_Tp&&>(_VSTD::declval<_A0>()))
+{};
 
 //      is_constructible entry point
 
 template <class _Tp, class... _Args>
 struct _LIBCPP_TYPE_VIS_ONLY is_constructible
-    : public __is_constructible_void_check<__contains_void<_Tp, _Args...>::value
-                                        || is_abstract<_Tp>::value,
-                                           _Tp, _Args...>
-    {};
-
-//      Array types are default constructible if their element type
-//      is default constructible
-
-template <class _Ap, size_t _Np>
-struct __libcpp_is_constructible<false, _Ap[_Np]>
-    : public is_constructible<typename remove_all_extents<_Ap>::type>
-    {};
-
-//      Otherwise array types are not constructible by this syntax
-
-template <class _Ap, size_t _Np, class ..._Args>
-struct __libcpp_is_constructible<false, _Ap[_Np], _Args...>
-    : public false_type
-    {};
-
-//      Incomplete array types are not constructible
-
-template <class _Ap, class ..._Args>
-struct __libcpp_is_constructible<false, _Ap[], _Args...>
-    : public false_type
-    {};
+    : public __libcpp_is_constructible<_Tp, _Args...>::type {};
+
 
 #else  // _LIBCPP_HAS_NO_VARIADICS
 

Modified: libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp?rev=276084&r1=276083&r2=276084&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp Wed Jul 20 00:01:24 2016
@@ -27,6 +27,9 @@ private:
     A(char);
 };
 
+struct Base {};
+struct Derived : public Base {};
+
 class Abstract
 {
     virtual void foo() = 0;
@@ -37,6 +40,21 @@ class AbstractDestructor
     virtual ~AbstractDestructor() = 0;
 };
 
+struct PrivateDtor {
+  PrivateDtor(int) {}
+private:
+  ~PrivateDtor() {}
+};
+
+struct S {
+   template <class T>
+#if TEST_STD_VER >= 11
+   explicit
+#endif
+   operator T () const { return T(); }
+};
+
+
 template <class T>
 void test_is_constructible()
 {
@@ -101,13 +119,41 @@ int main()
     test_is_not_constructible<int&> ();
     test_is_not_constructible<Abstract> ();
     test_is_not_constructible<AbstractDestructor> ();
+    test_is_constructible<int, S>();
+    test_is_not_constructible<int&, S>();
+
+#if TEST_STD_VER >= 11
+    test_is_constructible<int const&, int>();
+    test_is_constructible<int const&, int&&>();
 
-//  LWG 2560  -- postpone this test until bots updated
-//     test_is_not_constructible<void()> ();
-#if TEST_STD_VER > 11
-//     test_is_not_constructible<void() const> ();
-//     test_is_not_constructible<void() volatile> ();
-//     test_is_not_constructible<void() &> ();
-//     test_is_not_constructible<void() &&> ();
+    test_is_not_constructible<int&, int>();
+    test_is_not_constructible<int&, int const&>();
+    test_is_not_constructible<int&, int&&>();
+
+    test_is_constructible<int&&, int>();
+    test_is_constructible<int&&, int&&>();
+    test_is_not_constructible<int&&, int&>();
+    test_is_not_constructible<int&&, int const&&>();
+
+    test_is_constructible<Base, Derived>();
+    test_is_constructible<Base&, Derived&>();
+    test_is_not_constructible<Derived&, Base&>();
+    test_is_constructible<Base const&, Derived const&>();
+    test_is_not_constructible<Derived const&, Base const&>();
+    test_is_not_constructible<Derived const&, Base>();
+
+    test_is_constructible<Base&&, Derived>();
+    test_is_constructible<Base&&, Derived&&>();
+    test_is_not_constructible<Derived&&, Base&&>();
+    test_is_not_constructible<Derived&&, Base>();
+
+    // test that T must also be destructible
+    test_is_constructible<PrivateDtor&, PrivateDtor&>();
+    test_is_not_constructible<PrivateDtor, int>();
+
+    test_is_not_constructible<void() const> ();
+    test_is_not_constructible<void() volatile> ();
+    test_is_not_constructible<void() &> ();
+    test_is_not_constructible<void() &&> ();
 #endif
 }

Modified: libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_default_constructible.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_default_constructible.pass.cpp?rev=276084&r1=276083&r2=276084&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_default_constructible.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_default_constructible.pass.cpp Wed Jul 20 00:01:24 2016
@@ -92,15 +92,22 @@ int main()
     test_is_default_constructible<int*>();
     test_is_default_constructible<const int*>();
     test_is_default_constructible<char[3]>();
+    test_is_default_constructible<char[5][3]>();
+
     test_is_default_constructible<NotEmpty>();
     test_is_default_constructible<bit_zero>();
 
     test_is_not_default_constructible<void>();
     test_is_not_default_constructible<int&>();
     test_is_not_default_constructible<char[]>();
+    test_is_not_default_constructible<char[][3]>();
+
     test_is_not_default_constructible<Abstract>();
     test_is_not_default_constructible<NoDefaultConstructor>();
 #if TEST_STD_VER >= 11
     test_is_not_default_constructible<B>();
+    test_is_not_default_constructible<int&&>();
+    test_is_not_default_constructible<void()>();
+    test_is_not_default_constructible<void() const>();
 #endif
 }




More information about the cfe-commits mailing list