On Fri, 1 May 2020 at 21:15, Ville Voutilainen
<ville.voutilai...@gmail.com> wrote:
>
> Aggregate-paren-init breaks tuple and optional. This fixes the breakage.
> An LWG issue will be filed.

The previous approach was bogus. Here's a better one. Ok for master
and gcc-10 if
full testsuite run passes?

2020-05-02  Ville Voutilainen  <ville.voutilai...@gmail.com>

    PR libstdc++/94890
    * include/std/optional (__no_cpp20_converting_aggregates): New.
    (optional(_Up&&)): Use it.
    * include/std/tuple (__no_cpp20_converting_aggregates): New.
    (__valid_args): Use it.
    * testsuite/20_util/optional/cons/94890.cc: New.
    * testsuite/20_util/tuple/cons/94890.cc: Likewise.
diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional
index 37c2ba7a025..e74d79ddfc6 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -685,6 +685,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename... _Cond>
 	using _Requires = enable_if_t<__and_v<_Cond...>, bool>;
 
+      // Constraint for rejecting converting aggregates.
+      template <typename _Up>
+        static constexpr bool __no_cpp20_converting_aggregates()
+        {
+#if __cpp_aggregate_paren_init
+	  return !__and_<
+	           __and_<
+		     is_aggregate<_Tp>,
+	             __not_<
+		       is_same<_Tp,
+			       remove_reference_t<_Up>>>>>::value;
+#else
+	  return true;
+#endif
+        }
+
     public:
       using value_type = _Tp;
 
@@ -696,6 +712,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Up = _Tp,
 	       _Requires<__not_self<_Up>, __not_tag<_Up>,
 			 is_constructible<_Tp, _Up&&>,
+			 __bool_constant<
+			   __no_cpp20_converting_aggregates<_Up>()>,
 			 is_convertible<_Up&&, _Tp>> = true>
 	constexpr
 	optional(_Up&& __t)
@@ -704,6 +722,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _Up = _Tp,
 	       _Requires<__not_self<_Up>, __not_tag<_Up>,
 			 is_constructible<_Tp, _Up&&>,
+			 __bool_constant<
+			   __no_cpp20_converting_aggregates<_Up>()>,
 			 __not_<is_convertible<_Up&&, _Tp>>> = false>
 	explicit constexpr
 	optional(_Up&& __t)
diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index db4872d3a52..194b564341c 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -566,18 +566,40 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    __and_<is_nothrow_constructible<_Elements, _UElements>...>::value;
 	}
 
+
+      // Constraint for rejecting converting aggregates.
+      template <typename... _Args>
+        static constexpr bool __no_cpp20_converting_aggregates()
+        {
+#if __cpp_aggregate_paren_init
+	  return !__and_<
+	           __and_<
+		     is_aggregate<remove_reference_t<_Elements>>,
+	             __not_<
+		       is_same<remove_reference_t<_Elements>,
+			       remove_reference_t<_Args>>>>...>::value;
+#else
+	  return true;
+#endif
+        }
+
       // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) == 1.
       template<typename _Up>
 	static constexpr bool __valid_args()
 	{
 	  return sizeof...(_Elements) == 1
-	    && !is_same<tuple, __remove_cvref_t<_Up>>::value;
+	    && !is_same<tuple, __remove_cvref_t<_Up>>::value
+	    && __no_cpp20_converting_aggregates<_Up>();
 	}
 
       // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) > 1.
-      template<typename, typename, typename... _Tail>
-	static constexpr bool __valid_args()
-	{ return (sizeof...(_Tail) + 2) == sizeof...(_Elements); }
+      template<typename... _Args>
+      static constexpr
+      typename enable_if<(sizeof...(_Args) > 1), bool>::type __valid_args()
+	{
+	  return sizeof...(_Args) == sizeof...(_Elements)
+	    && __no_cpp20_converting_aggregates<_Args...>();
+	}
 
       /* Constraint for constructors with a tuple<UTypes...> parameter ensures
        * that the constructor is only viable when it would not interfere with
diff --git a/libstdc++-v3/testsuite/20_util/optional/cons/94890.cc b/libstdc++-v3/testsuite/20_util/optional/cons/94890.cc
new file mode 100644
index 00000000000..fe038eef7fc
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/optional/cons/94890.cc
@@ -0,0 +1,26 @@
+// Copyright (C) 2019-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/>.
+
+// { dg-do compile { target c++17 } }
+
+#include <optional>
+
+struct c { int i; };
+
+std::optional<c> x({0});
+
+static_assert(!std::is_convertible<int, std::optional<c>>::value, "");
diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/94890.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/94890.cc
new file mode 100644
index 00000000000..0665e2d9dd6
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/tuple/cons/94890.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2019-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/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <tuple>
+#include <type_traits>
+
+struct c { int i; };
+
+std::tuple<c> x({0});
+
+static_assert(!std::is_convertible<int, std::tuple<c>>::value, "");

Reply via email to