// RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s // RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s -DNO_CONSTEXPR // RUN: %clang_cc1 -std=c++20 -verify=cxx20,expected %s namespace std { #ifndef NO_CONSTEXPR #define CONSTEXPR constexpr #else #define CONSTEXPR #endif template CONSTEXPR T &&move(T &x) { static_assert(T::moveable, "instantiated move"); // expected-error {{no member named 'moveable' in 'B'}} // expected-error@-1 {{no member named 'moveable' in 'C'}} // expected-error@-2 {{no member named 'moveable' in 'D'}} return static_cast(x); } // Unrelated move functions are not the builtin. template CONSTEXPR int move(T, T) { return 5; } template struct ref { using type = T&; }; template struct ref { using type = T&&; }; template CONSTEXPR auto move_if_noexcept(T &x) -> typename ref(x)))>::type { static_assert(T::moveable, "instantiated move_if_noexcept"); // expected-error {{no member named 'moveable' in 'B'}} // expected-error@-1 {{no member named 'moveable' in 'D'}} return static_cast(x)))>::type>(x); } template struct remove_reference { using type = T; }; template struct remove_reference { using type = T; }; template struct remove_reference { using type = T; }; template struct is_lvalue_reference { static constexpr bool value = false; }; template struct is_lvalue_reference { static constexpr bool value = true; }; template CONSTEXPR T &&forward(typename remove_reference::type &x) { static_assert(T::moveable, "instantiated forward"); // expected-error {{no member named 'moveable' in 'B'}} // expected-error@-1 {{no member named 'moveable' in 'C'}} // expected-error@-2 {{no member named 'moveable' in 'D'}} return static_cast(x); } template CONSTEXPR T &&forward(typename remove_reference::type &&x) { static_assert(!is_lvalue_reference::value, "should not forward rval as lval"); // expected-error {{static assertion failed}} return static_cast(x); } template struct is_const { static constexpr bool value = false; }; template struct is_const { static constexpr bool value = true; }; template struct conditional { using type = T; }; template struct conditional { using type = F; }; template using CopyConst = typename conditional< is_const>::value, const T, T>::type; template using OverrideRef = typename conditional< is_lvalue_reference::value, typename remove_reference::type &, typename remove_reference::type &&>::type; template using ForwardLikeRetType = OverrideRef>; template CONSTEXPR auto forward_like(T &&t) -> ForwardLikeRetType { using TT = typename remove_reference::type; static_assert(TT::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}} // expected-error@-1 {{no member named 'moveable' in 'D'}} return static_cast>(t); } template CONSTEXPR const T &as_const(T &x) { static_assert(T::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}} // expected-error@-1 {{no member named 'moveable' in 'D'}} return x; } template CONSTEXPR T *addressof(T &x) { static_assert(T::moveable, "instantiated addressof"); // expected-error {{no member named 'moveable' in 'B'}} // expected-error@-1 {{no member named 'moveable' in 'D'}} return __builtin_addressof(x); } template CONSTEXPR T *__addressof(T &x) { static_assert(T::moveable, "instantiated __addressof"); // expected-error {{no member named 'moveable' in 'B'}} // expected-error@-1 {{no member named 'moveable' in 'D'}} return __builtin_addressof(x); } } // Note: this doesn't have a 'moveable' member. Instantiation of the above // functions will fail if it's attempted. struct A {}; constexpr bool f(A a) { // #f A &&move = std::move(a); // #call A &&move_if_noexcept = std::move_if_noexcept(a); A &&forward1 = std::forward(a); A &forward2 = std::forward(a); const A &as_const = std::as_const(a); A *addressof = std::addressof(a); A *addressof2 = std::__addressof(a); return &move == &a && &move_if_noexcept == &a && &forward1 == &a && &forward2 == &a && &as_const == &a && addressof == &a && addressof2 == &a && std::move(a, a) == 5; } #ifndef NO_CONSTEXPR static_assert(f({}), "should be constexpr"); #else // expected-error@#f {{never produces a constant expression}} // expected-note@#call {{}} #endif A &forward_rval_as_lval() { std::forward(A()); // expected-warning {{const attribute}} return std::forward(A()); // expected-note {{instantiation of}} expected-warning {{returning reference}} } struct B {}; B &&(*pMove)(B&) = std::move; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} B &&(*pForward)(B&) = &std::forward; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} B &&(*pForwardLike)(B&) = &std::forward_like; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} const B &(*pAsConst)(B&) = &std::as_const; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} B *(*pAddressof)(B&) = &std::addressof; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} B *(*pUnderUnderAddressof)(B&) = &std::__addressof; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} int (*pUnrelatedMove)(B, B) = std::move; struct C {}; C &&(&rMove)(C&) = std::move; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} C &&(&rForward)(C&) = std::forward; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} int (&rUnrelatedMove)(B, B) = std::move; void attribute_const() { int n; std::move(n); // expected-warning {{ignoring return value}} std::move_if_noexcept(n); // expected-warning {{ignoring return value}} std::forward(n); // expected-warning {{ignoring return value}} std::forward_like(n); // expected-warning {{ignoring return value}} std::addressof(n); // expected-warning {{ignoring return value}} std::__addressof(n); // expected-warning {{ignoring return value}} std::as_const(n); // expected-warning {{ignoring return value}} } struct D { void* operator new(__SIZE_TYPE__, D&&(*)(D&)); void* operator new(__SIZE_TYPE__, D*(*)(D&)); void* operator new(__SIZE_TYPE__, const D&(*)(D&)); }; void placement_new() { new (std::move) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} new (std::move_if_noexcept) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} new (std::forward) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} new (std::forward_like) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} new (std::addressof) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} new (std::__addressof) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} new (std::as_const) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}} } namespace std { template int &move(T); } int bad_signature = std::move(0); // expected-error {{unsupported signature for 'std::move'}}