[PATCH] P0357R3 reference_wrapper for incomplete types

Jonathan Wakely jwakely@redhat.com
Fri Jan 11 23:42:00 GMT 2019


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.

Tested powerpc64le-linux, committed to trunk.

-------------- next part --------------
commit d41fa8998e6b9760b4946df464296a2472e5fc06
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Jan 11 22:56:01 2019 +0000

    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.

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<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 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
+// <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)> );


More information about the Libstdc++ mailing list