From 3ecec1eff783311415180f8d53cbbf782698960f Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Sat, 17 Jan 2015 00:21:41 +0000 Subject: [PATCH] re PR libstdc++/56785 (std::tuple of two elements does not apply empty base class optimization when one of its elements is a std::tuple with two elements) PR libstdc++/56785 * include/std/tuple (_Tuple_impl): Remove zero-element specialization and define one-element specialization. * testsuite/20_util/tuple/56785.cc: New. From-SVN: r219785 --- libstdc++-v3/ChangeLog | 7 + libstdc++-v3/include/std/tuple | 148 +++++++++++++++--- libstdc++-v3/testsuite/20_util/tuple/56785.cc | 32 ++++ 3 files changed, 163 insertions(+), 24 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/tuple/56785.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index b0db0dceb80..ae4f3cc8e1a 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,10 @@ +2015-01-17 Jonathan Wakely + + PR libstdc++/56785 + * include/std/tuple (_Tuple_impl): Remove zero-element specialization + and define one-element specialization. + * testsuite/20_util/tuple/56785.cc: New. + 2015-01-17 Jonathan Wakely * testsuite/22_locale/codecvt/codecvt_utf8/requirements/1.cc: diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index b7100495ff4..e500a762d87 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -158,30 +158,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct _Tuple_impl; - /** - * Zero-element tuple implementation. This is the basis case for the - * inheritance recursion. - */ - template - struct _Tuple_impl<_Idx> - { - template friend class _Tuple_impl; - - _Tuple_impl() = default; - - template - _Tuple_impl(allocator_arg_t, const _Alloc&) { } - - template - _Tuple_impl(allocator_arg_t, const _Alloc&, const _Tuple_impl&) { } - - template - _Tuple_impl(allocator_arg_t, const _Alloc&, _Tuple_impl&&) { } - - protected: - void _M_swap(_Tuple_impl&) noexcept { /* no-op */ } - }; - template struct __is_empty_non_tuple : is_empty<_Tp> { }; @@ -358,6 +334,130 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; + // Basis case of inheritance recursion. + template + struct _Tuple_impl<_Idx, _Head> + : private _Head_base<_Idx, _Head, __empty_not_final<_Head>::value> + { + template friend class _Tuple_impl; + + typedef _Head_base<_Idx, _Head, __empty_not_final<_Head>::value> _Base; + + static constexpr _Head& + _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } + + static constexpr const _Head& + _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } + + constexpr _Tuple_impl() + : _Base() { } + + explicit + constexpr _Tuple_impl(const _Head& __head) + : _Base(__head) { } + + template + explicit + constexpr _Tuple_impl(_UHead&& __head) + : _Base(std::forward<_UHead>(__head)) { } + + constexpr _Tuple_impl(const _Tuple_impl&) = default; + + constexpr + _Tuple_impl(_Tuple_impl&& __in) + noexcept(is_nothrow_move_constructible<_Head>::value) + : _Base(std::forward<_Head>(_M_head(__in))) { } + + template + constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UHead>& __in) + : _Base(_Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } + + template + constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead>&& __in) + : _Base(std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) + { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) + : _Base(__tag, __use_alloc<_Head>(__a)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Head& __head) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _UHead&& __head) + : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), + std::forward<_UHead>(__head)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl&& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), + std::forward<_Head>(_M_head(__in))) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl<_Idx, _UHead>& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), + _Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl<_Idx, _UHead>&& __in) + : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), + std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) + { } + + _Tuple_impl& + operator=(const _Tuple_impl& __in) + { + _M_head(*this) = _M_head(__in); + return *this; + } + + _Tuple_impl& + operator=(_Tuple_impl&& __in) + noexcept(is_nothrow_move_assignable<_Head>::value) + { + _M_head(*this) = std::forward<_Head>(_M_head(__in)); + return *this; + } + + template + _Tuple_impl& + operator=(const _Tuple_impl<_Idx, _UHead>& __in) + { + _M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in); + return *this; + } + + template + _Tuple_impl& + operator=(_Tuple_impl<_Idx, _UHead>&& __in) + { + _M_head(*this) + = std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)); + return *this; + } + + protected: + void + _M_swap(_Tuple_impl& __in) + noexcept(noexcept(swap(std::declval<_Head&>(), std::declval<_Head&>()))) + { + using std::swap; + swap(_M_head(*this), _M_head(__in)); + } + }; + /// Primary class template, tuple template class tuple : public _Tuple_impl<0, _Elements...> diff --git a/libstdc++-v3/testsuite/20_util/tuple/56785.cc b/libstdc++-v3/testsuite/20_util/tuple/56785.cc new file mode 100644 index 00000000000..504ab0aef18 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/56785.cc @@ -0,0 +1,32 @@ +// Copyright (C) 2015 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++11" } +// { dg-do compile } + +#include + +class Empty { }; + +using std::tuple; +using char_pair = tuple; + +static_assert( sizeof(tuple) == sizeof(char_pair), + "Nested tuple tuple> is too big"); + +static_assert( sizeof(tuple) == (2 * sizeof(char_pair)), + "Nested tuple> is too big" ); -- 2.30.2