Skip to content

Commit

Permalink
[libc++] Make C++03 reference_wrapper more like C++11.
Browse files Browse the repository at this point in the history
Remove a bunch of LIBCPP_CXX03_LANG. This is the result of a
rabbithole to re-eliminate the workaround I introduced into
std::cref in D117953. It turns out that Clang's C++03 mode
(the only compiler we care about C++03 for) now supports all
the things we were originally eschewing via LIBCPP_CXX03_LANG;
we can fully support these reference_wrapper features in
C++03 mode, and un-XFAIL the relevant tests.

Drive-by constexprify a few more tests.

Differential Revision: https://reviews.llvm.org/D117974
  • Loading branch information
Arthur O'Dwyer committed Jan 27, 2022
1 parent 16031cb commit c99a585
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 92 deletions.
17 changes: 2 additions & 15 deletions libcxx/include/__functional/reference_wrapper.h
Expand Up @@ -34,25 +34,16 @@ class _LIBCPP_TEMPLATE_VIS reference_wrapper
private:
type* __f_;

#ifndef _LIBCPP_CXX03_LANG
static void __fun(_Tp&) _NOEXCEPT;
static void __fun(_Tp&&) = delete;
#endif

public:
// construct/copy/destroy
#ifdef _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
reference_wrapper(type& __f) _NOEXCEPT
: __f_(_VSTD::addressof(__f)) {}
#else
template <class _Up, class = __enable_if_t<!__is_same_uncvref<_Up, reference_wrapper>::value, decltype(__fun(declval<_Up>())) >>
template <class _Up, class = __enable_if_t<!__is_same_uncvref<_Up, reference_wrapper>::value, decltype(__fun(declval<_Up>())) > >
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
reference_wrapper(_Up&& __u) _NOEXCEPT_(noexcept(__fun(declval<_Up>()))) {
type& __f = static_cast<_Up&&>(__u);
__f_ = _VSTD::addressof(__f);
}
#endif

// access
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
Expand Down Expand Up @@ -210,15 +201,11 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
reference_wrapper<const _Tp>
cref(reference_wrapper<_Tp> __t) _NOEXCEPT
{
// C++20 says "return __t", but C++03 lacks the relevant
// converting constructor. This should be equivalent.
return __t.get();
return __t;
}

#ifndef _LIBCPP_CXX03_LANG
template <class _Tp> void ref(const _Tp&&) = delete;
template <class _Tp> void cref(const _Tp&&) = delete;
#endif

_LIBCPP_END_NAMESPACE_STD

Expand Down
Expand Up @@ -6,8 +6,6 @@
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03

// <functional>
//
// reference_wrapper
Expand All @@ -21,65 +19,58 @@
#include "test_macros.h"

struct convertible_to_int_ref {
int val = 0;
operator int&() { return val; }
operator int const&() const { return val; }
int val = 0;
operator int&() { return val; }
operator int const&() const { return val; }
};

template <bool IsNothrow>
struct nothrow_convertible {
int val = 0;
operator int&() noexcept(IsNothrow) { return val; }
int val = 0;
operator int&() TEST_NOEXCEPT_COND(IsNothrow) { return val; }
};

struct convertible_from_int {
convertible_from_int(int) {}
convertible_from_int(int) {}
};

void meow(std::reference_wrapper<int>) {}
void meow(convertible_from_int) {}

int gi;
std::reference_wrapper<int> purr() { return gi; };

template <class T>
void
test(T& t)
{
std::reference_wrapper<T> r(t);
assert(&r.get() == &t);
}

void f() {}

int main(int, char**)
{
convertible_to_int_ref convi;
test(convi);
convertible_to_int_ref const convic;
test(convic);

{
{
convertible_to_int_ref t;
std::reference_wrapper<convertible_to_int_ref> r(t);
assert(&r.get() == &t);
}
{
const convertible_to_int_ref t;
std::reference_wrapper<const convertible_to_int_ref> r(t);
assert(&r.get() == &t);
}
{
using Ref = std::reference_wrapper<int>;
static_assert((std::is_nothrow_constructible<Ref, nothrow_convertible<true>>::value), "");
static_assert((!std::is_nothrow_constructible<Ref, nothrow_convertible<false>>::value), "");
}

{
ASSERT_NOEXCEPT(Ref(nothrow_convertible<true>()));
ASSERT_NOT_NOEXCEPT(Ref(nothrow_convertible<false>()));
}
{
meow(0);
(true) ? purr() : 0;
}

#if TEST_STD_VER >= 17
{
}
{
extern std::reference_wrapper<int> purr();
ASSERT_SAME_TYPE(decltype(true ? purr() : 0), int);
}
#if TEST_STD_VER > 14
{
int i = 0;
std::reference_wrapper ri(i);
static_assert((std::is_same<decltype(ri), std::reference_wrapper<int>>::value), "" );
const int j = 0;
std::reference_wrapper rj(j);
static_assert((std::is_same<decltype(rj), std::reference_wrapper<const int>>::value), "" );
}
}
#endif

return 0;
return 0;
}
Expand Up @@ -6,8 +6,6 @@
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03

// <functional>
//
// reference_wrapper
Expand All @@ -20,46 +18,48 @@

#include "test_macros.h"

struct B {} b;
struct B {};

struct A1 {
operator B& () const { return b; }
mutable B b_;
TEST_CONSTEXPR operator B&() const { return b_; }
};

struct A2 {
operator B& () const noexcept { return b; }
mutable B b_;
TEST_CONSTEXPR operator B&() const TEST_NOEXCEPT { return b_; }
};

int main(int, char**)
{
{
std::reference_wrapper<B> b1 = A1();
assert(&b1.get() == &b);
b1 = A1();
assert(&b1.get() == &b);
void implicitly_convert(std::reference_wrapper<B>) TEST_NOEXCEPT;

static_assert(std::is_convertible<A1, std::reference_wrapper<B>>::value, "");
static_assert(!std::is_nothrow_constructible<std::reference_wrapper<B>, A1>::value, "");
#if TEST_STD_VER >= 20
static_assert(!std::is_nothrow_convertible_v<A1, std::reference_wrapper<B>>);
#endif
static_assert(std::is_assignable<std::reference_wrapper<B>, A1>::value, "");
static_assert(!std::is_nothrow_assignable<std::reference_wrapper<B>, A1>::value, "");
}

{
std::reference_wrapper<B> b2 = A2();
assert(&b2.get() == &b);
b2 = A2();
assert(&b2.get() == &b);
TEST_CONSTEXPR_CXX20 bool test()
{
{
A1 a;
ASSERT_NOT_NOEXCEPT(implicitly_convert(a));
std::reference_wrapper<B> b1 = a;
assert(&b1.get() == &a.b_);
ASSERT_NOT_NOEXCEPT(b1 = a);
b1 = a;
assert(&b1.get() == &a.b_);
}
{
A2 a;
ASSERT_NOEXCEPT(implicitly_convert(a));
std::reference_wrapper<B> b2 = a;
assert(&b2.get() == &a.b_);
ASSERT_NOEXCEPT(b2 = a);
b2 = a;
assert(&b2.get() == &a.b_);
}
return true;
}

static_assert(std::is_convertible<A2, std::reference_wrapper<B>>::value, "");
static_assert(std::is_nothrow_constructible<std::reference_wrapper<B>, A2>::value, "");
#if TEST_STD_VER >= 20
static_assert(std::is_nothrow_convertible_v<A2, std::reference_wrapper<B>>);
int main(int, char**) {
test();
#if TEST_STD_VER > 17
static_assert(test());
#endif
static_assert(std::is_assignable<std::reference_wrapper<B>, A2>::value, "");
static_assert(std::is_nothrow_assignable<std::reference_wrapper<B>, A2>::value, "");
}

return 0;
return 0;
}
Expand Up @@ -12,8 +12,6 @@

// reference_wrapper(T&&) = delete;

// XFAIL: c++03

#include <functional>
#include <cassert>

Expand Down
Expand Up @@ -14,8 +14,6 @@

// Don't allow binding to a temp

// XFAIL: c++03

#include <functional>

struct A {};
Expand Down

0 comments on commit c99a585

Please sign in to comment.