2
0
mirror of git://gcc.gnu.org/git/gcc.git synced 2025-04-10 03:20:27 +08:00

libstdc++: Fix is_trivially_constructible (PR 94033)

This attempts to make is_nothrow_constructible more robust (and
efficient to compile) by not depending on is_constructible. Instead the
__is_constructible intrinsic is used directly. The helper class
__is_nt_constructible_impl which checks whether the construction is
non-throwing now takes a bool template parameter that is substituted by
the result of the instrinsic. This fixes the reported bug by not using
the already-instantiated (and incorrect) value of std::is_constructible.
I don't think it really fixes the problem in general, because
std::is_nothrow_constructible itself could already have been
instantiated in a context where it gives the wrong result. A proper fix
needs to be done in the compiler.

	PR libstdc++/94033
	* include/std/type_traits (__is_nt_default_constructible_atom): Remove.
	(__is_nt_default_constructible_impl): Remove.
	(__is_nothrow_default_constructible_impl): Remove.
	(__is_nt_constructible_impl): Add bool template parameter. Adjust
	partial specializations.
	(__is_nothrow_constructible_impl): Replace class template with alias
	template.
	(is_nothrow_default_constructible): Derive from alias template
	__is_nothrow_constructible_impl instead of
	__is_nothrow_default_constructible_impl.
	* testsuite/20_util/is_nothrow_constructible/94003.cc: New test.
This commit is contained in:
Jonathan Wakely 2020-03-18 23:19:12 +00:00
parent 07fe4af4d5
commit b334182653
3 changed files with 86 additions and 43 deletions
libstdc++-v3
ChangeLog
include/std
testsuite/20_util/is_nothrow_constructible

@ -1,5 +1,18 @@
2020-03-18 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/94033
* include/std/type_traits (__is_nt_default_constructible_atom): Remove.
(__is_nt_default_constructible_impl): Remove.
(__is_nothrow_default_constructible_impl): Remove.
(__is_nt_constructible_impl): Add bool template parameter. Adjust
partial specializations.
(__is_nothrow_constructible_impl): Replace class template with alias
template.
(is_nothrow_default_constructible): Derive from alias template
__is_nothrow_constructible_impl instead of
__is_nothrow_default_constructible_impl.
* testsuite/20_util/is_nothrow_constructible/94003.cc: New test.
* include/std/stop_token (stop_token::_Stop_state_ref): Define
comparison operators explicitly if the compiler won't synthesize them.

@ -961,61 +961,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"template argument must be a complete class or an unbounded array");
};
template<typename _Tp>
struct __is_nt_default_constructible_atom
: public integral_constant<bool, noexcept(_Tp())>
template<bool, typename _Tp, typename... _Args>
struct __is_nt_constructible_impl
: public false_type
{ };
template<typename _Tp, bool = is_array<_Tp>::value>
struct __is_nt_default_constructible_impl;
template<typename _Tp>
struct __is_nt_default_constructible_impl<_Tp, true>
: public __and_<__is_array_known_bounds<_Tp>,
__is_nt_default_constructible_atom<typename
remove_all_extents<_Tp>::type>>
{ };
template<typename _Tp>
struct __is_nt_default_constructible_impl<_Tp, false>
: public __is_nt_default_constructible_atom<_Tp>
{ };
template<typename _Tp>
using __is_nothrow_default_constructible_impl
= __and_<__is_constructible_impl<_Tp>,
__is_nt_default_constructible_impl<_Tp>>;
/// is_nothrow_default_constructible
template<typename _Tp>
struct is_nothrow_default_constructible
: public __is_nothrow_default_constructible_impl<_Tp>::type
{
static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
"template argument must be a complete class or an unbounded array");
};
template<typename _Tp, typename... _Args>
struct __is_nt_constructible_impl
: public integral_constant<bool, noexcept(_Tp(declval<_Args>()...))>
struct __is_nt_constructible_impl<true, _Tp, _Args...>
: public __bool_constant<noexcept(_Tp(std::declval<_Args>()...))>
{ };
template<typename _Tp, typename _Arg>
struct __is_nt_constructible_impl<_Tp, _Arg>
: public integral_constant<bool,
noexcept(static_cast<_Tp>(declval<_Arg>()))>
struct __is_nt_constructible_impl<true, _Tp, _Arg>
: public __bool_constant<noexcept(static_cast<_Tp>(std::declval<_Arg>()))>
{ };
template<typename _Tp>
struct __is_nt_constructible_impl<_Tp>
: public __is_nothrow_default_constructible_impl<_Tp>
struct __is_nt_constructible_impl<true, _Tp>
: public __bool_constant<noexcept(_Tp())>
{ };
template<typename _Tp, size_t _Num>
struct __is_nt_constructible_impl<true, _Tp[_Num]>
: public __bool_constant<noexcept(typename remove_all_extents<_Tp>::type())>
{ };
template<typename _Tp, typename... _Args>
struct __is_nothrow_constructible_impl
: public __and_<__is_constructible_impl<_Tp, _Args...>,
__is_nt_constructible_impl<_Tp, _Args...>>
{ };
using __is_nothrow_constructible_impl
= __is_nt_constructible_impl<__is_constructible(_Tp, _Args...),
_Tp, _Args...>;
/// is_nothrow_constructible
template<typename _Tp, typename... _Args>
@ -1026,6 +1000,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"template argument must be a complete class or an unbounded array");
};
/// is_nothrow_default_constructible
template<typename _Tp>
struct is_nothrow_default_constructible
: public __is_nothrow_constructible_impl<_Tp>::type
{
static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
"template argument must be a complete class or an unbounded array");
};
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_nothrow_copy_constructible_impl;

@ -0,0 +1,46 @@
// 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/>.
// { dg-options "-std=gnu++17" }
// { dg-do compile { target c++17 } }
#include <optional>
#include <tuple>
template <bool B> struct abc {};
template <typename T>
struct future : public abc<std::is_trivially_constructible_v<std::tuple<T>>> {};
class mutation {
mutation();
friend class std::optional<mutation>;
};
using mutation_opt = std::optional<mutation>;
future<mutation_opt> foo();
template <typename Consumer> future<mutation_opt> consume_partitions() {
return foo();
}
future<mutation_opt> bar() { return consume_partitions<int>(); }
future<mutation> zed();
future<mutation> apply_counter_update() { return zed(); }