public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch] Fix std::experimental::any for small, non-trivial objects
@ 2015-05-02 12:39 Jonathan Wakely
  2015-05-02 13:04 ` Jonathan Wakely
  0 siblings, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2015-05-02 12:39 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 427 bytes --]

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.


[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 10083 bytes --]

commit 4eda9966d42f3de4dc23197e3b47afbe5f44d83a
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Nov 3 20:15:54 2014 +0000

    	* include/experimental/any (any::_Storage): Make non-copyable.
    	(any::any): Do not copy _Storage object.
    	(any::operator=): Implement more efficiently than swapping.
    	(any::swap): Use new _Op_xfer operation.
    	(any::_Op::_Op_xfer): New enumerator.
    	(_Manager_internal::_S_alloc): Remove unused function.
    	(_Manager_internal::_S_create, _Manager_external::_S_create): Use out
    	parameter instead of returning a _Storage object.
    	(_Manager_internal::_S_manage, _Manager_external::_S_manage): Add
    	_Op_xfer operation for moving and swapping.
    	* testsuite/experimental/any/cons/nontrivial.cc: New.
    	* testsuite/experimental/any/misc/any_cast_neg.cc: Adjust dg-error.

diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any
index 8c205d5..b2d1b9c 100644
--- a/libstdc++-v3/include/experimental/any
+++ b/libstdc++-v3/include/experimental/any
@@ -90,6 +90,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     // Holds either pointer to a heap object or the contained object itself.
     union _Storage
     {
+      // This constructor intentionally doesn't initialize anything.
+      _Storage() = default;
+
+      // Prevent trivial copies of this type, buffer might hold a non-POD.
+      _Storage(const _Storage&) = delete;
+      _Storage& operator=(const _Storage&) = delete;
+
       void* _M_ptr;
       std::aligned_storage<sizeof(_M_ptr), sizeof(_M_ptr)>::type _M_buffer;
     };
@@ -119,33 +126,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     any() noexcept : _M_manager(nullptr) { }
 
     /// Copy constructor, copies the state of @p __other
-    any(const any& __other) : _M_manager(__other._M_manager)
+    any(const any& __other)
     {
-      if (!__other.empty())
+      if (__other.empty())
+	_M_manager = nullptr;
+      else
 	{
 	  _Arg __arg;
 	  __arg._M_any = this;
-	  _M_manager(_Op_clone, &__other, &__arg);
+	  __other._M_manager(_Op_clone, &__other, &__arg);
 	}
     }
 
     /**
      * @brief Move constructor, transfer the state from @p __other
      *
-     * @post @c __other.empty() (not guaranteed for other implementations)
+     * @post @c __other.empty() (this postcondition is a GNU extension)
      */
     any(any&& __other) noexcept
-    : _M_manager(__other._M_manager),
-      _M_storage(__other._M_storage)
-    { __other._M_manager = nullptr; }
+    {
+      if (__other.empty())
+	_M_manager = nullptr;
+      else
+	{
+	  _Arg __arg;
+	  __arg._M_any = this;
+	  __other._M_manager(_Op_xfer, &__other, &__arg);
+	}
+    }
 
     /// Construct with a copy of @p __value as the contained object.
     template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
 	      typename _Mgr = _Manager<_Tp>>
       any(_ValueType&& __value)
-      : _M_manager(&_Mgr::_S_manage),
-        _M_storage(_Mgr::_S_create(std::forward<_ValueType>(__value)))
+      : _M_manager(&_Mgr::_S_manage)
       {
+        _Mgr::_S_create(_M_storage, std::forward<_ValueType>(__value));
 	static_assert(is_copy_constructible<_Tp>::value,
 		      "The contained object must be CopyConstructible");
       }
@@ -155,10 +171,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     // assignments
 
-    /// Copy the state of 
+    /// Copy the state of another object.
     any& operator=(const any& __rhs)
     {
-      any(__rhs).swap(*this);
+      if (__rhs.empty())
+	clear();
+      else
+	{
+	  if (!empty())
+	    _M_manager(_Op_destroy, this, nullptr);
+	  _Arg __arg;
+	  __arg._M_any = this;
+	  __rhs._M_manager(_Op_clone, &__rhs, &__arg);
+	}
       return *this;
     }
 
@@ -169,7 +194,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      */
     any& operator=(any&& __rhs) noexcept
     {
-      any(std::move(__rhs)).swap(*this);
+      if (__rhs.empty())
+	clear();
+      else
+	{
+	  if (!empty())
+	    _M_manager(_Op_destroy, this, nullptr);
+	  _Arg __arg;
+	  __arg._M_any = this;
+	  __rhs._M_manager(_Op_xfer, &__rhs, &__arg);
+	}
       return *this;
     }
 
@@ -177,7 +211,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     template<typename _ValueType>
       any& operator=(_ValueType&& __rhs)
       {
-	any(std::forward<_ValueType>(__rhs)).swap(*this);
+	*this = any(std::forward<_ValueType>(__rhs));
 	return *this;
       }
 
@@ -195,10 +229,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     /// Exchange state with another object.
     void swap(any& __rhs) noexcept
-    {
-      std::swap(_M_manager, __rhs._M_manager);
-      std::swap(_M_storage, __rhs._M_storage);
-    }
+      {
+	if (empty() && __rhs.empty())
+	  return;
+
+	if (!empty() && !__rhs.empty())
+	  {
+	    any __tmp;
+	    _Arg __arg;
+	    __arg._M_any = &__tmp;
+	    __rhs._M_manager(_Op_xfer, &__rhs, &__arg);
+	    __arg._M_any = &__rhs;
+	    _M_manager(_Op_xfer, this, &__arg);
+	    __arg._M_any = this;
+	    __tmp._M_manager(_Op_xfer, &__tmp, &__arg);
+	  }
+	else
+	  {
+	    any* __empty = empty() ? this : &__rhs;
+	    any* __full = empty() ? &__rhs : this;
+	    _Arg __arg;
+	    __arg._M_any = __empty;
+	    __full->_M_manager(_Op_xfer, __full, &__arg);
+	  }
+      }
 
     // observers
 
@@ -222,7 +276,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return __or_<is_reference<_Tp>, is_copy_constructible<_Tp>>::value; }
 
   private:
-    enum _Op { _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy };
+    enum _Op {
+	_Op_access, _Op_get_type_info, _Op_clone, _Op_destroy, _Op_xfer
+    };
 
     union _Arg
     {
@@ -252,20 +308,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_S_manage(_Op __which, const any* __anyp, _Arg* __arg);
 
 	template<typename _Up>
-	  static _Storage
-	  _S_create(_Up&& __value)
+	  static void
+	  _S_create(_Storage& __storage, _Up&& __value)
 	  {
-	    _Storage __storage;
 	    void* __addr = &__storage._M_buffer;
 	    ::new (__addr) _Tp(std::forward<_Up>(__value));
-	    return __storage;
-	  }
-
-	template<typename _Alloc, typename _Up>
-	  static _Storage
-	  _S_alloc(const _Alloc&, _Up&& __value)
-	  {
-	    return _S_create(std::forward<_Up>(__value));
 	  }
       };
 
@@ -277,12 +324,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_S_manage(_Op __which, const any* __anyp, _Arg* __arg);
 
 	template<typename _Up>
-	  static _Storage
-	  _S_create(_Up&& __value)
+	  static void
+	  _S_create(_Storage& __storage, _Up&& __value)
 	  {
-	    _Storage __storage;
 	    __storage._M_ptr = new _Tp(std::forward<_Up>(__value));
-	    return __storage;
 	  }
       };
   };
@@ -393,10 +438,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	break;
       case _Op_clone:
 	::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr);
+	__arg->_M_any->_M_manager = __any->_M_manager;
 	break;
       case _Op_destroy:
 	__ptr->~_Tp();
 	break;
+      case _Op_xfer:
+	::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr);
+	__ptr->~_Tp();
+	__arg->_M_any->_M_manager = __any->_M_manager;
+	const_cast<any*>(__any)->_M_manager = nullptr;
+	break;
       }
     }
 
@@ -419,10 +471,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	break;
       case _Op_clone:
 	__arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr);
+	__arg->_M_any->_M_manager = __any->_M_manager;
 	break;
       case _Op_destroy:
 	delete __ptr;
 	break;
+      case _Op_xfer:
+	__arg->_M_any->_M_storage._M_ptr = __any->_M_storage._M_ptr;
+	__arg->_M_any->_M_manager = __any->_M_manager;
+	const_cast<any*>(__any)->_M_manager = nullptr;
+	break;
       }
     }
 
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();
+}
diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc
index f1992d9..5823175 100644
--- a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc
+++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc
@@ -26,5 +26,5 @@ void test01()
   using std::experimental::any_cast;
 
   const any y(1);
-  any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 310 }
+  any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 355 }
 }

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] Fix std::experimental::any for small, non-trivial objects
  2015-05-02 12:39 [patch] Fix std::experimental::any for small, non-trivial objects Jonathan Wakely
@ 2015-05-02 13:04 ` Jonathan Wakely
  2015-05-02 17:05   ` Daniel Krügler
  0 siblings, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2015-05-02 13:04 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 844 bytes --]

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.

[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 2998 bytes --]

commit 81330dd9616c4adec9cdc72e32f64746a3834a47
Author: Jonathan Wakely <jwakely@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();
+}

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] Fix std::experimental::any for small, non-trivial objects
  2015-05-02 13:04 ` Jonathan Wakely
@ 2015-05-02 17:05   ` Daniel Krügler
  2015-05-02 17:33     ` Jonathan Wakely
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Krügler @ 2015-05-02 17:05 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches List

2015-05-02 15:03 GMT+02:00 Jonathan Wakely <jwakely@redhat.com>:
> 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.

Not related to the patch, but is the second template argument of
any::_Storage::_M_buffer really correct:

std::aligned_storage<sizeof(_M_ptr), sizeof(_M_ptr)>::type _M_buffer;

I would have expected to see this to be an alignment value.

- Daniel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] Fix std::experimental::any for small, non-trivial objects
  2015-05-02 17:05   ` Daniel Krügler
@ 2015-05-02 17:33     ` Jonathan Wakely
  2015-05-02 17:51       ` Daniel Krügler
  0 siblings, 1 reply; 6+ messages in thread
From: Jonathan Wakely @ 2015-05-02 17:33 UTC (permalink / raw)
  To: Daniel Krügler; +Cc: libstdc++, gcc-patches List

On 02/05/15 19:05 +0200, Daniel Krügler wrote:
>Not related to the patch, but is the second template argument of
>any::_Storage::_M_buffer really correct:
>
>std::aligned_storage<sizeof(_M_ptr), sizeof(_M_ptr)>::type _M_buffer;
>
>I would have expected to see this to be an alignment value.

Yes, that looks like a typo.

We could remove that second argument completely, although that might
increase the alignment requirements on any (probably not in practice).

Looking at it now, I think the _Internal alias template should also
check that alignof(_Tp) <= alignof(void*) so that it can safely be
stored in the _Storage.


Otherwise a type with sizeof(T) <= sizeof(void*) but
alignof(T) > alignof(void*) would not be correctly aligned when stored
in the buffer.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] Fix std::experimental::any for small, non-trivial objects
  2015-05-02 17:33     ` Jonathan Wakely
@ 2015-05-02 17:51       ` Daniel Krügler
  2015-05-02 18:20         ` Jonathan Wakely
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Krügler @ 2015-05-02 17:51 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches List

2015-05-02 19:33 GMT+02:00 Jonathan Wakely <jwakely@redhat.com>:
> Looking at it now, I think the _Internal alias template should also
> check that alignof(_Tp) <= alignof(void*) so that it can safely be
> stored in the _Storage.
>
> Otherwise a type with sizeof(T) <= sizeof(void*) but
> alignof(T) > alignof(void*) would not be correctly aligned when stored
> in the buffer.

Yes, I agree.

- Daniel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [patch] Fix std::experimental::any for small, non-trivial objects
  2015-05-02 17:51       ` Daniel Krügler
@ 2015-05-02 18:20         ` Jonathan Wakely
  0 siblings, 0 replies; 6+ messages in thread
From: Jonathan Wakely @ 2015-05-02 18:20 UTC (permalink / raw)
  To: Daniel Krügler; +Cc: libstdc++, gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 593 bytes --]

On 02/05/15 19:51 +0200, Daniel Krügler wrote:
>2015-05-02 19:33 GMT+02:00 Jonathan Wakely <jwakely@redhat.com>:
>> Looking at it now, I think the _Internal alias template should also
>> check that alignof(_Tp) <= alignof(void*) so that it can safely be
>> stored in the _Storage.
>>
>> Otherwise a type with sizeof(T) <= sizeof(void*) but
>> alignof(T) > alignof(void*) would not be correctly aligned when stored
>> in the buffer.
>
>Yes, I agree.

Fixed like so, tested powerpc64le-linux and powerpc-aix, committed to
trunk. I'll do something similar on the gcc5 branch too, but not
today.

[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 3645 bytes --]

commit a29ec813a90122d1c23eb74af379ce6e0c416c8e
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Sat May 2 19:05:51 2015 +0100

    	* include/experimental/any (any::_Storage): Fix alignment of buffer.
    	(any::_Internal): Check alignment of type.
    	* testsuite/experimental/any/cons/aligned.cc: New.
    	* testsuite/experimental/any/misc/any_cast_neg.cc: Adjust dg-error.

diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any
index b2d1b9c..7b5e5ec 100644
--- a/libstdc++-v3/include/experimental/any
+++ b/libstdc++-v3/include/experimental/any
@@ -98,11 +98,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Storage& operator=(const _Storage&) = delete;
 
       void* _M_ptr;
-      std::aligned_storage<sizeof(_M_ptr), sizeof(_M_ptr)>::type _M_buffer;
+      aligned_storage<sizeof(_M_ptr), alignof(void*)>::type _M_buffer;
     };
 
     template<typename _Tp, typename _Safe = is_nothrow_move_constructible<_Tp>,
-	     bool _Fits = (sizeof(_Tp) <= sizeof(_Storage))>
+	     bool _Fits = (sizeof(_Tp) <= sizeof(_Storage))
+			  && (alignof(_Tp) <= alignof(_Storage))>
       using _Internal = std::integral_constant<bool, _Safe::value && _Fits>;
 
     template<typename _Tp>
diff --git a/libstdc++-v3/testsuite/experimental/any/cons/aligned.cc b/libstdc++-v3/testsuite/experimental/any/cons/aligned.cc
new file mode 100644
index 0000000..3923994
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/any/cons/aligned.cc
@@ -0,0 +1,52 @@
+// 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 <cstdint>
+#include <testsuite_hooks.h>
+
+// Alignment requiremnts of this type prevent it being stored in 'any'
+struct alignas(2 * alignof(void*)) X { };
+
+bool
+stored_internally(void* obj, const std::experimental::any& a)
+{
+  std::uintptr_t a_addr = reinterpret_cast<std::uintptr_t>(&a);
+  std::uintptr_t a_end = a_addr + sizeof(a);
+  std::uintptr_t obj_addr = reinterpret_cast<std::uintptr_t>(obj);
+  return (a_addr <= obj_addr) && (obj_addr < a_end);
+}
+
+void
+test01()
+{
+  std::experimental::any a = X{};
+  X& x = std::experimental::any_cast<X&>(a);
+  VERIFY( !stored_internally(&x, a) );
+
+  a = 'X';
+  char& c = std::experimental::any_cast<char&>(a);
+  VERIFY( stored_internally(&c, a) );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc
index 5823175..39e3226 100644
--- a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc
+++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc
@@ -26,5 +26,5 @@ void test01()
   using std::experimental::any_cast;
 
   const any y(1);
-  any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 355 }
+  any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 356 }
 }

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-05-02 18:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-02 12:39 [patch] Fix std::experimental::any for small, non-trivial objects Jonathan Wakely
2015-05-02 13:04 ` Jonathan Wakely
2015-05-02 17:05   ` Daniel Krügler
2015-05-02 17:33     ` Jonathan Wakely
2015-05-02 17:51       ` Daniel Krügler
2015-05-02 18:20         ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).