mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 07:31:28 +00:00
[Clang] Treat std::forward_like
as builtin
This diff extends D123345 by adding support for std::forward_like. Test plan: ninja check-clang check-clang-tools check-llvm Differential revision: https://reviews.llvm.org/D142430
This commit is contained in:
parent
526966d07d
commit
0fd9c37d8c
@ -97,6 +97,9 @@ C2x Feature Support
|
||||
|
||||
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
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -1565,6 +1565,7 @@ LIBBUILTIN(addressof, "v*v&", "zfncThE", MEMORY, CXX_LANG)
|
||||
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)
|
||||
|
||||
|
@ -8339,6 +8339,7 @@ bool LValueExprEvaluator::VisitCallExpr(const CallExpr *E) {
|
||||
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())
|
||||
|
@ -717,6 +717,7 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
|
||||
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;
|
||||
|
@ -4674,6 +4674,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
|
||||
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: {
|
||||
|
@ -2471,6 +2471,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
|
||||
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: {
|
||||
|
@ -9556,6 +9556,7 @@ static bool isStdBuiltin(ASTContext &Ctx, FunctionDecl *FD,
|
||||
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 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
|
||||
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);
|
||||
|
@ -4,6 +4,7 @@ namespace std {
|
||||
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_a = std::move(a);
|
||||
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 @@ extern "C" void test(T &t) {
|
||||
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_
|
||||
|
@ -151,6 +151,48 @@ template <class T> struct PickRef<T, true> {
|
||||
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 @@ namespace move_forward_et_al_examples {
|
||||
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());
|
||||
|
||||
|
@ -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 @@ namespace std {
|
||||
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 @@ int builtin;
|
||||
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);
|
||||
|
@ -43,6 +43,33 @@ namespace std {
|
||||
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 @@ struct B {};
|
||||
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 @@ int (&rUnrelatedMove)(B, B) = std::move;
|
||||
// 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 @@ int (&rUnrelatedMove)(B, B) = std::move;
|
||||
// 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 @@ void attribute_const() {
|
||||
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}}
|
||||
|
Loading…
Reference in New Issue
Block a user