Commit b3341826 by Jonathan Wakely

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.
parent 07fe4af4
2020-03-18 Jonathan Wakely <jwakely@redhat.com> 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 * include/std/stop_token (stop_token::_Stop_state_ref): Define
comparison operators explicitly if the compiler won't synthesize them. comparison operators explicitly if the compiler won't synthesize them.
......
...@@ -961,62 +961,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -961,62 +961,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"template argument must be a complete class or an unbounded array"); "template argument must be a complete class or an unbounded array");
}; };
template<typename _Tp> template<bool, typename _Tp, typename... _Args>
struct __is_nt_default_constructible_atom struct __is_nt_constructible_impl
: public integral_constant<bool, noexcept(_Tp())> : 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> template<typename _Tp, typename... _Args>
struct __is_nt_constructible_impl struct __is_nt_constructible_impl<true, _Tp, _Args...>
: public integral_constant<bool, noexcept(_Tp(declval<_Args>()...))> : public __bool_constant<noexcept(_Tp(std::declval<_Args>()...))>
{ }; { };
template<typename _Tp, typename _Arg> template<typename _Tp, typename _Arg>
struct __is_nt_constructible_impl<_Tp, _Arg> struct __is_nt_constructible_impl<true, _Tp, _Arg>
: public integral_constant<bool, : public __bool_constant<noexcept(static_cast<_Tp>(std::declval<_Arg>()))>
noexcept(static_cast<_Tp>(declval<_Arg>()))>
{ }; { };
template<typename _Tp> template<typename _Tp>
struct __is_nt_constructible_impl<_Tp> struct __is_nt_constructible_impl<true, _Tp>
: public __is_nothrow_default_constructible_impl<_Tp> : public __bool_constant<noexcept(_Tp())>
{ }; { };
template<typename _Tp, typename... _Args> template<typename _Tp, size_t _Num>
struct __is_nothrow_constructible_impl struct __is_nt_constructible_impl<true, _Tp[_Num]>
: public __and_<__is_constructible_impl<_Tp, _Args...>, : public __bool_constant<noexcept(typename remove_all_extents<_Tp>::type())>
__is_nt_constructible_impl<_Tp, _Args...>>
{ }; { };
template<typename _Tp, typename... _Args>
using __is_nothrow_constructible_impl
= __is_nt_constructible_impl<__is_constructible(_Tp, _Args...),
_Tp, _Args...>;
/// is_nothrow_constructible /// is_nothrow_constructible
template<typename _Tp, typename... _Args> template<typename _Tp, typename... _Args>
struct is_nothrow_constructible struct is_nothrow_constructible
...@@ -1026,6 +1000,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1026,6 +1000,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"template argument must be a complete class or an unbounded array"); "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> template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_nothrow_copy_constructible_impl; struct __is_nothrow_copy_constructible_impl;
......
// 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(); }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment