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, "");