forked from OSchip/llvm-project
Make move and forward work in C++03.
These functions are key to allowing the use of rvalues and variadics in C++03 mode. Everything works the same as in C++11, except for one tangentially related case: struct T { T(T &&) = default; }; In C++11, T has a deleted copy constructor. But in C++03 Clang gives it both a move and a copy constructor. This seems reasonable enough given the extensions it's using. The other changes in this patch were the minimal set required to keep the tests passing after the move/forward change. Most notably the removal of the `__rv<unique_ptr>` hack that was present in an attempt to make unique_ptr move only without language support. llvm-svn: 364063
This commit is contained in:
parent
ddb9093684
commit
000f25a37e
|
@ -3181,11 +3181,7 @@ _SampleIterator sample(_PopulationIterator __first,
|
|||
|
||||
template<class _RandomAccessIterator, class _UniformRandomNumberGenerator>
|
||||
void shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
_UniformRandomNumberGenerator&& __g)
|
||||
#else
|
||||
_UniformRandomNumberGenerator& __g)
|
||||
#endif
|
||||
{
|
||||
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
|
||||
typedef uniform_int_distribution<ptrdiff_t> _Dp;
|
||||
|
|
|
@ -260,11 +260,7 @@ struct __throw_with_nested;
|
|||
template <class _Tp, class _Up>
|
||||
struct __throw_with_nested<_Tp, _Up, true> {
|
||||
_LIBCPP_NORETURN static inline _LIBCPP_INLINE_VISIBILITY void
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
__do_throw(_Tp&& __t)
|
||||
#else
|
||||
__do_throw (_Tp& __t)
|
||||
#endif // _LIBCPP_CXX03_LANG
|
||||
{
|
||||
throw __nested<_Up>(_VSTD::forward<_Tp>(__t));
|
||||
}
|
||||
|
@ -287,11 +283,7 @@ struct __throw_with_nested<_Tp, _Up, false> {
|
|||
template <class _Tp>
|
||||
_LIBCPP_NORETURN
|
||||
void
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
throw_with_nested(_Tp&& __t)
|
||||
#else
|
||||
throw_with_nested (_Tp& __t)
|
||||
#endif // _LIBCPP_CXX03_LANG
|
||||
{
|
||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
typedef typename decay<_Tp>::type _Up;
|
||||
|
|
|
@ -808,7 +808,6 @@ public:
|
|||
_LIBCPP_INLINE_VISIBILITY
|
||||
void clear() _NOEXCEPT {base::clear();}
|
||||
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
void splice_after(const_iterator __p, forward_list&& __x);
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
|
@ -816,7 +815,6 @@ public:
|
|||
_LIBCPP_INLINE_VISIBILITY
|
||||
void splice_after(const_iterator __p, forward_list&& __x,
|
||||
const_iterator __f, const_iterator __l);
|
||||
#endif // _LIBCPP_CXX03_LANG
|
||||
void splice_after(const_iterator __p, forward_list& __x);
|
||||
void splice_after(const_iterator __p, forward_list& __x, const_iterator __i);
|
||||
void splice_after(const_iterator __p, forward_list& __x,
|
||||
|
@ -1468,8 +1466,6 @@ forward_list<_Tp, _Alloc>::splice_after(const_iterator __p,
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
|
||||
template <class _Tp, class _Alloc>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
void
|
||||
|
@ -1499,8 +1495,6 @@ forward_list<_Tp, _Alloc>::splice_after(const_iterator __p,
|
|||
splice_after(__p, __x, __f, __l);
|
||||
}
|
||||
|
||||
#endif // _LIBCPP_CXX03_LANG
|
||||
|
||||
template <class _Tp, class _Alloc>
|
||||
void
|
||||
forward_list<_Tp, _Alloc>::remove(const value_type& __v)
|
||||
|
|
|
@ -2561,14 +2561,9 @@ public:
|
|||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
operator __rv<unique_ptr>() {
|
||||
return __rv<unique_ptr>(*this);
|
||||
}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
unique_ptr(__rv<unique_ptr> __u)
|
||||
: __ptr_(__u->release(),
|
||||
_VSTD::forward<deleter_type>(__u->get_deleter())) {}
|
||||
unique_ptr(unique_ptr&& __u)
|
||||
: __ptr_(__u.release(),
|
||||
_VSTD::forward<deleter_type>(__u.get_deleter())) {}
|
||||
|
||||
template <class _Up, class _Ep>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
|
@ -2586,7 +2581,7 @@ public:
|
|||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
unique_ptr(pointer __p, deleter_type __d)
|
||||
: __ptr_(_VSTD::move(__p), _VSTD::move(__d)) {}
|
||||
: __ptr_(__p, _VSTD::forward<deleter_type>(__d)) {}
|
||||
#endif // _LIBCPP_CXX03_LANG
|
||||
|
||||
#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR)
|
||||
|
@ -2863,19 +2858,14 @@ public:
|
|||
: __ptr_(pointer(), _VSTD::forward<deleter_type>(__d)) {}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
operator __rv<unique_ptr>() {
|
||||
return __rv<unique_ptr>(*this);
|
||||
}
|
||||
unique_ptr(unique_ptr&& __u)
|
||||
: __ptr_(__u.release(),
|
||||
_VSTD::forward<deleter_type>(__u.get_deleter())) {}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
unique_ptr(__rv<unique_ptr> __u)
|
||||
: __ptr_(__u->release(),
|
||||
_VSTD::forward<deleter_type>(__u->get_deleter())) {}
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
unique_ptr& operator=(__rv<unique_ptr> __u) {
|
||||
reset(__u->release());
|
||||
__ptr_.second() = _VSTD::forward<deleter_type>(__u->get_deleter());
|
||||
unique_ptr& operator=(unique_ptr&& __u) {
|
||||
reset(__u.release());
|
||||
__ptr_.second() = _VSTD::forward<deleter_type>(__u.get_deleter());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -3091,18 +3081,6 @@ operator>=(nullptr_t, const unique_ptr<_T1, _D1>& __x)
|
|||
return !(nullptr < __x);
|
||||
}
|
||||
|
||||
#ifdef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||
|
||||
template <class _Tp, class _Dp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
unique_ptr<_Tp, _Dp>
|
||||
move(unique_ptr<_Tp, _Dp>& __t)
|
||||
{
|
||||
return unique_ptr<_Tp, _Dp>(__rv<unique_ptr<_Tp, _Dp> >(__t));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_STD_VER > 11
|
||||
|
||||
template<class _Tp>
|
||||
|
|
|
@ -2277,8 +2277,6 @@ _LIBCPP_INLINE_VAR _LIBCPP_CONSTEXPR bool is_destructible_v
|
|||
|
||||
// move
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename remove_reference<_Tp>::type&&
|
||||
|
@ -2306,47 +2304,6 @@ forward(typename remove_reference<_Tp>::type&& __t) _NOEXCEPT
|
|||
return static_cast<_Tp&&>(__t);
|
||||
}
|
||||
|
||||
#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_Tp&
|
||||
move(_Tp& __t)
|
||||
{
|
||||
return __t;
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
const _Tp&
|
||||
move(const _Tp& __t)
|
||||
{
|
||||
return __t;
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_Tp&
|
||||
forward(typename remove_reference<_Tp>::type& __t) _NOEXCEPT
|
||||
{
|
||||
return __t;
|
||||
}
|
||||
|
||||
|
||||
template <class _Tp>
|
||||
class __rv
|
||||
{
|
||||
typedef typename remove_reference<_Tp>::type _Trr;
|
||||
_Trr& t_;
|
||||
public:
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
_Trr* operator->() {return &t_;}
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
explicit __rv(_Trr& __t) : t_(__t) {}
|
||||
};
|
||||
|
||||
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||
|
||||
template <class _Tp>
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// FIXME(EricWF): Make this test pass in C++03 with Clang once the transition
|
||||
// has gotten far enough that __invoke works.
|
||||
// XFAIL: c++98 || c++03
|
||||
|
||||
// <functional>
|
||||
|
||||
// INVOKE (f, t1, t2, ..., tN)
|
||||
|
|
|
@ -21,16 +21,10 @@ const A csource() {return A();}
|
|||
|
||||
int main(int, char**)
|
||||
{
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
std::forward<A&>(source()); // expected-note {{requested here}}
|
||||
// expected-error-re@type_traits:* 1 {{static_assert failed{{.*}} "can not forward an rvalue as an lvalue"}}
|
||||
}
|
||||
#else
|
||||
{
|
||||
std::forward<A&>(source()); // expected-error {{no matching function for call to 'forward'}}
|
||||
}
|
||||
#endif
|
||||
{
|
||||
const A ca = A();
|
||||
std::forward<A&>(ca); // expected-error {{no matching function for call to 'forward'}}
|
||||
|
|
|
@ -20,12 +20,12 @@ struct A
|
|||
{
|
||||
};
|
||||
|
||||
A source() noexcept {return A();}
|
||||
const A csource() noexcept {return A();}
|
||||
A source() TEST_NOEXCEPT {return A();}
|
||||
const A csource() TEST_NOEXCEPT {return A();}
|
||||
|
||||
|
||||
constexpr bool test_constexpr_forward() {
|
||||
#if TEST_STD_VER > 11
|
||||
constexpr bool test_constexpr_forward() {
|
||||
int x = 42;
|
||||
const int cx = 101;
|
||||
return std::forward<int&>(x) == 42
|
||||
|
@ -36,10 +36,8 @@ constexpr bool test_constexpr_forward() {
|
|||
&& std::forward<const int&&>(x) == 42
|
||||
&& std::forward<const int&>(cx) == 101
|
||||
&& std::forward<const int>(cx) == 101;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
|
@ -52,23 +50,23 @@ int main(int, char**)
|
|||
static_assert(std::is_same<decltype(std::forward<A&>(a)), A&>::value, "");
|
||||
static_assert(std::is_same<decltype(std::forward<A>(a)), A&&>::value, "");
|
||||
static_assert(std::is_same<decltype(std::forward<A>(source())), A&&>::value, "");
|
||||
static_assert(noexcept(std::forward<A&>(a)), "");
|
||||
static_assert(noexcept(std::forward<A>(a)), "");
|
||||
static_assert(noexcept(std::forward<A>(source())), "");
|
||||
ASSERT_NOEXCEPT(std::forward<A&>(a));
|
||||
ASSERT_NOEXCEPT(std::forward<A>(a));
|
||||
ASSERT_NOEXCEPT(std::forward<A>(source()));
|
||||
|
||||
static_assert(std::is_same<decltype(std::forward<const A&>(a)), const A&>::value, "");
|
||||
static_assert(std::is_same<decltype(std::forward<const A>(a)), const A&&>::value, "");
|
||||
static_assert(std::is_same<decltype(std::forward<const A>(source())), const A&&>::value, "");
|
||||
static_assert(noexcept(std::forward<const A&>(a)), "");
|
||||
static_assert(noexcept(std::forward<const A>(a)), "");
|
||||
static_assert(noexcept(std::forward<const A>(source())), "");
|
||||
ASSERT_NOEXCEPT(std::forward<const A&>(a));
|
||||
ASSERT_NOEXCEPT(std::forward<const A>(a));
|
||||
ASSERT_NOEXCEPT(std::forward<const A>(source()));
|
||||
|
||||
static_assert(std::is_same<decltype(std::forward<const A&>(ca)), const A&>::value, "");
|
||||
static_assert(std::is_same<decltype(std::forward<const A>(ca)), const A&&>::value, "");
|
||||
static_assert(std::is_same<decltype(std::forward<const A>(csource())), const A&&>::value, "");
|
||||
static_assert(noexcept(std::forward<const A&>(ca)), "");
|
||||
static_assert(noexcept(std::forward<const A>(ca)), "");
|
||||
static_assert(noexcept(std::forward<const A>(csource())), "");
|
||||
ASSERT_NOEXCEPT(std::forward<const A&>(ca));
|
||||
ASSERT_NOEXCEPT(std::forward<const A>(ca));
|
||||
ASSERT_NOEXCEPT(std::forward<const A>(csource()));
|
||||
|
||||
#if TEST_STD_VER > 11
|
||||
{
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// test forward
|
||||
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
struct A
|
||||
{
|
||||
};
|
||||
|
||||
A source() {return A();}
|
||||
const A csource() {return A();}
|
||||
|
||||
typedef char one;
|
||||
struct two {one _[2];};
|
||||
struct four {one _[4];};
|
||||
struct eight {one _[8];};
|
||||
|
||||
one test(A&);
|
||||
two test(const A&);
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
A a;
|
||||
const A ca = A();
|
||||
|
||||
((void)a); // Prevent unused warning
|
||||
((void)ca); // Prevent unused warning
|
||||
|
||||
#if TEST_STD_VER < 11
|
||||
static_assert(sizeof(test(std::forward<A&>(a))) == 1, "");
|
||||
static_assert(sizeof(test(std::forward<A>(a))) == 1, "");
|
||||
|
||||
// Libc++'s C++03 implementation of 'forward' cannot accept true non-const
|
||||
// rvalues.
|
||||
// static_assert(sizeof(test(std::forward<A>(source()))) == 2, "");
|
||||
|
||||
static_assert(sizeof(test(std::forward<const A&>(a))) == 2, "");
|
||||
static_assert(sizeof(test(std::forward<const A&>(source()))) == 2, "");
|
||||
static_assert(sizeof(test(std::forward<const A>(a))) == 2, "");
|
||||
static_assert(sizeof(test(std::forward<const A>(source()))) == 2, "");
|
||||
|
||||
static_assert(sizeof(test(std::forward<const A&>(ca))) == 2, "");
|
||||
static_assert(sizeof(test(std::forward<const A&>(csource()))) == 2, "");
|
||||
static_assert(sizeof(test(std::forward<const A>(ca))) == 2, "");
|
||||
static_assert(sizeof(test(std::forward<const A>(csource()))) == 2, "");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -6,7 +6,11 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
// This test should pass in C++03 with Clang extensions because Clang does
|
||||
// not implicitly delete the copy constructor when move constructors are
|
||||
// defaulted using extensions.
|
||||
|
||||
// XFAIL: c++98, c++03
|
||||
|
||||
// test move
|
||||
|
||||
|
@ -26,10 +30,9 @@ void test(move_only) {}
|
|||
|
||||
int main(int, char**)
|
||||
{
|
||||
move_only a;
|
||||
const move_only ca = move_only();
|
||||
|
||||
test(std::move(ca)); // c
|
||||
const move_only ca = move_only();
|
||||
// expected-error@+1 {{call to implicitly-deleted copy constructor of 'move_only'}}
|
||||
test(std::move(ca));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
// test move
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
@ -36,7 +34,7 @@ int x = 42;
|
|||
const int& cx = x;
|
||||
|
||||
template <class QualInt>
|
||||
QualInt get() noexcept { return static_cast<QualInt>(x); }
|
||||
QualInt get() TEST_NOEXCEPT { return static_cast<QualInt>(x); }
|
||||
|
||||
|
||||
int copy_ctor = 0;
|
||||
|
@ -49,30 +47,27 @@ struct A {
|
|||
A& operator=(const A&) = delete;
|
||||
};
|
||||
|
||||
constexpr bool test_constexpr_move() {
|
||||
#if TEST_STD_VER > 11
|
||||
constexpr bool test_constexpr_move() {
|
||||
int y = 42;
|
||||
const int cy = y;
|
||||
return std::move(y) == 42
|
||||
&& std::move(cy) == 42
|
||||
&& std::move(static_cast<int&&>(y)) == 42
|
||||
&& std::move(static_cast<int const&&>(y)) == 42;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
int main(int, char**)
|
||||
{
|
||||
{ // Test return type and noexcept.
|
||||
static_assert(std::is_same<decltype(std::move(x)), int&&>::value, "");
|
||||
static_assert(noexcept(std::move(x)), "");
|
||||
ASSERT_NOEXCEPT(std::move(x));
|
||||
static_assert(std::is_same<decltype(std::move(cx)), const int&&>::value, "");
|
||||
static_assert(noexcept(std::move(cx)), "");
|
||||
ASSERT_NOEXCEPT(std::move(cx));
|
||||
static_assert(std::is_same<decltype(std::move(42)), int&&>::value, "");
|
||||
static_assert(noexcept(std::move(42)), "");
|
||||
ASSERT_NOEXCEPT(std::move(42));
|
||||
static_assert(std::is_same<decltype(std::move(get<const int&&>())), const int&&>::value, "");
|
||||
static_assert(noexcept(std::move(get<int const&&>())), "");
|
||||
ASSERT_NOEXCEPT(std::move(get<int const&&>()));
|
||||
}
|
||||
{ // test copy and move semantics
|
||||
A a;
|
||||
|
|
|
@ -28,9 +28,7 @@ class A
|
|||
public:
|
||||
|
||||
A() {}
|
||||
#if TEST_STD_VER >= 11
|
||||
A(A&&) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct legacy
|
||||
|
@ -55,9 +53,7 @@ int main(int, char**)
|
|||
static_assert((std::is_same<decltype(std::move_if_noexcept(ca)), const A&&>::value), "");
|
||||
static_assert((std::is_same<decltype(std::move_if_noexcept(l)), const legacy&>::value), "");
|
||||
#else // C++ < 11
|
||||
// In C++03 libc++ #define's decltype to be __decltype on clang and
|
||||
// __typeof__ for other compilers. __typeof__ does not deduce the reference
|
||||
// qualifiers and will cause this test to fail.
|
||||
// In C++03 we don't have noexcept so we can never move :-(
|
||||
static_assert((std::is_same<decltype(std::move_if_noexcept(i)), const int&>::value), "");
|
||||
static_assert((std::is_same<decltype(std::move_if_noexcept(ci)), const int&>::value), "");
|
||||
static_assert((std::is_same<decltype(std::move_if_noexcept(a)), const A&>::value), "");
|
||||
|
|
Loading…
Reference in New Issue