diff mbox series

PR c++/90532 Ensure __is_constructible(T[]) is false

Message ID 20190520104308.GA2178@redhat.com
State New
Headers show
Series PR c++/90532 Ensure __is_constructible(T[]) is false | expand

Commit Message

Jonathan Wakely May 20, 2019, 10:43 a.m. UTC
An array of an unknown bound is an incomplete type, so no object of such
a type can be constructed. This means __is_constructible should always
be false for an array of unknown bound.

This patch also changes the std::is_default_constructible trait to use
std::is_constructible, which now gives the right answer for arrays of
unknown bound.

gcc/cp:

	PR c++/90532 Ensure __is_constructible(T[]) is false
	* method.c (is_xible_helper): Return error_mark_node for construction
	of an array of unknown bound.

gcc/testsuite:

	PR c++/90532 Ensure __is_constructible(T[]) is false
	* g++.dg/ext/90532.C: New test.

libstdc++-v3:

	PR c++/90532 Ensure __is_constructible(T[]) is false
	* include/std/type_traits (__do_is_default_constructible_impl)
	(__is_default_constructible_atom, __is_default_constructible_safe):
	Remove.
	(is_default_constructible): Use is_constructible.
	* testsuite/20_util/is_constructible/value.cc: Check int[] case.
	* testsuite/20_util/is_default_constructible/value.cc: Likewise.
	* testsuite/20_util/is_trivially_constructible/value.cc: Likewise.
	* testsuite/20_util/is_trivially_default_constructible/value.cc:
	Likewise.

Tested powerpc64le-linux. Is the G++ change OK for trunk?

This fixes a regression on gcc-9-branch and gcc-8-branch, because
changing std::is_constructible to use __is_constructible caused it to
start giving the wrong answer for arrays of unknown bound. OK for the
branches too, after appropriate testing?
commit 7345fea9bc28c0c7bd5d9e72a5f97341e6c0e4c2
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon May 20 10:13:19 2019 +0100

    PR c++/90532 Ensure __is_constructible(T[]) is false
    
    An array of an unknown bound is an incomplete type, so no object of such
    a type can be constructed. This means __is_constructible should always
    be false for an array of unknown bound.
    
    This patch also changes the std::is_default_constructible trait to use
    std::is_constructible, which now gives the right answer for arrays of
    unknown bound.
    
    gcc/cp:
    
            PR c++/90532 Ensure __is_constructible(T[]) is false
            * method.c (is_xible_helper): Return error_mark_node for construction
            of an array of unknown bound.
    
    gcc/testsuite:
    
            PR c++/90532 Ensure __is_constructible(T[]) is false
            * g++.dg/ext/90532.C: New test.
    
    libstdc++-v3:
    
            PR c++/90532 Ensure __is_constructible(T[]) is false
            * include/std/type_traits (__do_is_default_constructible_impl)
            (__is_default_constructible_atom, __is_default_constructible_safe):
            Remove.
            (is_default_constructible): Use is_constructible.
            * testsuite/20_util/is_constructible/value.cc: Check int[] case.
            * testsuite/20_util/is_default_constructible/value.cc: Likewise.
            * testsuite/20_util/is_trivially_constructible/value.cc: Likewise.
            * testsuite/20_util/is_trivially_default_constructible/value.cc:
            Likewise.

Comments

Nathan Sidwell May 20, 2019, 11:29 a.m. UTC | #1
On 5/20/19 6:43 AM, Jonathan Wakely wrote:
> An array of an unknown bound is an incomplete type, so no object of such
> a type can be constructed. This means __is_constructible should always
> be false for an array of unknown bound.
> 
> This patch also changes the std::is_default_constructible trait to use
> std::is_constructible, which now gives the right answer for arrays of
> unknown bound.
> 
> gcc/cp:
> 
>      PR c++/90532 Ensure __is_constructible(T[]) is false
>      * method.c (is_xible_helper): Return error_mark_node for construction
>      of an array of unknown bound.

ok, thanks
Jonathan Wakely May 20, 2019, 11:33 a.m. UTC | #2
On 20/05/19 07:29 -0400, Nathan Sidwell wrote:
>On 5/20/19 6:43 AM, Jonathan Wakely wrote:
>>An array of an unknown bound is an incomplete type, so no object of such
>>a type can be constructed. This means __is_constructible should always
>>be false for an array of unknown bound.
>>
>>This patch also changes the std::is_default_constructible trait to use
>>std::is_constructible, which now gives the right answer for arrays of
>>unknown bound.
>>
>>gcc/cp:
>>
>>     PR c++/90532 Ensure __is_constructible(T[]) is false
>>     * method.c (is_xible_helper): Return error_mark_node for construction
>>     of an array of unknown bound.
>
>ok, thanks

I noticed a missing space here, so I fixed that before committing:

-  else if (TREE_CODE(to) == ARRAY_TYPE && !TYPE_DOMAIN (to))
+  else if (TREE_CODE (to) == ARRAY_TYPE && !TYPE_DOMAIN (to))
diff mbox series

Patch

diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 3fb3b5a9091..8421d6d7fa8 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1201,6 +1201,8 @@  is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
     expr = assignable_expr (to, from);
   else if (trivial && from && TREE_CHAIN (from))
     return error_mark_node; // only 0- and 1-argument ctors can be trivial
+  else if (TREE_CODE(to) == ARRAY_TYPE && !TYPE_DOMAIN (to))
+    return error_mark_node; // can't construct an array of unknown bound
   else
     expr = constructible_expr (to, from);
   return expr;
diff --git a/gcc/testsuite/g++.dg/ext/90532.C b/gcc/testsuite/g++.dg/ext/90532.C
new file mode 100644
index 00000000000..acdc4e2b07e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/90532.C
@@ -0,0 +1,27 @@ 
+// { dg-do compile { target c++11 } }
+// PR c++/90532
+static_assert( !__is_constructible(int[]), "" );
+static_assert( !__is_constructible(int[], int), "" );
+static_assert( !__is_constructible(int[], int[]), "" );
+static_assert( !__is_trivially_constructible(int[]), "" );
+static_assert( !__is_trivially_constructible(int[], int), "" );
+static_assert( !__is_trivially_constructible(int[], int[]), "" );
+static_assert( !__is_trivially_constructible(int[], int(&)[]), "" );
+static_assert( !__is_trivially_constructible(int[], void), "" );
+struct A { };
+static_assert( !__is_constructible(A[]), "" );
+static_assert( !__is_constructible(A[], const A&), "" );
+static_assert( !__is_constructible(A[], const A[]), "" );
+static_assert( !__is_trivially_constructible(A[]), "" );
+static_assert( !__is_trivially_constructible(A[], const A&), "" );
+static_assert( !__is_trivially_constructible(A[], const A[]), "" );
+static_assert( !__is_trivially_constructible(A[], A(&)[]), "" );
+static_assert( !__is_trivially_constructible(A[], void), "" );
+struct B { B(); };
+static_assert( !__is_constructible(B[]), "" );
+static_assert( !__is_constructible(B[], const B&), "" );
+static_assert( !__is_trivially_constructible(B[]), "" );
+static_assert( !__is_trivially_constructible(B[], const B&), "" );
+static_assert( !__is_trivially_constructible(B[], const B[]), "" );
+static_assert( !__is_trivially_constructible(B[], B(&)[]), "" );
+static_assert( !__is_trivially_constructible(B[], void), "" );
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index b1c3e943e79..3a622eb61e0 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -878,58 +878,16 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __is_nt_destructible_safe<_Tp>::type
     { };
 
-  struct __do_is_default_constructible_impl
-  {
-    template<typename _Tp, typename = decltype(_Tp())>
-      static true_type __test(int);
-
-    template<typename>
-      static false_type __test(...);
-  };
-
-  template<typename _Tp>
-    struct __is_default_constructible_impl
-    : public __do_is_default_constructible_impl
-    {
-      typedef decltype(__test<_Tp>(0)) type;
-    };
-
-  template<typename _Tp>
-    struct __is_default_constructible_atom
-    : public __and_<__not_<is_void<_Tp>>,
-                    __is_default_constructible_impl<_Tp>>
-    { };
-
-  template<typename _Tp, bool = is_array<_Tp>::value>
-    struct __is_default_constructible_safe;
-
-  // The following technique is a workaround for a current core language
-  // restriction, which does not allow for array types to occur in
-  // functional casts of the form T().  Complete arrays can be default-
-  // constructed, if the element type is default-constructible, but
-  // arrays with unknown bounds are not.
-  template<typename _Tp>
-    struct __is_default_constructible_safe<_Tp, true>
-    : public __and_<__is_array_known_bounds<_Tp>,
-		    __is_default_constructible_atom<typename
-                      remove_all_extents<_Tp>::type>>
-    { };
-
-  template<typename _Tp>
-    struct __is_default_constructible_safe<_Tp, false>
-    : public __is_default_constructible_atom<_Tp>::type
+  /// is_constructible
+  template<typename _Tp, typename... _Args>
+    struct is_constructible
+      : public __bool_constant<__is_constructible(_Tp, _Args...)>
     { };
 
   /// is_default_constructible
   template<typename _Tp>
     struct is_default_constructible
-    : public __is_default_constructible_safe<_Tp>::type
-    { };
-
-  /// is_constructible
-  template<typename _Tp, typename... _Args>
-    struct is_constructible
-      : public __bool_constant<__is_constructible(_Tp, _Args...)>
+    : public is_constructible<_Tp>::type
     { };
 
   template<typename _Tp, bool = __is_referenceable<_Tp>::value>
diff --git a/libstdc++-v3/testsuite/20_util/is_constructible/value.cc b/libstdc++-v3/testsuite/20_util/is_constructible/value.cc
index acd7a5f5703..a8b40921d92 100644
--- a/libstdc++-v3/testsuite/20_util/is_constructible/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_constructible/value.cc
@@ -35,4 +35,11 @@  void test01()
   static_assert(test_property<is_constructible, ExplicitClass>(false), "");
   static_assert(test_property<is_constructible, ExplicitClass,
 		int, double>(false), "");
+  static_assert(test_property<is_constructible, int[]>(false), "PR c++/90532");
+  static_assert(test_property<is_constructible,
+		__gnu_test::construct::Empty[]>(false), "PR c++/90532");
+  static_assert(test_property<is_constructible,
+		__gnu_test::construct::Ukn[]>(false), "PR c++/90532");
+  static_assert(test_property<is_constructible,
+		__gnu_test::construct::nAny[]>(false), "PR c++/90532");
 }
diff --git a/libstdc++-v3/testsuite/20_util/is_default_constructible/value.cc b/libstdc++-v3/testsuite/20_util/is_default_constructible/value.cc
index bd66ed0ab92..f6df45d841b 100644
--- a/libstdc++-v3/testsuite/20_util/is_default_constructible/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_default_constructible/value.cc
@@ -138,3 +138,13 @@  static_assert(!std::is_default_constructible<DelCopy>::value, "Error");
 static_assert(!std::is_default_constructible<const DelCopy>::value, "Error");
 static_assert(!std::is_default_constructible<DelDtor>::value, "Error");
 static_assert(!std::is_default_constructible<const DelDtor>::value, "Error");
+
+static_assert(!std::is_default_constructible<int[]>::value, "PR c++/90532");
+static_assert(!std::is_default_constructible<Empty[]>::value, "PR c++/90532");
+static_assert(!std::is_default_constructible<B[]>::value, "PR c++/90532");
+static_assert(!std::is_default_constructible<D[]>::value, "PR c++/90532");
+static_assert(!std::is_default_constructible<U[]>::value, "PR c++/90532");
+static_assert(!std::is_default_constructible<Ukn[]>::value, "PR c++/90532");
+static_assert(!std::is_default_constructible<Ellipsis[]>::value, "PR c++/90532");
+static_assert(!std::is_default_constructible<Any[]>::value, "PR c++/90532");
+static_assert(!std::is_default_constructible<nAny[]>::value, "PR c++/90532");
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_constructible/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_constructible/value.cc
index 0c8ad62dbbc..0979ceff7e3 100644
--- a/libstdc++-v3/testsuite/20_util/is_trivially_constructible/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_constructible/value.cc
@@ -180,4 +180,6 @@  void test01()
 		MoveOnly, const MoveOnly&>(false), "");
   static_assert(test_property<is_trivially_constructible,
 		MoveOnly2>(false), "");
+  static_assert(test_property<is_trivially_constructible,
+		int[]>(false), "PR c++/90532");
 }
diff --git a/libstdc++-v3/testsuite/20_util/is_trivially_default_constructible/value.cc b/libstdc++-v3/testsuite/20_util/is_trivially_default_constructible/value.cc
index 8baca915df3..f457721925d 100644
--- a/libstdc++-v3/testsuite/20_util/is_trivially_default_constructible/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_trivially_default_constructible/value.cc
@@ -62,4 +62,13 @@  void test01()
 		construct::Nontrivial>(false), "");
   static_assert(test_category<is_trivially_default_constructible, 
 		HasTemplateCtor>(true), "");
+
+  static_assert(test_category<is_trivially_default_constructible,
+		int[]>(false), "PR c++/90532");
+  struct A { };
+  static_assert(test_category<is_trivially_default_constructible,
+		A[]>(false), "PR c++/90532");
+  struct B { B() { } };
+  static_assert(test_category<is_trivially_default_constructible,
+		B[]>(false), "PR c++/90532");
 }