On Mon, Jul 14, 2025 at 2:00 PM Jonathan Wakely <jwak...@redhat.com> wrote:
> I've just created LWG 4295 proposing this change, and am implementing it > via this patch. > > libstdc++-v3/ChangeLog: > > * include/experimental/memory (swap, make_observer_ptr): Add > constexpr. > (operator==, operator!=, operator<, operator>, operator<=) > (operator>=): Likewise. > * testsuite/experimental/memory/observer_ptr/make_observer.cc: > Checks for constant evaluation. > * testsuite/experimental/memory/observer_ptr/relops/relops.cc: > Likewise. > * testsuite/experimental/memory/observer_ptr/swap/swap.cc: > Likewise. > --- > > Tested x86_64-linux. > LGTM. Just P0 the issue. > > libstdc++-v3/include/experimental/memory | 22 +++++++-------- > .../memory/observer_ptr/make_observer.cc | 11 ++++++-- > .../memory/observer_ptr/relops/relops.cc | 28 +++++++++++-------- > .../memory/observer_ptr/swap/swap.cc | 20 ++++++++----- > 4 files changed, 50 insertions(+), 31 deletions(-) > > diff --git a/libstdc++-v3/include/experimental/memory > b/libstdc++-v3/include/experimental/memory > index 131e5acc03d9..1b01462e1b26 100644 > --- a/libstdc++-v3/include/experimental/memory > +++ b/libstdc++-v3/include/experimental/memory > @@ -148,42 +148,42 @@ inline namespace fundamentals_v2 > }; // observer_ptr<> > > template<typename _Tp> > - void > + constexpr void > swap(observer_ptr<_Tp>& __p1, observer_ptr<_Tp>& __p2) noexcept > { > __p1.swap(__p2); > } > > template<typename _Tp> > - observer_ptr<_Tp> > + constexpr observer_ptr<_Tp> > make_observer(_Tp* __p) noexcept > { > return observer_ptr<_Tp>(__p); > } > > template<typename _Tp, typename _Up> > - bool > + constexpr bool > operator==(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) > { > return __p1.get() == __p2.get(); > } > > template<typename _Tp, typename _Up> > - bool > + constexpr bool > operator!=(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) > { > return !(__p1 == __p2); > } > > template<typename _Tp> > - bool > + constexpr bool > operator==(observer_ptr<_Tp> __p, nullptr_t) noexcept > { > return !__p; > } > > template<typename _Tp> > - bool > + constexpr bool > operator==(nullptr_t, observer_ptr<_Tp> __p) noexcept > { > return !__p; > @@ -197,14 +197,14 @@ inline namespace fundamentals_v2 > } > > template<typename _Tp> > - bool > + constexpr bool > operator!=(nullptr_t, observer_ptr<_Tp> __p) noexcept > { > return bool(__p); > } > > template<typename _Tp, typename _Up> > - bool > + constexpr bool > operator<(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) > { > return std::less<typename common_type<typename > add_pointer<_Tp>::type, > @@ -214,21 +214,21 @@ inline namespace fundamentals_v2 > } > > template<typename _Tp, typename _Up> > - bool > + constexpr bool > operator>(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) > { > return __p2 < __p1; > } > > template<typename _Tp, typename _Up> > - bool > + constexpr bool > operator<=(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) > { > return !(__p2 < __p1); > } > > template<typename _Tp, typename _Up> > - bool > + constexpr bool > operator>=(observer_ptr<_Tp> __p1, observer_ptr<_Up> __p2) > { > return !(__p1 < __p2); > diff --git > a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/make_observer.cc > b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/make_observer.cc > index 048735ff63ae..1de9cf095092 100644 > --- > a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/make_observer.cc > +++ > b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/make_observer.cc > @@ -20,12 +20,19 @@ > #include <experimental/memory> > #include <testsuite_hooks.h> > > -int main() > +constexpr bool test() > { > const int i = 42; > auto o = std::experimental::make_observer(&i); > static_assert( std::is_same<decltype(o), > - std::experimental::observer_ptr<const int>>(), "" ); > + std::experimental::observer_ptr<const int>>(), "" ); > VERIFY( o && *o == 42 ); > VERIFY( o.get() == &i ); > + return true; > +} > + > +int main() > +{ > + test(); > + static_assert( test(), "LWG 4295 - make_observer should be constexpr" ); > } > diff --git > a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/relops/relops.cc > b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/relops/relops.cc > index 3e23e0b452be..d03dd5dcbd80 100644 > --- > a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/relops/relops.cc > +++ > b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/relops/relops.cc > @@ -22,13 +22,13 @@ > > using std::experimental::observer_ptr; > > -void test01() > +constexpr void test01() > { > observer_ptr<int> a, b; > VERIFY(a == b); > } > > -void test02() > +constexpr void test02() > { > int x[2]{}; > observer_ptr<int> a{&x[0]}; > @@ -40,7 +40,7 @@ void test02() > VERIFY(b > a); > } > > -void test03() > +constexpr void test03() > { > int x{}; > observer_ptr<int> a{&x}; > @@ -48,9 +48,10 @@ void test03() > VERIFY(a == b); > } > > -void test04() > +int x[2]{}; > + > +constexpr void test04() > { > - static constexpr int x[2]{}; > constexpr observer_ptr<const int> a{&x[0]}; > constexpr observer_ptr<const int> b{&x[1]}; > VERIFY(a != b); > @@ -60,20 +61,25 @@ void test04() > VERIFY(b > a); > } > > -void test05() > +constexpr void test05() > { > - static constexpr int x{}; > - constexpr observer_ptr<const int> a{&x}; > - constexpr observer_ptr<const int> b{&x}; > + constexpr observer_ptr<const int> a{&x[0]}; > + constexpr observer_ptr<const int> b{&x[0]}; > VERIFY(a == b); > } > > - > -int main() > +constexpr bool all_tests() > { > test01(); > test02(); > test03(); > test04(); > test05(); > + return true; > +} > + > +int main() > +{ > + all_tests(); > + static_assert( all_tests(), "LWG 4295 - relops should be constexpr" ); > } > diff --git > a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/swap/swap.cc > b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/swap/swap.cc > index 9e7678863512..84b8844af34d 100644 > --- a/libstdc++-v3/testsuite/experimental/memory/observer_ptr/swap/swap.cc > +++ b/libstdc++-v3/testsuite/experimental/memory/observer_ptr/swap/swap.cc > @@ -25,7 +25,7 @@ using std::experimental::observer_ptr; > struct B {}; > struct D : B {}; > > -void test01() > +constexpr void test01() > { > observer_ptr<int> a, b; > VERIFY(a == b); > @@ -33,7 +33,7 @@ void test01() > VERIFY(a == b); > } > > -void test02() > +constexpr void test02() > { > int x{}; > observer_ptr<int> a; > @@ -45,7 +45,7 @@ void test02() > VERIFY(!b); > } > > -void test03() > +constexpr void test03() > { > int x[2]{1,2}; > observer_ptr<int> a{&x[0]}; > @@ -57,10 +57,16 @@ void test03() > VERIFY(*b == 1); > } > > - > int main() > { > - test01(); > - test02(); > - test03(); > + auto tests = [] { > + test01(); > + test02(); > + test03(); > + return true; > + }; > + tests(); > +#if __cpp_lib_constexpr_algorithms >= 201806L // >= C++20 > + static_assert( tests(), "LWG 4295 - swap should be constexpr" ); > +#endif > } > -- > 2.50.1 > >