On Fri, 1 May 2020 at 21:15, Ville Voutilainen
<[email protected]> 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 <[email protected]>
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, "");