P0357R3 reference_wrapper for incomplete types
authorJonathan Wakely <jwakely@redhat.com>
Fri, 11 Jan 2019 23:41:11 +0000 (23:41 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 11 Jan 2019 23:41:11 +0000 (23:41 +0000)
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

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/refwrap.h
libstdc++-v3/testsuite/20_util/reference_wrapper/incomplete.cc [new file with mode: 0644]

index 1a0211336b31bd8319ebf8ba93733c75a44c2d3f..9ae1fced094ad9235eae5b2e6173eb57372cf7e9 100644 (file)
@@ -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.
index 5299b2125103633cae7f30818e1419488edc3e78..6b4335a22ac688de8e751636bf4944fef68986a6 100644 (file)
@@ -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 (file)
index 0000000..6fce8d9
--- /dev/null
@@ -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)> );