Skip to content

Commit 8749857

Browse files
committed
Assignment shouldn't modify the underlying value, test for that and also enable some disabled tests
1 parent da09bb1 commit 8749857

File tree

3 files changed

+94
-63
lines changed

3 files changed

+94
-63
lines changed

libcxx/include/optional

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,11 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> {
416416
__construct(std::forward<_That>(__opt).__get());
417417
}
418418
}
419+
420+
template <class _Up>
421+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from_val(_Up&& __val){
422+
this->__get() = std::forward<_Up>(__val);
423+
}
419424
};
420425

421426
template <class _Tp>
@@ -469,6 +474,11 @@ struct __optional_storage_base<_Tp, true> {
469474
__construct(std::forward<_That>(__opt).__get());
470475
}
471476
}
477+
478+
template <class _Up>
479+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from_val(_Up&& __val){
480+
__value_ = std::addressof(__val);
481+
}
472482
};
473483

474484
template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value>
@@ -864,7 +874,7 @@ public:
864874
int> = 0>
865875
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(_Up&& __v) {
866876
if (this->has_value())
867-
this->__get() = std::forward<_Up>(__v);
877+
this->__assign_from_val(std::forward<_Up>(__v));
868878
else
869879
this->__construct(std::forward<_Up>(__v));
870880
return *this;

libcxx/test/std/utilities/optional/optional.object/optional.object.assign/assign_value.pass.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,27 @@ constexpr void test_with_ref() {
278278
opt = {};
279279
assert(static_cast<bool>(opt) == false);
280280
}
281+
// test two objects, make sure that the optional only changes what it holds a reference to
282+
{
283+
T t2{_Val};
284+
optional<T&> opt{t};
285+
opt = t2;
286+
287+
assert(std::addressof(*opt) != std::addressof(t));
288+
assert(std::addressof(*opt) == std::addressof(t2));
289+
}
290+
// test that reassigning the reference for an optional<T&> doesn't affect the objet it's holding a reference to
291+
{
292+
int i = -1;
293+
int j = 2;
294+
optional<int&> opt{i};
295+
opt = j;
296+
297+
assert(i == -1);
298+
assert(std::addressof(*opt) != std::addressof(i));
299+
assert(std::addressof(*opt) == std::addressof(j));
300+
assert(*opt == 2);
301+
}
281302
}
282303
#endif
283304

libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp

Lines changed: 62 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -78,71 +78,71 @@ void test_ref(InitArgs&&... args)
7878
assert(&(*lhs) == &(*rhs));
7979
}
8080

81-
void test_reference_extension()
82-
{
83-
#if defined(_LIBCPP_VERSION) && 0 // FIXME these extensions are currently disabled.
84-
using T = TestTypes::TestType;
85-
T::reset();
86-
{
87-
T t;
88-
T::reset_constructors();
89-
test_ref<T&>();
90-
test_ref<T&>(t);
91-
assert(T::alive == 1);
92-
assert(T::constructed == 0);
93-
assert(T::assigned == 0);
94-
assert(T::destroyed == 0);
95-
}
96-
assert(T::destroyed == 1);
97-
assert(T::alive == 0);
98-
{
99-
T t;
100-
const T& ct = t;
101-
T::reset_constructors();
102-
test_ref<T const&>();
103-
test_ref<T const&>(t);
104-
test_ref<T const&>(ct);
105-
assert(T::alive == 1);
106-
assert(T::constructed == 0);
107-
assert(T::assigned == 0);
108-
assert(T::destroyed == 0);
109-
}
110-
assert(T::alive == 0);
111-
assert(T::destroyed == 1);
112-
{
113-
T t;
114-
T::reset_constructors();
115-
test_ref<T&&>();
116-
test_ref<T&&>(std::move(t));
117-
assert(T::alive == 1);
118-
assert(T::constructed == 0);
119-
assert(T::assigned == 0);
120-
assert(T::destroyed == 0);
121-
}
122-
assert(T::alive == 0);
123-
assert(T::destroyed == 1);
124-
{
125-
T t;
126-
const T& ct = t;
127-
T::reset_constructors();
128-
test_ref<T const&&>();
129-
test_ref<T const&&>(std::move(t));
130-
test_ref<T const&&>(std::move(ct));
131-
assert(T::alive == 1);
132-
assert(T::constructed == 0);
133-
assert(T::assigned == 0);
134-
assert(T::destroyed == 0);
135-
}
136-
assert(T::alive == 0);
137-
assert(T::destroyed == 1);
138-
{
139-
static_assert(!std::is_copy_constructible<std::optional<T&&>>::value, "");
140-
static_assert(!std::is_copy_constructible<std::optional<T const&&>>::value, "");
141-
}
81+
void test_reference_extension() {
82+
#if TEST_STD_VER >= 26
83+
using T = TestTypes::TestType;
84+
T::reset();
85+
{
86+
T t;
87+
T::reset_constructors();
88+
test_ref<T&>();
89+
test_ref<T&>(t);
90+
assert(T::alive == 1);
91+
assert(T::constructed == 0);
92+
assert(T::assigned == 0);
93+
assert(T::destroyed == 0);
94+
}
95+
assert(T::destroyed == 1);
96+
assert(T::alive == 0);
97+
{
98+
T t;
99+
const T& ct = t;
100+
T::reset_constructors();
101+
test_ref<T const&>();
102+
test_ref<T const&>(t);
103+
test_ref<T const&>(ct);
104+
assert(T::alive == 1);
105+
assert(T::constructed == 0);
106+
assert(T::assigned == 0);
107+
assert(T::destroyed == 0);
108+
}
109+
assert(T::alive == 0);
110+
assert(T::destroyed == 1);
111+
# if 0 // FIXME: optional<T&&> is not allowed.
112+
{
113+
T t;
114+
T::reset_constructors();
115+
test_ref<T&&>();
116+
test_ref<T&&>(std::move(t));
117+
assert(T::alive == 1);
118+
assert(T::constructed == 0);
119+
assert(T::assigned == 0);
120+
assert(T::destroyed == 0);
121+
}
122+
assert(T::alive == 0);
123+
assert(T::destroyed == 1);
124+
{
125+
T t;
126+
const T& ct = t;
127+
T::reset_constructors();
128+
test_ref<T const&&>();
129+
test_ref<T const&&>(std::move(t));
130+
test_ref<T const&&>(std::move(ct));
131+
assert(T::alive == 1);
132+
assert(T::constructed == 0);
133+
assert(T::assigned == 0);
134+
assert(T::destroyed == 0);
135+
}
136+
assert(T::alive == 0);
137+
assert(T::destroyed == 1);
138+
{
139+
static_assert(!std::is_copy_constructible<std::optional<T&&>>::value, "");
140+
static_assert(!std::is_copy_constructible<std::optional<T const&&>>::value, "");
141+
}
142+
# endif
142143
#endif
143144
}
144145

145-
146146
int main(int, char**)
147147
{
148148
test<int>();

0 commit comments

Comments
 (0)