On 09/04/20 17:00 -0400, Marek Polacek wrote:
In C++20 this is well-formed:

 using T = int[2];
 T t(1, 2);

which means that std::is_constructible_v<int[2], int, int> should be true.
But constructible_expr immediately returned the error_mark_node when it
saw a list with more than one element.  To give accurate results in
C++20, we have to try initializing the aggregate from a parenthesized list of
values.

To not repeat the same mistake as in c++/93790, if there's only one
element, I'm trying {} only when () didn't succeed.  is_constructible5.C
verifies this.

Jon, in paren-init24.C std::is_nothrow_constructible_v doesn't work,
I'm getting
error: invalid 'static_cast' from type 'int' to type 'int [1]'
and
error: functional cast to array type 'int [2]'

Are these the issues you had in mind when we spoke earlier today?

Here's the library change needed to uncomment the FIXMEs in
paren-init24.C

Bootstrapped and tested on powerpc64le-linux, I plan to commit this
to master today.


commit 474660c50d0983cf37a9da62fe7156b132076528
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Tue Apr 21 12:47:17 2020 +0100

    libstdc++: Support arrays in std::is_nothrow_constructible (PR 94149)
    
    The front end now supports parenthesized initialization for arrays in
    C++20, so extend std::is_nothrow_constructible to support them too.
    
    gcc/testsuite:
    
            PR c++/94149
            * g++.dg/cpp2a/paren-init24.C: Fix FIXMEs.
    
    libstdc++-v3:
    
            PR c++/94149
            * include/std/type_traits (__is_nt_constructible_impl): Add partial
            specializations for bounded arrays with non-empty initializers.
            * testsuite/20_util/is_nothrow_constructible/value_c++20.cc: New test.

diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init24.C b/gcc/testsuite/g++.dg/cpp2a/paren-init24.C
index a636a28ee6d..4e97bbc5b56 100644
--- a/gcc/testsuite/g++.dg/cpp2a/paren-init24.C
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init24.C
@@ -11,8 +11,7 @@ int main()
   static_assert(__is_constructible(T, int));
   static_assert(!__is_constructible(T, int, int));
   static_assert(std::is_constructible_v<T, int>);
-  //FIXME: libstdc++ problem?
-  //static_assert(std::is_nothrow_constructible_v<T, int>);
+  static_assert(std::is_nothrow_constructible_v<T, int>);
 
   using T2 = int[2];
   T2 t2(1);
@@ -21,6 +20,5 @@ int main()
   static_assert(__is_constructible(T2, int));
   static_assert(__is_constructible(T2, int, int));
   static_assert(std::is_constructible_v<T2, int, int>);
-  // FIXME libstdc++ problem?
-  //static_assert(std::is_nothrow_constructible_v<T2, int, int>);
+  static_assert(std::is_nothrow_constructible_v<T2, int, int>);
 }
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 65b9902b56d..f96b5297b83 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -986,6 +986,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public __bool_constant<noexcept(typename remove_all_extents<_Tp>::type())>
     { };
 
+#if __cpp_aggregate_paren_init
+  template<typename _Tp, size_t _Num, typename _Arg>
+    struct __is_nt_constructible_impl<true, _Tp[_Num], _Arg>
+    : public __is_nt_constructible_impl<true, _Tp, _Arg>
+    { };
+
+  template<typename _Tp, size_t _Num, typename... _Args>
+    struct __is_nt_constructible_impl<true, _Tp[_Num], _Args...>
+    : public __and_<__is_nt_constructible_impl<true, _Tp, _Args>...>
+    { };
+#endif
+
   template<typename _Tp, typename... _Args>
     using __is_nothrow_constructible_impl
       = __is_nt_constructible_impl<__is_constructible(_Tp, _Args...),
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_constructible/value_c++20.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_constructible/value_c++20.cc
new file mode 100644
index 00000000000..6bf0a513b14
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_constructible/value_c++20.cc
@@ -0,0 +1,69 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <type_traits>
+
+static_assert( std::is_nothrow_constructible_v<int[1]> );
+static_assert( std::is_nothrow_constructible_v<int[1], int> );
+static_assert( std::is_nothrow_constructible_v<int[2], int> );
+static_assert( std::is_nothrow_constructible_v<int[2], int, int> );
+static_assert( ! std::is_nothrow_constructible_v<int[1], int, int> );
+static_assert( ! std::is_nothrow_constructible_v<int[]> );
+static_assert( ! std::is_nothrow_constructible_v<int[], int> );
+static_assert( ! std::is_nothrow_constructible_v<int[], int, int> );
+
+struct X
+{
+  X() = default;
+  X(int) noexcept { }
+  X(double) { }
+};
+
+static_assert( std::is_nothrow_constructible_v<X[2]> );
+static_assert( std::is_nothrow_constructible_v<X[1], X> );
+static_assert( std::is_nothrow_constructible_v<X[1], int> );
+static_assert( ! std::is_nothrow_constructible_v<X[1], double> );
+static_assert( ! std::is_nothrow_constructible_v<X[2], int, double> );
+
+struct Y
+{
+  int i;
+  X x;
+};
+
+static_assert( std::is_nothrow_constructible_v<Y> );
+static_assert( std::is_nothrow_constructible_v<Y, Y> );
+static_assert( std::is_nothrow_constructible_v<Y, int> );
+static_assert( ! std::is_nothrow_constructible_v<Y, X> );
+static_assert( std::is_nothrow_constructible_v<Y, int, X> );
+static_assert( std::is_nothrow_constructible_v<Y, int, int> );
+static_assert( ! std::is_nothrow_constructible_v<Y, int, double> );
+
+struct Z : Y { };
+
+static_assert( std::is_nothrow_constructible_v<Z> );
+static_assert( std::is_nothrow_constructible_v<Z, Z> );
+static_assert( std::is_nothrow_constructible_v<Z, Y> );
+static_assert( ! std::is_nothrow_constructible_v<Z, int> );
+static_assert( ! std::is_nothrow_constructible_v<Z, int, X> );
+static_assert( ! std::is_nothrow_constructible_v<Z, int, int> );
+static_assert( ! std::is_nothrow_constructible_v<Z, Y, double> );
+static_assert( ! std::is_nothrow_constructible_v<Z, int, double> );
+static_assert( ! std::is_nothrow_constructible_v<Z, X> );

Reply via email to