On 02/05/15 13:39 +0100, Jonathan Wakely wrote:
My initial implementation of experimental::any was too dumb, it
assumed you could just swap the bytes of _Storage, and return it from
functions like any POD type, but if the _Storage object contains a
non-trivially-copyable object internally (not on the heap) then it's
wrong to treat it as a POD.

This patch makes the _Storage object non-copyable and fixes all the
uses of it.

Tested powerpc64le-linux, committed to trunk.

Here's a much smaller patch for the gcc5 branch, which just avoids the
small-object optimisation for non-trivially-copyable types. This
pessimises some types, but is safe.

(Given that this stuff is all "experimental" anyway, maybe we could
just backport the full fix from trunk, but this is OK for now.)

Tested powerpc64le-linux, committed to gcc-5-branch.
commit 81330dd9616c4adec9cdc72e32f64746a3834a47
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Sat May 2 13:44:16 2015 +0100

    	* include/experimental/any (_Internal): Check for trivially-copyable
    	instead of nothrow move constructible.
    	* testsuite/experimental/any/cons/nontrivial.cc: New.

diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any
index 8c205d5..487ba01 100644
--- a/libstdc++-v3/include/experimental/any
+++ b/libstdc++-v3/include/experimental/any
@@ -94,7 +94,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       std::aligned_storage<sizeof(_M_ptr), sizeof(_M_ptr)>::type _M_buffer;
     };
 
-    template<typename _Tp, typename _Safe = is_nothrow_move_constructible<_Tp>,
+    template<typename _Tp, typename _Safe = is_trivially_copyable<_Tp>,
 	     bool _Fits = (sizeof(_Tp) <= sizeof(_Storage))>
       using _Internal = std::integral_constant<bool, _Safe::value && _Fits>;
 
diff --git a/libstdc++-v3/testsuite/experimental/any/cons/nontrivial.cc b/libstdc++-v3/testsuite/experimental/any/cons/nontrivial.cc
new file mode 100644
index 0000000..14b7765
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/any/cons/nontrivial.cc
@@ -0,0 +1,75 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++14" }
+
+#include <experimental/any>
+#include <testsuite_hooks.h>
+
+struct LocationAware
+{
+  LocationAware() { }
+  ~LocationAware() { VERIFY(self == this); }
+  LocationAware(const LocationAware&) { }
+  LocationAware& operator=(const LocationAware&) { return *this; }
+  LocationAware(LocationAware&&) noexcept { }
+  LocationAware& operator=(LocationAware&&) noexcept { return *this; }
+
+  void* const self = this;
+};
+static_assert(std::is_nothrow_move_constructible<LocationAware>::value, "");
+static_assert(!std::is_trivially_copyable<LocationAware>::value, "");
+
+using std::experimental::any;
+
+void
+test01()
+{
+
+  LocationAware l;
+  any a = l;
+}
+
+void
+test02()
+{
+  LocationAware l;
+  any a = l;
+  any b = a;
+  {
+    any tmp = std::move(a);
+    a = std::move(b);
+    b = std::move(tmp);
+  }
+}
+
+void
+test03()
+{
+  LocationAware l;
+  any a = l;
+  any b = a;
+  swap(a, b);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}

Reply via email to