diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2019-01-11 23:41:11 +0000 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2019-01-11 23:41:11 +0000 |
commit | aaeac1568dfb8062ed622f1dad312b09f0c885f4 (patch) | |
tree | 110481d49087c9adfb538e4018d5c8dd8e514526 /libstdc++-v3 | |
parent | 5e9aed14dcb5c984186f8b1e042bde9f3aaafa5e (diff) | |
download | gcc-aaeac1568dfb8062ed622f1dad312b09f0c885f4.zip gcc-aaeac1568dfb8062ed622f1dad312b09f0c885f4.tar.gz gcc-aaeac1568dfb8062ed622f1dad312b09f0c885f4.tar.bz2 |
P0357R3 reference_wrapper for incomplete types
This patch implements the C++2a proposal to allow incomplete types in
std::reference_wrapper, which was previously undefined.
The change cannot be implemented for earlier standards, because prior to
C++2a std::reference_wrapper has a weak result type, so must inspect the
template argument to see if it defines a nested result_type member. That
is deprecated (but still required) in C++17, and removed from C++2a.
The removal of the base class from reference_wrapper is a potential ABI
change, as it could alter the layout of a type which derives from
reference_wrapper<T> and from an empty type with _Weak_result_type<T> as
a base class. Previously the repeated _Weak_result_type<T> base class
would have prevented the empty base-class optimization, but if
reference_wrapper<T> no longer derives from it, the empty class could be
placed at the same address as the reference_wrapper<T> base. In
practice, the only types which derive from _Weak_result_type or from
_Reference_wrapper_base_memfun or any of its base classes are non-empty
types defined in libstdc++: std::reference_wrapper, std::function, and
std::_Bind. As they are non-empty types, they are not eligible for EBO
anyway.
* include/bits/refwrap.h [__cplusplus > 201703L]
(_Refwrap_base_arg1, _Refwrap_base_arg2, _Reference_wrapper_base)
(_Reference_wrapper_base_memfun): Do not define for C++2a.
(reference_wrapper): Do not derive from _Reference_wrapper_base_memfun
for C++2a.
(reference_wrapper::operator()): Add static assertion.
* testsuite/20_util/reference_wrapper/incomplete.cc: New test.
From-SVN: r267866
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/ChangeLog | 8 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/refwrap.h | 9 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/reference_wrapper/incomplete.cc | 36 |
3 files changed, 53 insertions, 0 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 1a02113..9ae1fce 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,13 @@ 2019-01-11 Jonathan Wakely <jwakely@redhat.com> + * include/bits/refwrap.h [__cplusplus > 201703L] + (_Refwrap_base_arg1, _Refwrap_base_arg2, _Reference_wrapper_base) + (_Reference_wrapper_base_memfun): Do not define for C++2a. + (reference_wrapper): Do not derive from _Reference_wrapper_base_memfun + for C++2a. + (reference_wrapper::operator()): Add static assertion. + * testsuite/20_util/reference_wrapper/incomplete.cc: New test. + * include/std/chrono (duration_values::zero(), duration_values::min()) (duration_values::max()): Add noexcept. (duration::zero(), duration::min(), duration::max()): Likewise. diff --git a/libstdc++-v3/include/bits/refwrap.h b/libstdc++-v3/include/bits/refwrap.h index 5299b21..6b4335a 100644 --- a/libstdc++-v3/include/bits/refwrap.h +++ b/libstdc++-v3/include/bits/refwrap.h @@ -175,6 +175,7 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, true_type) : _Weak_result_type_memfun<typename remove_cv<_Functor>::type> { }; +#if __cplusplus <= 201703L // Detect nested argument_type. template<typename _Tp, typename = __void_t<>> struct _Refwrap_base_arg1 @@ -279,6 +280,7 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, true_type) { using result_type = typename _Mem_fn_traits<_MemFunPtr>::__result_type; }; +#endif // ! C++20 /** * @brief Primary class template for reference_wrapper. @@ -287,7 +289,11 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, true_type) */ template<typename _Tp> class reference_wrapper +#if __cplusplus <= 201703L + // In C++20 std::reference_wrapper<T> allows T to be incomplete, + // so checking for nested types could result in ODR violations. : public _Reference_wrapper_base_memfun<typename remove_cv<_Tp>::type> +#endif { _Tp* _M_data; @@ -327,6 +333,9 @@ _GLIBCXX_MEM_FN_TRAITS(&& noexcept, false_type, true_type) typename result_of<_Tp&(_Args&&...)>::type operator()(_Args&&... __args) const { +#if __cplusplus > 201703L + static_assert(sizeof(type), "type must be complete"); +#endif return std::__invoke(get(), std::forward<_Args>(__args)...); } }; diff --git a/libstdc++-v3/testsuite/20_util/reference_wrapper/incomplete.cc b/libstdc++-v3/testsuite/20_util/reference_wrapper/incomplete.cc new file mode 100644 index 0000000..6fce8d9 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/reference_wrapper/incomplete.cc @@ -0,0 +1,36 @@ +// Copyright (C) 2019 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++2a" } +// { dg-do compile { target c++2a } } + +// P0357R3 reference_wrapper for incomplete types + +#include <functional> + +struct Incomplete; + +template class std::reference_wrapper<Incomplete>; + +Incomplete& f(); + +std::reference_wrapper<Incomplete> r = f(); +static_assert( std::is_same_v<decltype(r)::type, Incomplete> ); +static_assert( std::is_same_v<decltype(r.get()), Incomplete&> ); + +std::reference_wrapper r2 = f(); +static_assert( std::is_same_v<decltype(r), decltype(r2)> ); |