From aaeac1568dfb8062ed622f1dad312b09f0c885f4 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 11 Jan 2019 23:41:11 +0000 Subject: [PATCH] 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 and from an empty type with _Weak_result_type as a base class. Previously the repeated _Weak_result_type base class would have prevented the empty base-class optimization, but if reference_wrapper no longer derives from it, the empty class could be placed at the same address as the reference_wrapper 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 --- libstdc++-v3/ChangeLog | 8 +++++ libstdc++-v3/include/bits/refwrap.h | 9 +++++ .../20_util/reference_wrapper/incomplete.cc | 36 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 libstdc++-v3/testsuite/20_util/reference_wrapper/incomplete.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 1a0211336b3..9ae1fced094 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,13 @@ 2019-01-11 Jonathan Wakely + * 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 5299b212510..6b4335a22ac 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::type> { }; +#if __cplusplus <= 201703L // Detect nested argument_type. template> 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 class reference_wrapper +#if __cplusplus <= 201703L + // In C++20 std::reference_wrapper allows T to be incomplete, + // so checking for nested types could result in ODR violations. : public _Reference_wrapper_base_memfun::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 00000000000..6fce8d9e304 --- /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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +// P0357R3 reference_wrapper for incomplete types + +#include + +struct Incomplete; + +template class std::reference_wrapper; + +Incomplete& f(); + +std::reference_wrapper r = f(); +static_assert( std::is_same_v ); +static_assert( std::is_same_v ); + +std::reference_wrapper r2 = f(); +static_assert( std::is_same_v );