xref: /llvm-project/clang/test/SemaCXX/builtin-std-move.cpp (revision 47df391296fcf8fe430e1ff6f797e5d7cfd41ca4)
1af0ee617SSirraide // RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s
2af0ee617SSirraide // RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s -DNO_CONSTEXPR
3af0ee617SSirraide // RUN: %clang_cc1 -std=c++20 -verify=cxx20,expected %s
4*47df3912STimm Baeder //
5*47df3912STimm Baeder // RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s -fexperimental-new-constant-interpreter -DNEW_INTERP
6*47df3912STimm Baeder // RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s -fexperimental-new-constant-interpreter -DNEW_INTERP -DNO_CONSTEXPR
7*47df3912STimm Baeder // RUN: %clang_cc1 -std=c++20 -verify=cxx20,expected %s -fexperimental-new-constant-interpreter -DNEW_INTERP
872315d02SRichard Smith 
972315d02SRichard Smith namespace std {
1072315d02SRichard Smith #ifndef NO_CONSTEXPR
1172315d02SRichard Smith #define CONSTEXPR constexpr
1272315d02SRichard Smith #else
1372315d02SRichard Smith #define CONSTEXPR
1472315d02SRichard Smith #endif
1572315d02SRichard Smith 
move(T & x)1672315d02SRichard Smith   template<typename T> CONSTEXPR T &&move(T &x) {
1772315d02SRichard Smith     static_assert(T::moveable, "instantiated move"); // expected-error {{no member named 'moveable' in 'B'}}
1872315d02SRichard Smith                                                      // expected-error@-1 {{no member named 'moveable' in 'C'}}
19af0ee617SSirraide                                                      // expected-error@-2 {{no member named 'moveable' in 'D'}}
2072315d02SRichard Smith     return static_cast<T&&>(x);
2172315d02SRichard Smith   }
2272315d02SRichard Smith 
2372315d02SRichard Smith   // Unrelated move functions are not the builtin.
move(T,T)2472315d02SRichard Smith   template<typename T> CONSTEXPR int move(T, T) { return 5; }
2572315d02SRichard Smith 
2672315d02SRichard Smith   template<typename T, bool Rref> struct ref { using type = T&; };
2772315d02SRichard Smith   template<typename T> struct ref<T, true> { using type = T&&; };
2872315d02SRichard Smith 
move_if_noexcept(T & x)2972315d02SRichard Smith   template<typename T> CONSTEXPR auto move_if_noexcept(T &x) -> typename ref<T, noexcept(T(static_cast<T&&>(x)))>::type {
3072315d02SRichard Smith     static_assert(T::moveable, "instantiated move_if_noexcept"); // expected-error {{no member named 'moveable' in 'B'}}
31af0ee617SSirraide                                                                  // expected-error@-1 {{no member named 'moveable' in 'D'}}
3272315d02SRichard Smith     return static_cast<typename ref<T, noexcept(T(static_cast<T&&>(x)))>::type>(x);
3372315d02SRichard Smith   }
3472315d02SRichard Smith 
3572315d02SRichard Smith   template<typename T> struct remove_reference { using type = T; };
3672315d02SRichard Smith   template<typename T> struct remove_reference<T&> { using type = T; };
3772315d02SRichard Smith   template<typename T> struct remove_reference<T&&> { using type = T; };
3872315d02SRichard Smith 
3972315d02SRichard Smith   template<typename T> struct is_lvalue_reference { static constexpr bool value = false; };
4072315d02SRichard Smith   template<typename T> struct is_lvalue_reference<T&> { static constexpr bool value = true; };
4172315d02SRichard Smith 
forward(typename remove_reference<T>::type & x)4272315d02SRichard Smith   template<typename T> CONSTEXPR T &&forward(typename remove_reference<T>::type &x) {
4372315d02SRichard Smith     static_assert(T::moveable, "instantiated forward"); // expected-error {{no member named 'moveable' in 'B'}}
4472315d02SRichard Smith                                                         // expected-error@-1 {{no member named 'moveable' in 'C'}}
45af0ee617SSirraide                                                         // expected-error@-2 {{no member named 'moveable' in 'D'}}
4672315d02SRichard Smith     return static_cast<T&&>(x);
4772315d02SRichard Smith   }
forward(typename remove_reference<T>::type && x)4872315d02SRichard Smith   template<typename T> CONSTEXPR T &&forward(typename remove_reference<T>::type &&x) {
4976476efdSMuhammad Usman Shahid     static_assert(!is_lvalue_reference<T>::value, "should not forward rval as lval"); // expected-error {{static assertion failed}}
5072315d02SRichard Smith     return static_cast<T&&>(x);
5172315d02SRichard Smith   }
5272315d02SRichard Smith 
530fd9c37dSAlexander Shaposhnikov   template <class T> struct is_const { static constexpr bool value = false; };
540fd9c37dSAlexander Shaposhnikov   template <class T> struct is_const<const T> { static constexpr bool value = true; };
550fd9c37dSAlexander Shaposhnikov 
560fd9c37dSAlexander Shaposhnikov   template <bool B, class T, class F> struct conditional { using type = T; };
570fd9c37dSAlexander Shaposhnikov   template <class T, class F> struct conditional<false, T, F> { using type = F; };
580fd9c37dSAlexander Shaposhnikov 
590fd9c37dSAlexander Shaposhnikov   template <class U, class T>
600fd9c37dSAlexander Shaposhnikov   using CopyConst = typename conditional<
610fd9c37dSAlexander Shaposhnikov           is_const<remove_reference<U>>::value,
620fd9c37dSAlexander Shaposhnikov           const T, T>::type;
630fd9c37dSAlexander Shaposhnikov 
640fd9c37dSAlexander Shaposhnikov   template <class U, class T>
650fd9c37dSAlexander Shaposhnikov   using OverrideRef = typename conditional<
660fd9c37dSAlexander Shaposhnikov           is_lvalue_reference<U &&>::value,
670fd9c37dSAlexander Shaposhnikov           typename remove_reference<T>::type &,
680fd9c37dSAlexander Shaposhnikov           typename remove_reference<T>::type &&>::type;
690fd9c37dSAlexander Shaposhnikov 
700fd9c37dSAlexander Shaposhnikov   template <class U, class T>
710fd9c37dSAlexander Shaposhnikov   using ForwardLikeRetType = OverrideRef<U &&, CopyConst<U, T>>;
720fd9c37dSAlexander Shaposhnikov 
730fd9c37dSAlexander Shaposhnikov   template <class U, class T>
forward_like(T && t)740fd9c37dSAlexander Shaposhnikov   CONSTEXPR auto forward_like(T &&t) -> ForwardLikeRetType<U, T> {
750fd9c37dSAlexander Shaposhnikov     using TT = typename remove_reference<T>::type;
760fd9c37dSAlexander Shaposhnikov     static_assert(TT::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
77af0ee617SSirraide                                                           // expected-error@-1 {{no member named 'moveable' in 'D'}}
780fd9c37dSAlexander Shaposhnikov     return static_cast<ForwardLikeRetType<U, T>>(t);
790fd9c37dSAlexander Shaposhnikov   }
800fd9c37dSAlexander Shaposhnikov 
as_const(T & x)8172315d02SRichard Smith   template<typename T> CONSTEXPR const T &as_const(T &x) {
8272315d02SRichard Smith     static_assert(T::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
83af0ee617SSirraide                                                          // expected-error@-1 {{no member named 'moveable' in 'D'}}
8472315d02SRichard Smith     return x;
8572315d02SRichard Smith   }
8672315d02SRichard Smith 
addressof(T & x)8772315d02SRichard Smith   template<typename T> CONSTEXPR T *addressof(T &x) {
8872315d02SRichard Smith     static_assert(T::moveable, "instantiated addressof"); // expected-error {{no member named 'moveable' in 'B'}}
89af0ee617SSirraide                                                           // expected-error@-1 {{no member named 'moveable' in 'D'}}
9072315d02SRichard Smith     return __builtin_addressof(x);
9172315d02SRichard Smith   }
9272315d02SRichard Smith 
__addressof(T & x)9372315d02SRichard Smith   template<typename T> CONSTEXPR T *__addressof(T &x) {
9472315d02SRichard Smith     static_assert(T::moveable, "instantiated __addressof"); // expected-error {{no member named 'moveable' in 'B'}}
95af0ee617SSirraide                                                             // expected-error@-1 {{no member named 'moveable' in 'D'}}
9672315d02SRichard Smith     return __builtin_addressof(x);
9772315d02SRichard Smith   }
9872315d02SRichard Smith }
9972315d02SRichard Smith 
10072315d02SRichard Smith // Note: this doesn't have a 'moveable' member. Instantiation of the above
10172315d02SRichard Smith // functions will fail if it's attempted.
10272315d02SRichard Smith struct A {};
f(A a)10372315d02SRichard Smith constexpr bool f(A a) { // #f
10472315d02SRichard Smith   A &&move = std::move(a); // #call
10572315d02SRichard Smith   A &&move_if_noexcept = std::move_if_noexcept(a);
10672315d02SRichard Smith   A &&forward1 = std::forward<A>(a);
10772315d02SRichard Smith   A &forward2 = std::forward<A&>(a);
10872315d02SRichard Smith   const A &as_const = std::as_const(a);
10972315d02SRichard Smith   A *addressof = std::addressof(a);
11072315d02SRichard Smith   A *addressof2 = std::__addressof(a);
11172315d02SRichard Smith   return &move == &a && &move_if_noexcept == &a &&
11272315d02SRichard Smith          &forward1 == &a && &forward2 == &a &&
11372315d02SRichard Smith          &as_const == &a && addressof == &a &&
11472315d02SRichard Smith          addressof2 == &a && std::move(a, a) == 5;
11572315d02SRichard Smith }
11672315d02SRichard Smith 
11772315d02SRichard Smith #ifndef NO_CONSTEXPR
11872315d02SRichard Smith static_assert(f({}), "should be constexpr");
119*47df3912STimm Baeder #elif !defined(NEW_INTERP)
12072315d02SRichard Smith // expected-error@#f {{never produces a constant expression}}
12172315d02SRichard Smith // expected-note@#call {{}}
12272315d02SRichard Smith #endif
12372315d02SRichard Smith 
forward_rval_as_lval()12472315d02SRichard Smith A &forward_rval_as_lval() {
12572315d02SRichard Smith   std::forward<A&&>(A()); // expected-warning {{const attribute}}
12631b0be4eSAlexander Shaposhnikov   return std::forward<A&>(A()); // expected-note {{instantiation of}} expected-warning {{returning reference}}
12772315d02SRichard Smith }
12872315d02SRichard Smith 
12972315d02SRichard Smith struct B {};
130af0ee617SSirraide B &&(*pMove)(B&) = std::move;                            // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
131af0ee617SSirraide B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept;     // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
132af0ee617SSirraide B &&(*pForward)(B&) = &std::forward<B>;                  // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
133af0ee617SSirraide B &&(*pForwardLike)(B&) = &std::forward_like<int&&, B&>; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
134af0ee617SSirraide const B &(*pAsConst)(B&) = &std::as_const;               // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
135af0ee617SSirraide B *(*pAddressof)(B&) = &std::addressof;                  // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
136af0ee617SSirraide B *(*pUnderUnderAddressof)(B&) = &std::__addressof;      // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
13772315d02SRichard Smith int (*pUnrelatedMove)(B, B) = std::move;
13872315d02SRichard Smith 
13972315d02SRichard Smith struct C {};
140af0ee617SSirraide C &&(&rMove)(C&) = std::move;          // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
141af0ee617SSirraide C &&(&rForward)(C&) = std::forward<C>; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
14272315d02SRichard Smith int (&rUnrelatedMove)(B, B) = std::move;
14372315d02SRichard Smith 
attribute_const()14472315d02SRichard Smith void attribute_const() {
14572315d02SRichard Smith   int n;
14672315d02SRichard Smith   std::move(n); // expected-warning {{ignoring return value}}
14772315d02SRichard Smith   std::move_if_noexcept(n); // expected-warning {{ignoring return value}}
14872315d02SRichard Smith   std::forward<int>(n); // expected-warning {{ignoring return value}}
1490fd9c37dSAlexander Shaposhnikov   std::forward_like<float&&>(n); // expected-warning {{ignoring return value}}
15072315d02SRichard Smith   std::addressof(n); // expected-warning {{ignoring return value}}
15172315d02SRichard Smith   std::__addressof(n); // expected-warning {{ignoring return value}}
15272315d02SRichard Smith   std::as_const(n); // expected-warning {{ignoring return value}}
15372315d02SRichard Smith }
15472315d02SRichard Smith 
155af0ee617SSirraide struct D {
156af0ee617SSirraide   void* operator new(__SIZE_TYPE__, D&&(*)(D&));
157af0ee617SSirraide   void* operator new(__SIZE_TYPE__, D*(*)(D&));
158af0ee617SSirraide   void* operator new(__SIZE_TYPE__, const D&(*)(D&));
159af0ee617SSirraide };
160af0ee617SSirraide 
placement_new()161af0ee617SSirraide void placement_new() {
162af0ee617SSirraide   new (std::move<D>) D;             // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
163af0ee617SSirraide   new (std::move_if_noexcept<D>) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
164af0ee617SSirraide   new (std::forward<D>) D;          // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
165af0ee617SSirraide   new (std::forward_like<D>) D;     // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
166af0ee617SSirraide   new (std::addressof<D>) D;        // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
167af0ee617SSirraide   new (std::__addressof<D>) D;      // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
168af0ee617SSirraide   new (std::as_const<D>) D;         // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
169af0ee617SSirraide }
170af0ee617SSirraide 
17172315d02SRichard Smith namespace std {
17272315d02SRichard Smith   template<typename T> int &move(T);
17372315d02SRichard Smith }
17472315d02SRichard Smith int bad_signature = std::move(0); // expected-error {{unsupported signature for 'std::move<int>'}}
175