Skip to content

Commit 8db85ce

Browse files
authored
Merge pull request #103 from steve-downey/refsteal-paper
R9 of paper which fixes the reference stealing bug
2 parents b383b1a + d481100 commit 8db85ce

File tree

5 files changed

+793
-63
lines changed

5 files changed

+793
-63
lines changed

include/beman/optional26/optional.hpp

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,16 @@ concept enable_forward_value = !std::is_same_v<std::decay_t<U>, optional<T>> &&
201201
!std::is_same_v<std::decay_t<U>, in_place_t> && std::is_constructible_v<T, U&&>;
202202

203203
template <class T, class U, class Other>
204-
concept enable_from_other =
205-
!std::is_same_v<T, U> && std::is_constructible_v<T, Other> && !std::is_constructible_v<T, optional<U>&> &&
206-
!std::is_constructible_v<T, optional<U>&&> && !std::is_constructible_v<T, const optional<U>&> &&
207-
!std::is_constructible_v<T, const optional<U>&&> && !std::is_convertible_v<optional<U>&, T> &&
208-
!std::is_convertible_v<optional<U>&&, T> && !std::is_convertible_v<const optional<U>&, T> &&
209-
!std::is_convertible_v<const optional<U>&&, T>;
204+
concept enable_from_other = !std::is_same_v<T, U> && //
205+
std::is_constructible_v<T, Other> && //
206+
!std::is_constructible_v<T, optional<U>&> && //
207+
!std::is_constructible_v<T, optional<U>&&> && //
208+
!std::is_constructible_v<T, const optional<U>&> && //
209+
!std::is_constructible_v<T, const optional<U>&&> && //
210+
!std::is_convertible_v<optional<U>&, T> && //
211+
!std::is_convertible_v<optional<U>&&, T> && //
212+
!std::is_convertible_v<const optional<U>&, T> && //
213+
!std::is_convertible_v<const optional<U>&&, T>;
210214

211215
template <class T, class U>
212216
concept enable_assign_forward = !std::is_same_v<optional<T>, std::decay_t<U>> &&
@@ -279,12 +283,12 @@ class optional {
279283
requires(!std::is_reference_v<U> && detail::enable_from_other<T, U, const U&>);
280284

281285
template <class U>
282-
constexpr explicit(!std::is_convertible_v<U, T>) optional(optional<U>&& rhs)
283-
requires(!std::is_reference_v<U> && detail::enable_from_other<T, U, U &&>);
286+
constexpr explicit(!std::is_convertible_v<U, T>) optional(const optional<U>& rhs)
287+
requires(std::is_reference_v<U> && detail::enable_from_other<T, U, U>);
284288

285289
template <class U>
286-
constexpr explicit(!std::is_convertible_v<U&, T>) optional(const optional<U&>& rhs)
287-
requires(detail::enable_from_other<T, U&, U&>);
290+
constexpr explicit(!std::is_convertible_v<U, T>) optional(optional<U>&& rhs)
291+
requires(!std::is_reference_v<U> && detail::enable_from_other<T, U, U &&>);
288292

289293
// \ref{optional.dtor}, destructor
290294
constexpr ~optional()
@@ -324,12 +328,12 @@ class optional {
324328
requires(!std::is_reference_v<U> && detail::enable_assign_from_other<T, U, const U&>);
325329

326330
template <class U>
327-
constexpr optional& operator=(optional<U>&& rhs)
328-
requires(!std::is_reference_v<U> && detail::enable_assign_from_other<T, U, U>);
331+
constexpr optional& operator=(const optional<U>& rhs)
332+
requires(std::is_reference_v<U> && detail::enable_assign_from_other<T, U, U>);
329333

330334
template <class U>
331-
constexpr optional& operator=(const optional<U&>& rhs)
332-
requires(detail::enable_assign_from_other<T, U&, U&>);
335+
constexpr optional& operator=(optional<U>&& rhs)
336+
requires(!std::is_reference_v<U> && detail::enable_assign_from_other<T, U, U>);
333337

334338
template <class... Args>
335339
constexpr T& emplace(Args&&... args);
@@ -358,9 +362,9 @@ class optional {
358362
constexpr T& value() &;
359363
constexpr const T& value() const&;
360364
constexpr T&& value() &&;
361-
template <class U>
365+
template <class U = std::remove_cv_t<T>>
362366
constexpr T value_or(U&& u) const&;
363-
template <class U>
367+
template <class U = std::remove_cv_t<T>>
364368
constexpr T value_or(U&& u) &&;
365369

366370
// \ref{optional.monadic}, monadic operations
@@ -456,7 +460,7 @@ inline constexpr optional<T>::optional(in_place_t, std::initializer_list<U> il,
456460
template <class T>
457461
template <class U>
458462
inline constexpr optional<T>::optional(U&& u)
459-
requires detail::enable_forward_value<T, U> //&& std::is_convertible_v<U&&, T>
463+
requires detail::enable_forward_value<T, U>
460464
: optional(in_place, std::forward<U>(u)) {}
461465

462466
/// Converting copy constructor.
@@ -470,24 +474,25 @@ inline constexpr optional<T>::optional(const optional<U>& rhs)
470474
}
471475
}
472476

473-
/// Converting move constructor.
477+
/// Converting copy constructor for U&
474478
template <class T>
475479
template <class U>
476-
inline constexpr optional<T>::optional(optional<U>&& rhs)
477-
requires(!std::is_reference_v<U> && detail::enable_from_other<T, U, U &&>)
480+
inline constexpr optional<T>::optional(const optional<U>& rhs)
481+
requires(std::is_reference_v<U> && detail::enable_from_other<T, U, U>)
478482
{
479483
if (rhs.has_value()) {
480-
construct(std::move(*rhs));
484+
construct(*rhs);
481485
}
482486
}
483487

488+
/// Converting move constructor.
484489
template <class T>
485490
template <class U>
486-
inline constexpr optional<T>::optional(const optional<U&>& rhs)
487-
requires(detail::enable_from_other<T, U&, U&>)
491+
inline constexpr optional<T>::optional(optional<U>&& rhs)
492+
requires(!std::is_reference_v<U> && detail::enable_from_other<T, U, U &&>)
488493
{
489494
if (rhs.has_value()) {
490-
construct(*rhs);
495+
construct(std::move(*rhs));
491496
}
492497
}
493498

@@ -578,45 +583,45 @@ inline constexpr optional<T>& optional<T>::operator=(const optional<U>& rhs)
578583
return *this;
579584
}
580585

581-
/// Converting move assignment operator.
582-
///
583-
/// Moves the value from `rhs` if there is one. Otherwise resets the stored
584-
/// value in `*this`.
585586
template <class T>
586587
template <class U>
587-
inline constexpr optional<T>& optional<T>::operator=(optional<U>&& rhs)
588-
requires(!std::is_reference_v<U> && detail::enable_assign_from_other<T, U, U>)
588+
inline constexpr optional<T>& optional<T>::operator=(const optional<U>& rhs)
589+
requires(std::is_reference_v<U> && detail::enable_assign_from_other<T, U, U>)
589590
{
590591
if (has_value()) {
591592
if (rhs.has_value()) {
592-
value_ = std::move(*rhs);
593+
value_ = *rhs;
593594
} else {
594595
hard_reset();
595596
}
596597
}
597598

598599
else if (rhs.has_value()) {
599-
construct(std::move(*rhs));
600+
construct(*rhs);
600601
}
601602

602603
return *this;
603604
}
604605

606+
/// Converting move assignment operator.
607+
///
608+
/// Moves the value from `rhs` if there is one. Otherwise resets the stored
609+
/// value in `*this`.
605610
template <class T>
606611
template <class U>
607-
inline constexpr optional<T>& optional<T>::operator=(const optional<U&>& rhs)
608-
requires(detail::enable_assign_from_other<T, U&, U&>)
612+
inline constexpr optional<T>& optional<T>::operator=(optional<U>&& rhs)
613+
requires(!std::is_reference_v<U> && detail::enable_assign_from_other<T, U, U>)
609614
{
610615
if (has_value()) {
611616
if (rhs.has_value()) {
612-
value_ = *rhs;
617+
value_ = std::move(*rhs);
613618
} else {
614619
hard_reset();
615620
}
616621
}
617622

618623
else if (rhs.has_value()) {
619-
construct(*rhs);
624+
construct(std::move(*rhs));
620625
}
621626

622627
return *this;

papers/P2988/base-optional.tex

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
\rSec0[utilities]{General utilities library}
2-
31
\rSec1[optional]{Optional objects}
42

53
\rSec2[optional.general]{General}
@@ -88,7 +86,7 @@
8886
constexpr void swap(optional<T>&, optional<T>&) noexcept(@\seebelow@);
8987

9088
template<class T>
91-
constexpr optional<@\seebelow@> make_optional(T&&);
89+
constexpr optional<decay_t<T>> make_optional(T&&);
9290
template<class T, class... Args>
9391
constexpr optional<T> make_optional(Args&&... args);
9492
template<class T, class U, class... Args>
@@ -124,7 +122,7 @@
124122
constexpr explicit optional(in_place_t, Args&&...);
125123
template<class U, class... Args>
126124
constexpr explicit optional(in_place_t, initializer_list<U>, Args&&...);
127-
template<class U = T>
125+
template<class U = remove_cv_t<T>>
128126
constexpr explicit(@\seebelow@) optional(U&&);
129127
template<class U>
130128
constexpr explicit(@\seebelow@) optional(const optional<U>&);
@@ -138,7 +136,7 @@
138136
constexpr optional& operator=(nullopt_t) noexcept;
139137
constexpr optional& operator=(const optional&);
140138
constexpr optional& operator=(optional&&) noexcept(@\seebelow@);
141-
template<class U = T> constexpr optional& operator=(U&&);
139+
template<class U = remove_cv_t<T>> constexpr optional& operator=(U&&);
142140
template<class U> constexpr optional& operator=(const optional<U>&);
143141
template<class U> constexpr optional& operator=(optional<U>&&);
144142
template<class... Args> constexpr T& emplace(Args&&...);
@@ -166,8 +164,8 @@
166164
constexpr T& value() &; // freestanding-deleted
167165
constexpr T&& value() &&; // freestanding-deleted
168166
constexpr const T&& value() const &&; // freestanding-deleted
169-
template<class U> constexpr T value_or(U&&) const &;
170-
template<class U> constexpr T value_or(U&&) &&;
167+
template<class U = remove_cv_t<T>> constexpr T value_or(U&&) const &;
168+
template<class U = remove_cv_t<T>> constexpr T value_or(U&&) &&;
171169

172170
// \ref{optional.monadic}, monadic operations
173171
template<class F> constexpr auto and_then(F&& f) &;
@@ -185,7 +183,7 @@
185183
constexpr void reset() noexcept;
186184

187185
private:
188-
T *val; // \expos
186+
T* val; // \expos
189187
};
190188

191189
template<class T>
@@ -197,8 +195,7 @@
197195
Any instance of \tcode{optional<T>} at any given time either contains a value or does not contain a value.
198196
When an instance of \tcode{optional<T>} \defnx{contains a value}{contains a value!\idxcode{optional}},
199197
it means that an object of type \tcode{T}, referred to as the optional object's \defnx{contained value}{contained value!\idxcode{optional}},
200-
is allocated within the storage of the optional object.
201-
Implementations are not permitted to use additional storage, such as dynamic memory, to allocate its contained value.
198+
is nested within\iref{intro.object} the optional object.
202199
When an object of type \tcode{optional<T>} is contextually converted to \tcode{bool},
203200
the conversion returns \tcode{true} if the object contains a value;
204201
otherwise the conversion returns \tcode{false}.
@@ -359,7 +356,7 @@
359356

360357
\indexlibraryctor{optional}%
361358
\begin{itemdecl}
362-
template<class U = T> constexpr explicit(@\seebelow@) optional(U&& v);
359+
template<class U = remove_cv_t<T>> constexpr explicit(@\seebelow@) optional(U&& v);
363360
\end{itemdecl}
364361

365362
\begin{itemdescr}
@@ -611,16 +608,18 @@
611608

612609
\indexlibrarymember{operator=}{optional}%
613610
\begin{itemdecl}
614-
template<class U = T> constexpr optional<T>& operator=(U&& v);
611+
template<class U = remove_cv_t<T>> constexpr optional& operator=(U&& v);
615612
\end{itemdecl}
616613

617614
\begin{itemdescr}
618615
\pnum
619616
\constraints
620-
\tcode{is_same_v<remove_cvref_t<U>, optional>} is \tcode{false},
621-
\tcode{conjunction_v<is_scalar<T>, is_same<T, decay_t<U>>>} is \tcode{false},
622-
\tcode{is_constructible_v<T, U>} is \tcode{true}, and
623-
\tcode{is_assignable_v<T\&, U>} is \tcode{true}.
617+
\begin{itemize}
618+
\item \tcode{is_same_v<remove_cvref_t<U>, optional>} is \tcode{false},
619+
\item \tcode{conjunction_v<is_scalar<T>, is_same<T, decay_t<U>>>} is \tcode{false},
620+
\item \tcode{is_constructible_v<T, U>} is \tcode{true}, and
621+
\item \tcode{is_assignable_v<T\&, U>} is \tcode{true}.
622+
\end{itemize}
624623

625624
\pnum
626625
\effects
@@ -1046,7 +1045,7 @@
10461045

10471046
\indexlibrarymember{value_or}{optional}%
10481047
\begin{itemdecl}
1049-
template<class U> constexpr T value_or(U&& v) const &;
1048+
template<class U = remove_cv_t<T>> constexpr T value_or(U&& v) const &;
10501049
\end{itemdecl}
10511050

10521051
\begin{itemdescr}
@@ -1064,7 +1063,7 @@
10641063

10651064
\indexlibrarymember{value_or}{optional}%
10661065
\begin{itemdecl}
1067-
template<class U> constexpr T value_or(U&& v) &&;
1066+
template<class U = remove_cv_t<T>> constexpr T value_or(U&& v) &&;
10681067
\end{itemdecl}
10691068

10701069
\begin{itemdescr}
@@ -1512,6 +1511,7 @@
15121511
\begin{itemdescr}
15131512
\pnum
15141513
\constraints
1514+
\tcode{U} is not a specialization of \tcode{optional}.
15151515
The expression \tcode{*x == v} is well-formed and
15161516
its result is convertible to \tcode{bool}.
15171517
\begin{note}
@@ -1531,6 +1531,7 @@
15311531
\begin{itemdescr}
15321532
\pnum
15331533
\constraints
1534+
\tcode{T} is not a specialization of \tcode{optional}.
15341535
The expression \tcode{v == *x} is well-formed and
15351536
its result is convertible to \tcode{bool}.
15361537

@@ -1547,6 +1548,7 @@
15471548
\begin{itemdescr}
15481549
\pnum
15491550
\constraints
1551+
\tcode{U} is not a specialization of \tcode{optional}.
15501552
The expression \tcode{*x != v} is well-formed and
15511553
its result is convertible to \tcode{bool}.
15521554

@@ -1563,6 +1565,7 @@
15631565
\begin{itemdescr}
15641566
\pnum
15651567
\constraints
1568+
\tcode{T} is not a specialization of \tcode{optional}.
15661569
The expression \tcode{v != *x} is well-formed and
15671570
its result is convertible to \tcode{bool}.
15681571

@@ -1579,6 +1582,7 @@
15791582
\begin{itemdescr}
15801583
\pnum
15811584
\constraints
1585+
\tcode{U} is not a specialization of \tcode{optional}.
15821586
The expression \tcode{*x < v} is well-formed and
15831587
its result is convertible to \tcode{bool}.
15841588

@@ -1595,6 +1599,7 @@
15951599
\begin{itemdescr}
15961600
\pnum
15971601
\constraints
1602+
\tcode{T} is not a specialization of \tcode{optional}.
15981603
The expression \tcode{v < *x} is well-formed and
15991604
its result is convertible to \tcode{bool}.
16001605

@@ -1611,6 +1616,7 @@
16111616
\begin{itemdescr}
16121617
\pnum
16131618
\constraints
1619+
\tcode{U} is not a specialization of \tcode{optional}.
16141620
The expression \tcode{*x > v} is well-formed and
16151621
its result is convertible to \tcode{bool}.
16161622

@@ -1627,6 +1633,7 @@
16271633
\begin{itemdescr}
16281634
\pnum
16291635
\constraints
1636+
\tcode{T} is not a specialization of \tcode{optional}.
16301637
The expression \tcode{v > *x} is well-formed and
16311638
its result is convertible to \tcode{bool}.
16321639

@@ -1643,6 +1650,7 @@
16431650
\begin{itemdescr}
16441651
\pnum
16451652
\constraints
1653+
\tcode{U} is not a specialization of \tcode{optional}.
16461654
The expression \tcode{*x <= v} is well-formed and
16471655
its result is convertible to \tcode{bool}.
16481656

@@ -1659,6 +1667,7 @@
16591667
\begin{itemdescr}
16601668
\pnum
16611669
\constraints
1670+
\tcode{T} is not a specialization of \tcode{optional}.
16621671
The expression \tcode{v <= *x} is well-formed and
16631672
its result is convertible to \tcode{bool}.
16641673

@@ -1675,6 +1684,7 @@
16751684
\begin{itemdescr}
16761685
\pnum
16771686
\constraints
1687+
\tcode{U} is not a specialization of \tcode{optional}.
16781688
The expression \tcode{*x >= v} is well-formed and
16791689
its result is convertible to \tcode{bool}.
16801690

@@ -1691,6 +1701,7 @@
16911701
\begin{itemdescr}
16921702
\pnum
16931703
\constraints
1704+
\tcode{T} is not a specialization of \tcode{optional}.
16941705
The expression \tcode{v >= *x} is well-formed and
16951706
its result is convertible to \tcode{bool}.
16961707

papers/P2988/mybiblio.bib

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,12 @@ @misc{rawgithu58:online
5858
year = {},
5959
note = {(Accessed on 08/14/2024)}
6060
}
61+
62+
@misc{The_Beman_Project_beman_optional26,
63+
author = {The Beman Project},
64+
license = {Apache-2.0},
65+
title = {{beman.optional26}},
66+
howpublished = {\url{https://github.com/bemanproject/optional26}},
67+
month = {},
68+
year = {},
69+
}

0 commit comments

Comments
 (0)