This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG0fd9c37d8cf2: [Clang] Treat `std::forward_like` as builtin (authored by alexander-shaposhnikov).
Changed prior to commit: https://reviews.llvm.org/D142430?vs=491598&id=493042#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D142430/new/ https://reviews.llvm.org/D142430 Files: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/Builtins.def clang/lib/AST/ExprConstant.cpp clang/lib/Analysis/BodyFarm.cpp clang/lib/CodeGen/CGBuiltin.cpp clang/lib/Sema/SemaChecking.cpp clang/lib/Sema/SemaDecl.cpp clang/test/CodeGenCXX/builtin-std-move.cpp clang/test/SemaCXX/attr-lifetimebound.cpp clang/test/SemaCXX/builtin-std-move-nobuiltin.cpp clang/test/SemaCXX/builtin-std-move.cpp
Index: clang/test/SemaCXX/builtin-std-move.cpp =================================================================== --- clang/test/SemaCXX/builtin-std-move.cpp +++ clang/test/SemaCXX/builtin-std-move.cpp @@ -43,6 +43,33 @@ return static_cast<T&&>(x); } + template <class T> struct is_const { static constexpr bool value = false; }; + template <class T> struct is_const<const T> { static constexpr bool value = true; }; + + template <bool B, class T, class F> struct conditional { using type = T; }; + template <class T, class F> struct conditional<false, T, F> { using type = F; }; + + template <class U, class T> + using CopyConst = typename conditional< + is_const<remove_reference<U>>::value, + const T, T>::type; + + template <class U, class T> + using OverrideRef = typename conditional< + is_lvalue_reference<U &&>::value, + typename remove_reference<T>::type &, + typename remove_reference<T>::type &&>::type; + + template <class U, class T> + using ForwardLikeRetType = OverrideRef<U &&, CopyConst<U, T>>; + + template <class U, class T> + CONSTEXPR auto forward_like(T &&t) -> ForwardLikeRetType<U, T> { + using TT = typename remove_reference<T>::type; + static_assert(TT::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}} + return static_cast<ForwardLikeRetType<U, T>>(t); + } + template<typename T> CONSTEXPR const T &as_const(T &x) { static_assert(T::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}} return x; @@ -92,14 +119,15 @@ B &&(*pMove)(B&) = std::move; // #1 expected-note {{instantiation of}} B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept; // #2 expected-note {{instantiation of}} B &&(*pForward)(B&) = &std::forward<B>; // #3 expected-note {{instantiation of}} -const B &(*pAsConst)(B&) = &std::as_const; // #4 expected-note {{instantiation of}} -B *(*pAddressof)(B&) = &std::addressof; // #5 expected-note {{instantiation of}} -B *(*pUnderUnderAddressof)(B&) = &std::__addressof; // #6 expected-note {{instantiation of}} +B &&(*pForwardLike)(B&) = &std::forward_like<int&&, B&>; // #4 expected-note {{instantiation of}} +const B &(*pAsConst)(B&) = &std::as_const; // #5 expected-note {{instantiation of}} +B *(*pAddressof)(B&) = &std::addressof; // #6 expected-note {{instantiation of}} +B *(*pUnderUnderAddressof)(B&) = &std::__addressof; // #7 expected-note {{instantiation of}} int (*pUnrelatedMove)(B, B) = std::move; struct C {}; -C &&(&rMove)(C&) = std::move; // #7 expected-note {{instantiation of}} -C &&(&rForward)(C&) = std::forward<C>; // #8 expected-note {{instantiation of}} +C &&(&rMove)(C&) = std::move; // #8 expected-note {{instantiation of}} +C &&(&rForward)(C&) = std::forward<C>; // #9 expected-note {{instantiation of}} int (&rUnrelatedMove)(B, B) = std::move; #if __cplusplus <= 201703L @@ -111,6 +139,7 @@ // expected-warning@#6 {{non-addressable}} // expected-warning@#7 {{non-addressable}} // expected-warning@#8 {{non-addressable}} +// expected-warning@#9 {{non-addressable}} #else // expected-error@#1 {{non-addressable}} // expected-error@#2 {{non-addressable}} @@ -120,6 +149,7 @@ // expected-error@#6 {{non-addressable}} // expected-error@#7 {{non-addressable}} // expected-error@#8 {{non-addressable}} +// expected-error@#9 {{non-addressable}} #endif void attribute_const() { @@ -127,6 +157,7 @@ std::move(n); // expected-warning {{ignoring return value}} std::move_if_noexcept(n); // expected-warning {{ignoring return value}} std::forward<int>(n); // expected-warning {{ignoring return value}} + std::forward_like<float&&>(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}} Index: clang/test/SemaCXX/builtin-std-move-nobuiltin.cpp =================================================================== --- clang/test/SemaCXX/builtin-std-move-nobuiltin.cpp +++ clang/test/SemaCXX/builtin-std-move-nobuiltin.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -std=c++20 -verify %s -DBUILTIN=builtin // RUN: %clang_cc1 -std=c++20 -verify %s -DBUILTIN=nobuiltin -fno-builtin -// RUN: %clang_cc1 -std=c++20 -verify %s -DBUILTIN=nobuiltin -fno-builtin-std-move -fno-builtin-std-move_if_noexcept -fno-builtin-std-forward +// RUN: %clang_cc1 -std=c++20 -verify %s -DBUILTIN=nobuiltin -fno-builtin-std-move -fno-builtin-std-move_if_noexcept -fno-builtin-std-forward -fno-builtin-std-forward_like // RUN: %clang_cc1 -std=c++20 -verify %s -DBUILTIN=nobuiltin -ffreestanding // expected-no-diagnostics @@ -10,6 +10,7 @@ template<typename T> constexpr T &&move(T &x) { return (T&&)nobuiltin; } template<typename T> constexpr T &&move_if_noexcept(T &x) { return (T&&)nobuiltin; } template<typename T> constexpr T &&forward(T &x) { return (T&&)nobuiltin; } + template<typename U, typename T> constexpr T &&forward_like(T &X) { return (T&&)nobuiltin; } } template<typename T> constexpr T *addr(T &&r) { return &r; } @@ -18,3 +19,4 @@ static_assert(addr(std::move(builtin)) == &BUILTIN); static_assert(addr(std::move_if_noexcept(builtin)) == &BUILTIN); static_assert(addr(std::forward(builtin)) == &BUILTIN); +static_assert(addr(std::forward_like<int&>(builtin)) == &BUILTIN); Index: clang/test/SemaCXX/attr-lifetimebound.cpp =================================================================== --- clang/test/SemaCXX/attr-lifetimebound.cpp +++ clang/test/SemaCXX/attr-lifetimebound.cpp @@ -151,6 +151,48 @@ using type = typename remove_reference<T>::type &&; }; +template <class T> struct is_lvalue_reference { + static constexpr bool value = false; +}; + +template <class T> struct is_lvalue_reference<T &> { + static constexpr bool value = true; +}; + +template <class T> struct is_const { + static constexpr bool value = false; +}; + +template <class T> struct is_const<const T> { + static constexpr bool value = true; +}; + +template <bool B, class T, class F> struct conditional { + using type = T; +}; + +template <class T, class F> struct conditional<false, T, F> { + using type = F; +}; + +template <class U, class T> +using CopyConst = typename conditional<is_const<remove_reference<U>>::value, + const T, T>::type; + +template <class U, class T> +using OverrideRef = + typename conditional<is_lvalue_reference<U &&>::value, + typename remove_reference<T>::type &, + typename remove_reference<T>::type &&>::type; + +template <class U, class T> +using ForwardLikeRetType = OverrideRef<U &&, CopyConst<U, T>>; + +template <class U> +constexpr auto forward_like(auto &&t) -> ForwardLikeRetType<U, decltype(t)> { + return static_cast<ForwardLikeRetType<U, decltype(t)>>(t); +} + template <class T> auto move_if_noexcept(T &t) -> typename PickRef<T, noexcept(T(static_cast<T &&>(t)))>::type { @@ -177,6 +219,9 @@ S &&Forward = std::forward<S &&>(S{}); // expected-warning {{temporary bound to local reference 'Forward' will be destroyed at the end of the full-expression}} S ForwardOk = std::forward<S &&>(S{}); + S &&ForwardLike = std::forward_like<int&&>(S{}); // expected-warning {{temporary bound to local reference 'ForwardLike' will be destroyed at the end of the full-expression}} + S ForwardLikeOk = std::forward_like<int&&>(S{}); + const S &Const = std::as_const(S{}.self()); // expected-warning {{temporary bound to local reference 'Const' will be destroyed at the end of the full-expression}} const S ConstOk = std::as_const(S{}.self()); Index: clang/test/CodeGenCXX/builtin-std-move.cpp =================================================================== --- clang/test/CodeGenCXX/builtin-std-move.cpp +++ clang/test/CodeGenCXX/builtin-std-move.cpp @@ -4,6 +4,7 @@ template<typename T> constexpr T &&move(T &val) { return static_cast<T&&>(val); } template<typename T> constexpr T &&move_if_noexcept(T &val); template<typename T> constexpr T &&forward(T &val); + template<typename U, typename T> constexpr T &&forward_like(T &&val); template<typename T> constexpr const T &as_const(T &val); // Not the builtin. @@ -23,6 +24,8 @@ T &&move_if_noexcept_a = std::move_if_noexcept(a); // CHECK-DAG: @forward_a = constant ptr @a T &forward_a = std::forward<T&>(a); +// CHECK-DAG: @forward_like_a = constant ptr @a +T &forward_like_a = std::forward_like<int&>(a); // Check emission of a non-constant call. // CHECK-LABEL: define {{.*}} void @test @@ -39,6 +42,9 @@ take(std::forward<T&&>(t)); // CHECK: %3 = load ptr, ptr %[[T_REF]] // CHECK: call void @take_lval(ptr {{.*}} %3) + take_lval(std::forward_like<int&>(t)); + // CHECK: %4 = load ptr, ptr %[[T_REF]] + // CHECK: call void @take_lval(ptr {{.*}} %4) take_lval(std::as_const<T&&>(t)); // CHECK: call {{.*}} @_ZSt4moveI1TS0_ET_T0_S2_S1_ Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -9556,6 +9556,7 @@ case Builtin::BIaddressof: case Builtin::BI__addressof: case Builtin::BIforward: + case Builtin::BIforward_like: case Builtin::BImove: case Builtin::BImove_if_noexcept: case Builtin::BIas_const: { @@ -16196,6 +16197,7 @@ case Builtin::BI__builtin_addressof: case Builtin::BIas_const: case Builtin::BIforward: + case Builtin::BIforward_like: case Builtin::BImove: case Builtin::BImove_if_noexcept: if (ParmVarDecl *P = FD->getParamDecl(0u); Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -2471,6 +2471,7 @@ case Builtin::BIaddressof: case Builtin::BI__addressof: case Builtin::BIforward: + case Builtin::BIforward_like: case Builtin::BImove: case Builtin::BImove_if_noexcept: case Builtin::BIas_const: { Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -4674,6 +4674,7 @@ case Builtin::BImove: case Builtin::BImove_if_noexcept: case Builtin::BIforward: + case Builtin::BIforward_like: case Builtin::BIas_const: return RValue::get(EmitLValue(E->getArg(0)).getPointer(*this)); case Builtin::BI__GetExceptionInfo: { Index: clang/lib/Analysis/BodyFarm.cpp =================================================================== --- clang/lib/Analysis/BodyFarm.cpp +++ clang/lib/Analysis/BodyFarm.cpp @@ -717,6 +717,7 @@ switch (BuiltinID) { case Builtin::BIas_const: case Builtin::BIforward: + case Builtin::BIforward_like: case Builtin::BImove: case Builtin::BImove_if_noexcept: FF = create_std_move_forward; Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -8339,6 +8339,7 @@ return false; case Builtin::BIas_const: case Builtin::BIforward: + case Builtin::BIforward_like: case Builtin::BImove: case Builtin::BImove_if_noexcept: if (cast<FunctionDecl>(E->getCalleeDecl())->isConstexpr()) Index: clang/include/clang/Basic/Builtins.def =================================================================== --- clang/include/clang/Basic/Builtins.def +++ clang/include/clang/Basic/Builtins.def @@ -1565,6 +1565,7 @@ LANGBUILTIN(__addressof, "v*v&", "zfncTE", CXX_LANG) LIBBUILTIN(as_const, "v&v&", "zfncThE", UTILITY, CXX_LANG) LIBBUILTIN(forward, "v&v&", "zfncThE", UTILITY, CXX_LANG) +LIBBUILTIN(forward_like, "v&v&", "zfncThE", UTILITY, CXX_LANG) LIBBUILTIN(move, "v&v&", "zfncThE", UTILITY, CXX_LANG) LIBBUILTIN(move_if_noexcept, "v&v&", "zfncThE", UTILITY, CXX_LANG) Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -97,6 +97,9 @@ C++ Language Changes in Clang ----------------------------- +- Improved ``-O0`` code generation for calls to ``std::forward_like``. Similarly to + ``std::move, std::forward`` et al. it is now treated as a compiler builtin and implemented + directly rather than instantiating the definition from the standard library. C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits