summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorville <ville@138bc75d-0d04-0410-961f-82ee72b054a4>2015-09-25 16:41:45 +0000
committerville <ville@138bc75d-0d04-0410-961f-82ee72b054a4>2015-09-25 16:41:45 +0000
commit63e26b218b009b1cec13faa237b6e10cf347a078 (patch)
tree4b6be450261dddabdc4c78c3e479be2e192f2ee6
parenta6871bda07973b01bb6472dbd4cac03339cce8e2 (diff)
downloadgcc-63e26b218b009b1cec13faa237b6e10cf347a078.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@228134 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--libstdc++-v3/ChangeLog10
-rw-r--r--libstdc++-v3/include/std/tuple44
-rw-r--r--libstdc++-v3/testsuite/20_util/tuple/cons/nested_tuple_construct.cc60
3 files changed, 106 insertions, 8 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 24a60508cce..50f6e8b694c 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 59b992a4a06..751d7eb97cc 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 00000000000..32ef3cc0259
--- /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 = "";
+}