diff options
author | Eric Fiselier <eric@efcs.ca> | 2016-09-07 01:56:07 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2016-09-07 01:56:07 +0000 |
commit | ef853e978058cc57d2b5f0bcf0ee0e3a34528655 (patch) | |
tree | 909b312817f1a5263ad427ff44253129d75c8223 /libcxx | |
parent | 23e51e4905aa0da19174a9973a95adce6809a7c6 (diff) |
Fix PR30260 - optional<const T> 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
<experimental/optional> to _LIBCPP_EXPERIMENTAL_OPTIONAL from _LIBCPP_OPTIONAL.
Diffstat (limited to 'libcxx')
9 files changed, 113 insertions, 14 deletions
diff --git a/libcxx/include/experimental/optional b/libcxx/include/experimental/optional index 11bf8678da0..966c889e99d 100644 --- a/libcxx/include/experimental/optional +++ b/libcxx/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/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/assign_value.pass.cpp b/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/assign_value.pass.cpp index 3d0d2e03158..27aafe0df6b 100644 --- a/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/assign_value.pass.cpp +++ b/libcxx/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 { }; @@ -53,6 +61,11 @@ int main() assert(*opt == i); } { + optional<const AllowConstAssign> opt; + const AllowConstAssign other; + opt = other; + } + { optional<std::unique_ptr<int>> opt; opt = std::unique_ptr<int>(new int(3)); assert(static_cast<bool>(opt) == true); diff --git a/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/copy.pass.cpp b/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/copy.pass.cpp index 89ea345029c..ff37b22c7d2 100644 --- a/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/copy.pass.cpp +++ b/libcxx/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; @@ -43,6 +50,11 @@ int main() assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); } { + optional<const AllowConstAssign> opt; + optional<const AllowConstAssign> opt2; + opt = opt2; + } + { optional<int> opt; constexpr optional<int> opt2(2); opt = opt2; diff --git a/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/emplace.pass.cpp b/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/emplace.pass.cpp index 94f2bb21a47..6a7b56e588d 100644 --- a/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/emplace.pass.cpp +++ b/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/emplace.pass.cpp @@ -81,6 +81,12 @@ int main() assert(*opt == 1); } { + optional<const int> opt(2); + opt.emplace(1); + assert(static_cast<bool>(opt) == true); + assert(*opt == 1); + } + { optional<X> opt; opt.emplace(); assert(static_cast<bool>(opt) == true); diff --git a/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp b/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp index fec37408e43..b02616ef995 100644 --- a/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp +++ b/libcxx/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<const X> opt(x); + assert(X::dtor_called == false); + opt.emplace({1, 2}); + assert(X::dtor_called == true); + assert(*opt == X({1, 2})); + } + } { optional<std::vector<int>> opt; opt.emplace({1, 2, 3}, std::allocator<int>()); diff --git a/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/move.pass.cpp b/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/move.pass.cpp index fa00f5602c7..1c3b780677e 100644 --- a/libcxx/test/std/experimental/optional/optional.object/optional.object.assign/move.pass.cpp +++ b/libcxx/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; @@ -77,6 +84,11 @@ int main() assert(*opt == *opt2); } { + optional<const AllowConstAssign> opt; + optional<const AllowConstAssign> opt2; + opt = std::move(opt2); + } + { static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, ""); optional<X> opt; optional<X> opt2(X{}); diff --git a/libcxx/test/std/experimental/optional/optional.object/optional.object.ctor/copy.pass.cpp b/libcxx/test/std/experimental/optional/optional.object/optional.object.ctor/copy.pass.cpp index 144af2e3a7d..c7c687caf53 100644 --- a/libcxx/test/std/experimental/optional/optional.object/optional.object.ctor/copy.pass.cpp +++ b/libcxx/test/std/experimental/optional/optional.object/optional.object.ctor/copy.pass.cpp @@ -88,6 +88,11 @@ int main() test(rhs); } { + typedef const int T; + optional<T> rhs(3); + test(rhs); + } + { typedef X T; optional<T> rhs; test(rhs); @@ -98,6 +103,11 @@ int main() test(rhs); } { + typedef const X T; + optional<T> rhs(X(3)); + test(rhs); + } + { typedef Y T; optional<T> rhs; test(rhs); diff --git a/libcxx/test/std/experimental/optional/optional.object/optional.object.ctor/move.pass.cpp b/libcxx/test/std/experimental/optional/optional.object/optional.object.ctor/move.pass.cpp index 851157f960f..4ed0c92e026 100644 --- a/libcxx/test/std/experimental/optional/optional.object/optional.object.ctor/move.pass.cpp +++ b/libcxx/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() { { @@ -87,6 +98,11 @@ int main() test(rhs); } { + typedef const int T; + optional<T> rhs(3); + test(rhs); + } + { typedef X T; optional<T> rhs; test(rhs); @@ -97,6 +113,11 @@ int main() test(rhs); } { + typedef const ConstMovable T; + optional<T> rhs(ConstMovable(3)); + test(rhs); + } + { typedef Y T; optional<T> rhs; test(rhs); diff --git a/libcxx/test/std/experimental/optional/optional.object/optional.object.swap/swap.pass.cpp b/libcxx/test/std/experimental/optional/optional.object/optional.object.swap/swap.pass.cpp index 620dda19e3f..be0d1efb60d 100644 --- a/libcxx/test/std/experimental/optional/optional.object/optional.object.swap/swap.pass.cpp +++ b/libcxx/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() { { @@ -113,6 +117,11 @@ int main() assert(*opt2 == 1); } { + optional<const ConstSwappable> opt; + optional<const ConstSwappable> opt2; + opt.swap(opt2); + } + { optional<X> opt1; optional<X> opt2; static_assert(noexcept(opt1.swap(opt2)) == true, ""); |