diff options
author | Ville Voutilainen <ville.voutilainen@gmail.com> | 2015-09-25 19:41:45 +0300 |
---|---|---|
committer | Ville Voutilainen <ville@gcc.gnu.org> | 2015-09-25 19:41:45 +0300 |
commit | 5e2f2cd5842d2543721a895c64a3b2a553542344 (patch) | |
tree | 4b6be450261dddabdc4c78c3e479be2e192f2ee6 | |
parent | 41d9f1e0397b3661f765d21d8397e2a54aa4cd55 (diff) | |
download | gcc-5e2f2cd5842d2543721a895c64a3b2a553542344.zip gcc-5e2f2cd5842d2543721a895c64a3b2a553542344.tar.gz gcc-5e2f2cd5842d2543721a895c64a3b2a553542344.tar.bz2 |
Avoid creating dangling references in case of nested tuples
for tuple constructors that construct from other tuples.
2015-09-25 Ville Voutilainen <ville.voutilainen@gmail.com>
Avoid creating dangling references in case of nested tuples
for tuple constructors that construct from other tuples.
* include/std/tuple (_TC::_NonNestedTuple): New.
* include/std/tuple (tuple::_TNTC): New.
* include/std/tuple (tuple(const tuple<_UElements...>&),
tuple(tuple<_UElements...>&&): Use _TNTC.
* testsuite/20_util/tuple/cons/nested_tuple_construct.cc: New.
From-SVN: r228134
-rw-r--r-- | libstdc++-v3/ChangeLog | 10 | ||||
-rw-r--r-- | libstdc++-v3/include/std/tuple | 44 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/tuple/cons/nested_tuple_construct.cc | 60 |
3 files changed, 106 insertions, 8 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 24a6050..50f6e8b 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,13 @@ +2015-09-25 Ville Voutilainen <ville.voutilainen@gmail.com> + + Avoid creating dangling references in case of nested tuples + for tuple constructors that construct from other tuples. + * include/std/tuple (_TC::_NonNestedTuple): New. + * include/std/tuple (tuple::_TNTC): New. + * include/std/tuple (tuple(const tuple<_UElements...>&), + tuple(tuple<_UElements...>&&): Use _TNTC. + * testsuite/20_util/tuple/cons/nested_tuple_construct.cc: New. + 2015-09-24 Jonathan Wakely <jwakely@redhat.com> PR libstdc++/67707 diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 59b992a..751d7eb 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -486,6 +486,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __and_<is_convertible<_UElements&&, _Elements>...>::value; } + + template<typename _SrcTuple> + static constexpr bool _NonNestedTuple() + { + return __and_<__not_<is_convertible<_SrcTuple, _Elements...>>, + __not_<is_constructible<_Elements..., _SrcTuple>> + >::value; + } }; template<typename... _Elements> @@ -514,6 +522,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return false; } + + template<typename... _UElements> + static constexpr bool _NonNestedTuple() + { + return true; + } }; /// Primary class template, tuple @@ -599,40 +613,54 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr tuple(tuple&&) = default; - template<typename... _UElements, typename + // Shortcut for the cases where constructors taking tuples + // must avoid creating temporaries. + template<typename _Dummy> using _TNTC = + _TC<is_same<_Dummy, void>::value && sizeof...(_Elements) == 1, + _Elements...>; + + template<typename... _UElements, typename _Dummy = void, typename enable_if<_TMC<_UElements...>::template _ConstructibleTuple<_UElements...>() && _TMC<_UElements...>::template - _ImplicitlyConvertibleTuple<_UElements...>(), + _ImplicitlyConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple<const tuple<_UElements...>&>(), bool>::type=true> constexpr tuple(const tuple<_UElements...>& __in) : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) { } - template<typename... _UElements, typename + template<typename... _UElements, typename _Dummy = void, typename enable_if<_TMC<_UElements...>::template _ConstructibleTuple<_UElements...>() && !_TMC<_UElements...>::template - _ImplicitlyConvertibleTuple<_UElements...>(), + _ImplicitlyConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple<const tuple<_UElements...>&>(), bool>::type=false> explicit constexpr tuple(const tuple<_UElements...>& __in) : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) { } - template<typename... _UElements, typename + template<typename... _UElements, typename _Dummy = void, typename enable_if<_TMC<_UElements...>::template _MoveConstructibleTuple<_UElements...>() && _TMC<_UElements...>::template - _ImplicitlyMoveConvertibleTuple<_UElements...>(), + _ImplicitlyMoveConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple<tuple<_UElements...>&&>(), bool>::type=true> constexpr tuple(tuple<_UElements...>&& __in) : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } - template<typename... _UElements, typename + template<typename... _UElements, typename _Dummy = void, typename enable_if<_TMC<_UElements...>::template _MoveConstructibleTuple<_UElements...>() && !_TMC<_UElements...>::template - _ImplicitlyMoveConvertibleTuple<_UElements...>(), + _ImplicitlyMoveConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple<tuple<_UElements...>&&>(), bool>::type=false> explicit constexpr tuple(tuple<_UElements...>&& __in) : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/nested_tuple_construct.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/nested_tuple_construct.cc new file mode 100644 index 0000000..32ef3cc --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/nested_tuple_construct.cc @@ -0,0 +1,60 @@ +#include <string> +#include <tuple> +#include <testsuite_hooks.h> + +static std::string result; + +struct X { + int state; // this has to be here + X() { + result += "Def"; + } + + X(X const&) { + result += "Copy"; + } + + X(X&&) { + result += "Move"; + } + + ~X() { + result += "Dtor"; + } +}; + +void f() +{ + X v; + std::tuple<X> t1{v}; + std::tuple<std::tuple<X>&&> t2{std::move(t1)}; + std::tuple<std::tuple<X>> t3{std::move(t2)}; +} + +void f2() +{ + X v; + std::tuple<X> t1{std::move(v)}; + std::tuple<std::tuple<X>&&> t2{std::move(t1)}; + std::tuple<std::tuple<X>> t3{std::move(t2)}; +} + +void f3() +{ + std::tuple<X> t1{X{}}; + std::tuple<std::tuple<X>&&> t2{std::move(t1)}; + std::tuple<std::tuple<X>> t3{std::move(t2)}; +} + +int main() +{ + f(); + VERIFY(result == "DefCopyMoveDtorDtorDtor"); + result = ""; + f2(); + VERIFY(result == "DefMoveMoveDtorDtorDtor"); + result = ""; + f3(); + VERIFY(result == "DefMoveDtorMoveDtorDtor"); + result = ""; +} |