From b9231a2326136a4d4955afb93a917099abb9c94e Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Wed, 7 Sep 2016 01:56:07 +0000 Subject: [PATCH] Fix PR30260 - optional not working. This patch fixes PR30260 by using a (void*) cast on the placement argument to placement new to casts away the const. See also http://llvm.org/PR30260. As a drive by change this patch also changes the header guard for to _LIBCPP_EXPERIMENTAL_OPTIONAL from _LIBCPP_OPTIONAL. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@280775 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/experimental/optional | 33 +++++++++++-------- .../assign_value.pass.cpp | 13 ++++++++ .../optional.object.assign/copy.pass.cpp | 12 +++++++ .../optional.object.assign/emplace.pass.cpp | 6 ++++ .../emplace_initializer_list.pass.cpp | 11 +++++++ .../optional.object.assign/move.pass.cpp | 12 +++++++ .../optional.object.ctor/copy.pass.cpp | 10 ++++++ .../optional.object.ctor/move.pass.cpp | 21 ++++++++++++ .../optional.object.swap/swap.pass.cpp | 9 +++++ 9 files changed, 113 insertions(+), 14 deletions(-) diff --git a/include/experimental/optional b/include/experimental/optional index 11bf8678d..966c889e9 100644 --- a/include/experimental/optional +++ b/include/experimental/optional @@ -8,8 +8,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP_OPTIONAL -#define _LIBCPP_OPTIONAL +#ifndef _LIBCPP_EXPERIMENTAL_OPTIONAL +#define _LIBCPP_EXPERIMENTAL_OPTIONAL /* optional synopsis @@ -211,7 +211,7 @@ protected: : __engaged_(__x.__engaged_) { if (__engaged_) - ::new(_VSTD::addressof(__val_)) value_type(__x.__val_); + ::new((void*)_VSTD::addressof(__val_)) value_type(__x.__val_); } _LIBCPP_INLINE_VISIBILITY @@ -220,7 +220,7 @@ protected: : __engaged_(__x.__engaged_) { if (__engaged_) - ::new(_VSTD::addressof(__val_)) value_type(_VSTD::move(__x.__val_)); + ::new((void*)_VSTD::addressof(__val_)) value_type(_VSTD::move(__x.__val_)); } _LIBCPP_INLINE_VISIBILITY @@ -262,7 +262,7 @@ protected: : __engaged_(__x.__engaged_) { if (__engaged_) - ::new(_VSTD::addressof(__val_)) value_type(__x.__val_); + ::new((void*)_VSTD::addressof(__val_)) value_type(__x.__val_); } _LIBCPP_INLINE_VISIBILITY @@ -271,7 +271,7 @@ protected: : __engaged_(__x.__engaged_) { if (__engaged_) - ::new(_VSTD::addressof(__val_)) value_type(_VSTD::move(__x.__val_)); + ::new((void*)_VSTD::addressof(__val_)) value_type(_VSTD::move(__x.__val_)); } _LIBCPP_INLINE_VISIBILITY @@ -368,7 +368,7 @@ public: if (this->__engaged_) this->__val_.~value_type(); else - ::new(_VSTD::addressof(this->__val_)) value_type(__opt.__val_); + ::new((void*)_VSTD::addressof(this->__val_)) value_type(__opt.__val_); this->__engaged_ = __opt.__engaged_; } return *this; @@ -390,7 +390,8 @@ public: if (this->__engaged_) this->__val_.~value_type(); else - ::new(_VSTD::addressof(this->__val_)) value_type(_VSTD::move(__opt.__val_)); + ::new((void*)_VSTD::addressof(this->__val_)) + value_type(_VSTD::move(__opt.__val_)); this->__engaged_ = __opt.__engaged_; } return *this; @@ -412,7 +413,7 @@ public: this->__val_ = _VSTD::forward<_Up>(__v); else { - ::new(_VSTD::addressof(this->__val_)) value_type(_VSTD::forward<_Up>(__v)); + ::new((void*)_VSTD::addressof(this->__val_)) value_type(_VSTD::forward<_Up>(__v)); this->__engaged_ = true; } return *this; @@ -429,7 +430,8 @@ public: emplace(_Args&&... __args) { *this = nullopt; - ::new(_VSTD::addressof(this->__val_)) value_type(_VSTD::forward<_Args>(__args)...); + ::new((void*)_VSTD::addressof(this->__val_)) + value_type(_VSTD::forward<_Args>(__args)...); this->__engaged_ = true; } @@ -444,7 +446,8 @@ public: emplace(initializer_list<_Up> __il, _Args&&... __args) { *this = nullopt; - ::new(_VSTD::addressof(this->__val_)) value_type(__il, _VSTD::forward<_Args>(__args)...); + ::new((void*)_VSTD::addressof(this->__val_)) + value_type(__il, _VSTD::forward<_Args>(__args)...); this->__engaged_ = true; } @@ -464,12 +467,14 @@ public: { if (this->__engaged_) { - ::new(_VSTD::addressof(__opt.__val_)) value_type(_VSTD::move(this->__val_)); + ::new((void*)_VSTD::addressof(__opt.__val_)) + value_type(_VSTD::move(this->__val_)); this->__val_.~value_type(); } else { - ::new(_VSTD::addressof(this->__val_)) value_type(_VSTD::move(__opt.__val_)); + ::new((void*)_VSTD::addressof(this->__val_)) + value_type(_VSTD::move(__opt.__val_)); __opt.__val_.~value_type(); } swap(this->__engaged_, __opt.__engaged_); @@ -901,4 +906,4 @@ _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_STD_VER > 11 -#endif // _LIBCPP_OPTIONAL +#endif // _LIBCPP_EXPERIMENTAL_OPTIONAL diff --git a/test/std/experimental/optional/optional.object/optional.object.assign/assign_value.pass.cpp b/test/std/experimental/optional/optional.object/optional.object.assign/assign_value.pass.cpp index 3d0d2e031..27aafe0df 100644 --- a/test/std/experimental/optional/optional.object/optional.object.assign/assign_value.pass.cpp +++ b/test/std/experimental/optional/optional.object/optional.object.assign/assign_value.pass.cpp @@ -19,6 +19,14 @@ using std::experimental::optional; +struct AllowConstAssign { + AllowConstAssign() = default; + AllowConstAssign(AllowConstAssign const&) {} + AllowConstAssign const& operator=(AllowConstAssign const&) const { + return *this; + } +}; + struct X { }; @@ -52,6 +60,11 @@ int main() assert(static_cast(opt) == true); assert(*opt == i); } + { + optional opt; + const AllowConstAssign other; + opt = other; + } { optional> opt; opt = std::unique_ptr(new int(3)); diff --git a/test/std/experimental/optional/optional.object/optional.object.assign/copy.pass.cpp b/test/std/experimental/optional/optional.object/optional.object.assign/copy.pass.cpp index 89ea34502..ff37b22c7 100644 --- a/test/std/experimental/optional/optional.object/optional.object.assign/copy.pass.cpp +++ b/test/std/experimental/optional/optional.object/optional.object.assign/copy.pass.cpp @@ -19,6 +19,13 @@ using std::experimental::optional; +struct AllowConstAssign { + AllowConstAssign(AllowConstAssign const&) {} + AllowConstAssign const& operator=(AllowConstAssign const&) const { + return *this; + } +}; + struct X { static bool throw_now; @@ -42,6 +49,11 @@ int main() static_assert(static_cast(opt2) == false, ""); assert(static_cast(opt) == static_cast(opt2)); } + { + optional opt; + optional opt2; + opt = opt2; + } { optional opt; constexpr optional opt2(2); diff --git a/test/std/experimental/optional/optional.object/optional.object.assign/emplace.pass.cpp b/test/std/experimental/optional/optional.object/optional.object.assign/emplace.pass.cpp index 94f2bb21a..6a7b56e58 100644 --- a/test/std/experimental/optional/optional.object/optional.object.assign/emplace.pass.cpp +++ b/test/std/experimental/optional/optional.object/optional.object.assign/emplace.pass.cpp @@ -80,6 +80,12 @@ int main() assert(static_cast(opt) == true); assert(*opt == 1); } + { + optional opt(2); + opt.emplace(1); + assert(static_cast(opt) == true); + assert(*opt == 1); + } { optional opt; opt.emplace(); diff --git a/test/std/experimental/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp b/test/std/experimental/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp index fec37408e..b02616ef9 100644 --- a/test/std/experimental/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp +++ b/test/std/experimental/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp @@ -81,6 +81,17 @@ int main() assert(*opt == X({1, 2})); } } + X::dtor_called = false; + { + X x; + { + optional opt(x); + assert(X::dtor_called == false); + opt.emplace({1, 2}); + assert(X::dtor_called == true); + assert(*opt == X({1, 2})); + } + } { optional> opt; opt.emplace({1, 2, 3}, std::allocator()); diff --git a/test/std/experimental/optional/optional.object/optional.object.assign/move.pass.cpp b/test/std/experimental/optional/optional.object/optional.object.assign/move.pass.cpp index fa00f5602..1c3b78067 100644 --- a/test/std/experimental/optional/optional.object/optional.object.assign/move.pass.cpp +++ b/test/std/experimental/optional/optional.object/optional.object.assign/move.pass.cpp @@ -21,6 +21,13 @@ using std::experimental::optional; +struct AllowConstAssign { + AllowConstAssign(AllowConstAssign const&) {} + AllowConstAssign const& operator=(AllowConstAssign const&) const { + return *this; + } +}; + struct X { static bool throw_now; @@ -76,6 +83,11 @@ int main() assert(static_cast(opt) == static_cast(opt2)); assert(*opt == *opt2); } + { + optional opt; + optional opt2; + opt = std::move(opt2); + } { static_assert(!std::is_nothrow_move_assignable>::value, ""); optional opt; diff --git a/test/std/experimental/optional/optional.object/optional.object.ctor/copy.pass.cpp b/test/std/experimental/optional/optional.object/optional.object.ctor/copy.pass.cpp index 144af2e3a..c7c687caf 100644 --- a/test/std/experimental/optional/optional.object/optional.object.ctor/copy.pass.cpp +++ b/test/std/experimental/optional/optional.object/optional.object.ctor/copy.pass.cpp @@ -87,6 +87,11 @@ int main() optional rhs(3); test(rhs); } + { + typedef const int T; + optional rhs(3); + test(rhs); + } { typedef X T; optional rhs; @@ -97,6 +102,11 @@ int main() optional rhs(X(3)); test(rhs); } + { + typedef const X T; + optional rhs(X(3)); + test(rhs); + } { typedef Y T; optional rhs; diff --git a/test/std/experimental/optional/optional.object/optional.object.ctor/move.pass.cpp b/test/std/experimental/optional/optional.object/optional.object.ctor/move.pass.cpp index 851157f96..4ed0c92e0 100644 --- a/test/std/experimental/optional/optional.object/optional.object.ctor/move.pass.cpp +++ b/test/std/experimental/optional/optional.object/optional.object.ctor/move.pass.cpp @@ -74,6 +74,17 @@ public: friend constexpr bool operator==(const Z& x, const Z& y) {return x.i_ == y.i_;} }; + +class ConstMovable +{ + int i_; +public: + ConstMovable(int i) : i_(i) {} + ConstMovable(const ConstMovable&& x) : i_(x.i_) {} + ~ConstMovable() {i_ = 0;} + friend bool operator==(const ConstMovable& x, const ConstMovable& y) {return x.i_ == y.i_;} +}; + int main() { { @@ -86,6 +97,11 @@ int main() optional rhs(3); test(rhs); } + { + typedef const int T; + optional rhs(3); + test(rhs); + } { typedef X T; optional rhs; @@ -96,6 +112,11 @@ int main() optional rhs(X(3)); test(rhs); } + { + typedef const ConstMovable T; + optional rhs(ConstMovable(3)); + test(rhs); + } { typedef Y T; optional rhs; diff --git a/test/std/experimental/optional/optional.object/optional.object.swap/swap.pass.cpp b/test/std/experimental/optional/optional.object/optional.object.swap/swap.pass.cpp index 620dda19e..be0d1efb6 100644 --- a/test/std/experimental/optional/optional.object/optional.object.swap/swap.pass.cpp +++ b/test/std/experimental/optional/optional.object/optional.object.swap/swap.pass.cpp @@ -62,6 +62,10 @@ public: friend void swap(Z& x, Z& y) {throw 6;} }; +struct ConstSwappable { +}; +void swap(ConstSwappable const&, ConstSwappable const&) {} + int main() { { @@ -112,6 +116,11 @@ int main() assert(static_cast(opt2) == true); assert(*opt2 == 1); } + { + optional opt; + optional opt2; + opt.swap(opt2); + } { optional opt1; optional opt2;