xref: /llvm-project/clang/test/SemaCXX/builtin-std-move.cpp (revision 47df391296fcf8fe430e1ff6f797e5d7cfd41ca4)
1 // RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s
2 // RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s -DNO_CONSTEXPR
3 // RUN: %clang_cc1 -std=c++20 -verify=cxx20,expected %s
4 //
5 // RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s -fexperimental-new-constant-interpreter -DNEW_INTERP
6 // RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s -fexperimental-new-constant-interpreter -DNEW_INTERP -DNO_CONSTEXPR
7 // RUN: %clang_cc1 -std=c++20 -verify=cxx20,expected %s -fexperimental-new-constant-interpreter -DNEW_INTERP
8 
9 namespace std {
10 #ifndef NO_CONSTEXPR
11 #define CONSTEXPR constexpr
12 #else
13 #define CONSTEXPR
14 #endif
15 
move(T & x)16   template<typename T> CONSTEXPR T &&move(T &x) {
17     static_assert(T::moveable, "instantiated move"); // expected-error {{no member named 'moveable' in 'B'}}
18                                                      // expected-error@-1 {{no member named 'moveable' in 'C'}}
19                                                      // expected-error@-2 {{no member named 'moveable' in 'D'}}
20     return static_cast<T&&>(x);
21   }
22 
23   // Unrelated move functions are not the builtin.
move(T,T)24   template<typename T> CONSTEXPR int move(T, T) { return 5; }
25 
26   template<typename T, bool Rref> struct ref { using type = T&; };
27   template<typename T> struct ref<T, true> { using type = T&&; };
28 
move_if_noexcept(T & x)29   template<typename T> CONSTEXPR auto move_if_noexcept(T &x) -> typename ref<T, noexcept(T(static_cast<T&&>(x)))>::type {
30     static_assert(T::moveable, "instantiated move_if_noexcept"); // expected-error {{no member named 'moveable' in 'B'}}
31                                                                  // expected-error@-1 {{no member named 'moveable' in 'D'}}
32     return static_cast<typename ref<T, noexcept(T(static_cast<T&&>(x)))>::type>(x);
33   }
34 
35   template<typename T> struct remove_reference { using type = T; };
36   template<typename T> struct remove_reference<T&> { using type = T; };
37   template<typename T> struct remove_reference<T&&> { using type = T; };
38 
39   template<typename T> struct is_lvalue_reference { static constexpr bool value = false; };
40   template<typename T> struct is_lvalue_reference<T&> { static constexpr bool value = true; };
41 
forward(typename remove_reference<T>::type & x)42   template<typename T> CONSTEXPR T &&forward(typename remove_reference<T>::type &x) {
43     static_assert(T::moveable, "instantiated forward"); // expected-error {{no member named 'moveable' in 'B'}}
44                                                         // expected-error@-1 {{no member named 'moveable' in 'C'}}
45                                                         // expected-error@-2 {{no member named 'moveable' in 'D'}}
46     return static_cast<T&&>(x);
47   }
forward(typename remove_reference<T>::type && x)48   template<typename T> CONSTEXPR T &&forward(typename remove_reference<T>::type &&x) {
49     static_assert(!is_lvalue_reference<T>::value, "should not forward rval as lval"); // expected-error {{static assertion failed}}
50     return static_cast<T&&>(x);
51   }
52 
53   template <class T> struct is_const { static constexpr bool value = false; };
54   template <class T> struct is_const<const T> { static constexpr bool value = true; };
55 
56   template <bool B, class T, class F> struct conditional { using type = T; };
57   template <class T, class F> struct conditional<false, T, F> { using type = F; };
58 
59   template <class U, class T>
60   using CopyConst = typename conditional<
61           is_const<remove_reference<U>>::value,
62           const T, T>::type;
63 
64   template <class U, class T>
65   using OverrideRef = typename conditional<
66           is_lvalue_reference<U &&>::value,
67           typename remove_reference<T>::type &,
68           typename remove_reference<T>::type &&>::type;
69 
70   template <class U, class T>
71   using ForwardLikeRetType = OverrideRef<U &&, CopyConst<U, T>>;
72 
73   template <class U, class T>
forward_like(T && t)74   CONSTEXPR auto forward_like(T &&t) -> ForwardLikeRetType<U, T> {
75     using TT = typename remove_reference<T>::type;
76     static_assert(TT::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
77                                                           // expected-error@-1 {{no member named 'moveable' in 'D'}}
78     return static_cast<ForwardLikeRetType<U, T>>(t);
79   }
80 
as_const(T & x)81   template<typename T> CONSTEXPR const T &as_const(T &x) {
82     static_assert(T::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
83                                                          // expected-error@-1 {{no member named 'moveable' in 'D'}}
84     return x;
85   }
86 
addressof(T & x)87   template<typename T> CONSTEXPR T *addressof(T &x) {
88     static_assert(T::moveable, "instantiated addressof"); // expected-error {{no member named 'moveable' in 'B'}}
89                                                           // expected-error@-1 {{no member named 'moveable' in 'D'}}
90     return __builtin_addressof(x);
91   }
92 
__addressof(T & x)93   template<typename T> CONSTEXPR T *__addressof(T &x) {
94     static_assert(T::moveable, "instantiated __addressof"); // expected-error {{no member named 'moveable' in 'B'}}
95                                                             // expected-error@-1 {{no member named 'moveable' in 'D'}}
96     return __builtin_addressof(x);
97   }
98 }
99 
100 // Note: this doesn't have a 'moveable' member. Instantiation of the above
101 // functions will fail if it's attempted.
102 struct A {};
f(A a)103 constexpr bool f(A a) { // #f
104   A &&move = std::move(a); // #call
105   A &&move_if_noexcept = std::move_if_noexcept(a);
106   A &&forward1 = std::forward<A>(a);
107   A &forward2 = std::forward<A&>(a);
108   const A &as_const = std::as_const(a);
109   A *addressof = std::addressof(a);
110   A *addressof2 = std::__addressof(a);
111   return &move == &a && &move_if_noexcept == &a &&
112          &forward1 == &a && &forward2 == &a &&
113          &as_const == &a && addressof == &a &&
114          addressof2 == &a && std::move(a, a) == 5;
115 }
116 
117 #ifndef NO_CONSTEXPR
118 static_assert(f({}), "should be constexpr");
119 #elif !defined(NEW_INTERP)
120 // expected-error@#f {{never produces a constant expression}}
121 // expected-note@#call {{}}
122 #endif
123 
forward_rval_as_lval()124 A &forward_rval_as_lval() {
125   std::forward<A&&>(A()); // expected-warning {{const attribute}}
126   return std::forward<A&>(A()); // expected-note {{instantiation of}} expected-warning {{returning reference}}
127 }
128 
129 struct B {};
130 B &&(*pMove)(B&) = std::move;                            // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
131 B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept;     // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
132 B &&(*pForward)(B&) = &std::forward<B>;                  // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
133 B &&(*pForwardLike)(B&) = &std::forward_like<int&&, B&>; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
134 const B &(*pAsConst)(B&) = &std::as_const;               // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
135 B *(*pAddressof)(B&) = &std::addressof;                  // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
136 B *(*pUnderUnderAddressof)(B&) = &std::__addressof;      // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
137 int (*pUnrelatedMove)(B, B) = std::move;
138 
139 struct C {};
140 C &&(&rMove)(C&) = std::move;          // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
141 C &&(&rForward)(C&) = std::forward<C>; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
142 int (&rUnrelatedMove)(B, B) = std::move;
143 
attribute_const()144 void attribute_const() {
145   int n;
146   std::move(n); // expected-warning {{ignoring return value}}
147   std::move_if_noexcept(n); // expected-warning {{ignoring return value}}
148   std::forward<int>(n); // expected-warning {{ignoring return value}}
149   std::forward_like<float&&>(n); // expected-warning {{ignoring return value}}
150   std::addressof(n); // expected-warning {{ignoring return value}}
151   std::__addressof(n); // expected-warning {{ignoring return value}}
152   std::as_const(n); // expected-warning {{ignoring return value}}
153 }
154 
155 struct D {
156   void* operator new(__SIZE_TYPE__, D&&(*)(D&));
157   void* operator new(__SIZE_TYPE__, D*(*)(D&));
158   void* operator new(__SIZE_TYPE__, const D&(*)(D&));
159 };
160 
placement_new()161 void placement_new() {
162   new (std::move<D>) D;             // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
163   new (std::move_if_noexcept<D>) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
164   new (std::forward<D>) D;          // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
165   new (std::forward_like<D>) D;     // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
166   new (std::addressof<D>) D;        // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
167   new (std::__addressof<D>) D;      // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
168   new (std::as_const<D>) D;         // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
169 }
170 
171 namespace std {
172   template<typename T> int &move(T);
173 }
174 int bad_signature = std::move(0); // expected-error {{unsupported signature for 'std::move<int>'}}
175