[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
https://github.com/tbaederr closed https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/70772 >From 8449070d0cec2ad120c9d8a36a72594d595b7fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Tue, 31 Oct 2023 07:17:16 +0100 Subject: [PATCH] [clang][Interp] Handle std::move etc. builtins --- clang/lib/AST/Interp/ByteCodeExprGen.h | 9 +-- clang/lib/AST/Interp/Context.h | 13 +++- clang/lib/AST/Interp/Interp.cpp | 2 +- clang/lib/AST/Interp/InterpBuiltin.cpp | 22 +- clang/test/AST/Interp/functions.cpp | 89 + clang/test/SemaCXX/builtin-std-move.cpp | 6 +- 6 files changed, 129 insertions(+), 12 deletions(-) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index 893b75b028b6f..315169d487cd4 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -128,15 +128,8 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, // If the function does not exist yet, it is compiled. const Function *getFunction(const FunctionDecl *FD); - /// Classifies a type. std::optional classify(const Expr *E) const { -if (E->isGLValue()) { - if (E->getType()->isFunctionType()) -return PT_FnPtr; - return PT_Ptr; -} - -return classify(E->getType()); +return Ctx.classify(E); } std::optional classify(QualType Ty) const { return Ctx.classify(Ty); diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index ab83a8d132246..c7620921e467e 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -70,9 +70,20 @@ class Context final { /// Return the size of T in bits. uint32_t getBitWidth(QualType T) const { return Ctx.getIntWidth(T); } - /// Classifies an expression. + /// Classifies a type. std::optional classify(QualType T) const; + /// Classifies an expression. + std::optional classify(const Expr *E) const { +if (E->isGLValue()) { + if (E->getType()->isFunctionType()) +return PT_FnPtr; + return PT_Ptr; +} + +return classify(E->getType()); + } + const CXXMethodDecl * getOverridingFunction(const CXXRecordDecl *DynamicDecl, const CXXRecordDecl *StaticDecl, diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index be9ed81af69ec..4c3184aec9968 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -141,7 +141,7 @@ static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { namespace clang { namespace interp { static void popArg(InterpState &S, const Expr *Arg) { - PrimType Ty = S.getContext().classify(Arg->getType()).value_or(PT_Ptr); + PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr); TYPE_SWITCH(Ty, S.Stk.discard()); } diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 754ca96b0c645..280aa39398c8e 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -634,12 +634,23 @@ static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_move(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + + PrimType ArgT = S.getContext().classify(Call->getArg(0)).value_or(PT_Ptr); + + TYPE_SWITCH(ArgT, const T &Arg = S.Stk.peek(); S.Stk.push(Arg);); + + return Func->getDecl()->isConstexpr(); +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { InterpFrame *Frame = S.Current; APValue Dummy; - std::optional ReturnT = S.getContext().classify(Call->getType()); + std::optional ReturnT = S.getContext().classify(Call); // If classify failed, we assume void. assert(ReturnT || Call->getType()->isVoidType()); @@ -848,6 +859,15 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BIas_const: + case Builtin::BIforward: + case Builtin::BIforward_like: + case Builtin::BImove: + case Builtin::BImove_if_noexcept: +if (!interp__builtin_move(S, OpPC, Frame, F, Call)) + return false; +break; + default: return false; } diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 75f3c5d192b2c..6e995ce704e39 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -413,3 +413,92 @@ namespace AddressOf { constexpr _Complex float F = {3, 4}; static_assert(__builtin_addressof(F) == &F, ""); } + +namespace std { +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template +constexpr typename std::remove_ref
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/70772 >From 7f4cb1f727a497c6da1fc3f4740522ff5adb3964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Tue, 31 Oct 2023 07:17:16 +0100 Subject: [PATCH] [clang][Interp] Handle std::move etc. builtins --- clang/lib/AST/Interp/ByteCodeExprGen.h | 9 +-- clang/lib/AST/Interp/Context.h | 13 +++- clang/lib/AST/Interp/Interp.cpp | 2 +- clang/lib/AST/Interp/InterpBuiltin.cpp | 22 +- clang/test/AST/Interp/functions.cpp | 89 + clang/test/SemaCXX/builtin-std-move.cpp | 6 +- 6 files changed, 129 insertions(+), 12 deletions(-) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index 63ea8292b587675..9fc8ce13b1d7fda 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -128,15 +128,8 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, // If the function does not exist yet, it is compiled. const Function *getFunction(const FunctionDecl *FD); - /// Classifies a type. std::optional classify(const Expr *E) const { -if (E->isGLValue()) { - if (E->getType()->isFunctionType()) -return PT_FnPtr; - return PT_Ptr; -} - -return classify(E->getType()); +return Ctx.classify(E); } std::optional classify(QualType Ty) const { return Ctx.classify(Ty); diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index ab83a8d13224670..c7620921e467e71 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -70,9 +70,20 @@ class Context final { /// Return the size of T in bits. uint32_t getBitWidth(QualType T) const { return Ctx.getIntWidth(T); } - /// Classifies an expression. + /// Classifies a type. std::optional classify(QualType T) const; + /// Classifies an expression. + std::optional classify(const Expr *E) const { +if (E->isGLValue()) { + if (E->getType()->isFunctionType()) +return PT_FnPtr; + return PT_Ptr; +} + +return classify(E->getType()); + } + const CXXMethodDecl * getOverridingFunction(const CXXRecordDecl *DynamicDecl, const CXXRecordDecl *StaticDecl, diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 807b860f3565d3a..38861253b217323 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -141,7 +141,7 @@ static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { namespace clang { namespace interp { static void popArg(InterpState &S, const Expr *Arg) { - PrimType Ty = S.getContext().classify(Arg->getType()).value_or(PT_Ptr); + PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr); TYPE_SWITCH(Ty, S.Stk.discard()); } diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 754ca96b0c645e5..280aa39398c8e9a 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -634,12 +634,23 @@ static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_move(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + + PrimType ArgT = S.getContext().classify(Call->getArg(0)).value_or(PT_Ptr); + + TYPE_SWITCH(ArgT, const T &Arg = S.Stk.peek(); S.Stk.push(Arg);); + + return Func->getDecl()->isConstexpr(); +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { InterpFrame *Frame = S.Current; APValue Dummy; - std::optional ReturnT = S.getContext().classify(Call->getType()); + std::optional ReturnT = S.getContext().classify(Call); // If classify failed, we assume void. assert(ReturnT || Call->getType()->isVoidType()); @@ -848,6 +859,15 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BIas_const: + case Builtin::BIforward: + case Builtin::BIforward_like: + case Builtin::BImove: + case Builtin::BImove_if_noexcept: +if (!interp__builtin_move(S, OpPC, Frame, F, Call)) + return false; +break; + default: return false; } diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 75f3c5d192b2cf2..6e995ce704e3949 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -413,3 +413,92 @@ namespace AddressOf { constexpr _Complex float F = {3, 4}; static_assert(__builtin_addressof(F) == &F, ""); } + +namespace std { +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template +constexpr type
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
@@ -378,3 +378,92 @@ namespace Packs { static_assert(foo() == 2, ""); static_assert(foo<>() == 0, ""); } + +namespace std { +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template +constexpr typename std::remove_reference::type&& move(T &&t) noexcept { + return static_cast::type &&>(t); +} +} +/// The std::move declaration above gets translated to a builtin function. +namespace Move { tbaederr wrote: I've enabled `test/SemaCXX/builtin-std-move.cpp` with the new interpreter. https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/70772 >From c6c7d246b334a95306cda410e7d115353acb7c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Tue, 31 Oct 2023 07:17:16 +0100 Subject: [PATCH] [clang][Interp] Handle std::move etc. builtins --- clang/lib/AST/Interp/ByteCodeExprGen.h | 9 +-- clang/lib/AST/Interp/Context.h | 13 +++- clang/lib/AST/Interp/Interp.cpp | 2 +- clang/lib/AST/Interp/InterpBuiltin.cpp | 22 +- clang/test/AST/Interp/functions.cpp | 89 + clang/test/SemaCXX/builtin-std-move.cpp | 6 +- 6 files changed, 129 insertions(+), 12 deletions(-) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index df4cb736299cb62..907e6f1f764502c 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -128,15 +128,8 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, // If the function does not exist yet, it is compiled. const Function *getFunction(const FunctionDecl *FD); - /// Classifies a type. std::optional classify(const Expr *E) const { -if (E->isGLValue()) { - if (E->getType()->isFunctionType()) -return PT_FnPtr; - return PT_Ptr; -} - -return classify(E->getType()); +return Ctx.classify(E); } std::optional classify(QualType Ty) const { return Ctx.classify(Ty); diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index ab83a8d13224670..c7620921e467e71 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -70,9 +70,20 @@ class Context final { /// Return the size of T in bits. uint32_t getBitWidth(QualType T) const { return Ctx.getIntWidth(T); } - /// Classifies an expression. + /// Classifies a type. std::optional classify(QualType T) const; + /// Classifies an expression. + std::optional classify(const Expr *E) const { +if (E->isGLValue()) { + if (E->getType()->isFunctionType()) +return PT_FnPtr; + return PT_Ptr; +} + +return classify(E->getType()); + } + const CXXMethodDecl * getOverridingFunction(const CXXRecordDecl *DynamicDecl, const CXXRecordDecl *StaticDecl, diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 807b860f3565d3a..38861253b217323 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -141,7 +141,7 @@ static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { namespace clang { namespace interp { static void popArg(InterpState &S, const Expr *Arg) { - PrimType Ty = S.getContext().classify(Arg->getType()).value_or(PT_Ptr); + PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr); TYPE_SWITCH(Ty, S.Stk.discard()); } diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 754ca96b0c645e5..280aa39398c8e9a 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -634,12 +634,23 @@ static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_move(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + + PrimType ArgT = S.getContext().classify(Call->getArg(0)).value_or(PT_Ptr); + + TYPE_SWITCH(ArgT, const T &Arg = S.Stk.peek(); S.Stk.push(Arg);); + + return Func->getDecl()->isConstexpr(); +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { InterpFrame *Frame = S.Current; APValue Dummy; - std::optional ReturnT = S.getContext().classify(Call->getType()); + std::optional ReturnT = S.getContext().classify(Call); // If classify failed, we assume void. assert(ReturnT || Call->getType()->isVoidType()); @@ -848,6 +859,15 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BIas_const: + case Builtin::BIforward: + case Builtin::BIforward_like: + case Builtin::BImove: + case Builtin::BImove_if_noexcept: +if (!interp__builtin_move(S, OpPC, Frame, F, Call)) + return false; +break; + default: return false; } diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 75f3c5d192b2cf2..6e995ce704e3949 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -413,3 +413,92 @@ namespace AddressOf { constexpr _Complex float F = {3, 4}; static_assert(__builtin_addressof(F) == &F, ""); } + +namespace std { +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template +constexpr type
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff e3993e044ec5925e59c131f798f823a9f16f0433 f4f4dd022d09dee65b6152d083af1c7fba9c8052 -- clang/lib/AST/Interp/ByteCodeExprGen.h clang/lib/AST/Interp/Context.h clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/InterpBuiltin.cpp clang/test/AST/Interp/functions.cpp clang/test/SemaCXX/builtin-std-move.cpp `` View the diff from clang-format here. ``diff diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 3956eec6cd..ae25ce13fd 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -383,9 +383,9 @@ bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { << CD->getInheritedConstructor().getConstructor()->getParent(); S.Note(DiagDecl->getLocation(), diag::note_declared_at); } else { -// Don't emit anything if the function isn't defined and we're checking for -// a constnat expression. It might be defined at the point we're actually -// calling it. +// Don't emit anything if the function isn't defined and we're checking +// for a constnat expression. It might be defined at the point we're +// actually calling it. if (!DiagDecl->isDefined() && S.checkingPotentialConstantExpression()) return false; `` https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/70772 >From e850b96306ab5d9e6aac4171150195ea013f6ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Tue, 31 Oct 2023 07:17:16 +0100 Subject: [PATCH 1/5] [clang][Interp] Handle std::move etc. builtins --- clang/lib/AST/Interp/InterpBuiltin.cpp | 17 + clang/test/AST/Interp/functions.cpp| 15 +++ 2 files changed, 32 insertions(+) diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 754ca96b0c645e..142f92ffc337c3 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -634,6 +634,15 @@ static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_move(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + + const Pointer &Arg = S.Stk.peek(); + S.Stk.push(Arg); + return Func->getDecl()->isConstexpr(); +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { InterpFrame *Frame = S.Current; @@ -848,6 +857,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BIas_const: + case Builtin::BIforward: + case Builtin::BIforward_like: + case Builtin::BImove: +if (!interp__builtin_move(S, OpPC, Frame, F, Call)) + return false; +break; + default: return false; } diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 75f3c5d192b2cf..019af555c347a6 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -413,3 +413,18 @@ namespace AddressOf { constexpr _Complex float F = {3, 4}; static_assert(__builtin_addressof(F) == &F, ""); } + +namespace std { +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template +constexpr typename std::remove_reference::type&& move(T &&t) noexcept { + return static_cast::type &&>(t); +} +} +/// The std::move declaration above gets translated to a builtin function. +namespace Move { + constexpr int A = std::move(5); + static_assert(A == 5, ""); +} >From d90032c82863ea20e7896b78c1d9b78590603a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Thu, 2 Nov 2023 09:17:41 +0100 Subject: [PATCH 2/5] Add more tests --- clang/test/AST/Interp/functions.cpp | 74 + 1 file changed, 74 insertions(+) diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 019af555c347a6..6e995ce704e394 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -425,6 +425,80 @@ constexpr typename std::remove_reference::type&& move(T &&t) noexcept { } /// The std::move declaration above gets translated to a builtin function. namespace Move { +#if __cplusplus >= 202002L + consteval int f_eval() { // expected-note 12{{declared here}} \ + // ref-note 12{{declared here}} +return 0; + } + + /// From test/SemaCXX/cxx2a-consteval. + struct Copy { +int(*ptr)(); +constexpr Copy(int(*p)() = nullptr) : ptr(p) {} +consteval Copy(const Copy&) = default; + }; + + constexpr const Copy &to_lvalue_ref(const Copy &&a) { +return a; + } + + void test() { +constexpr const Copy C; +// there is no the copy constructor call when its argument is a prvalue because of garanteed copy elision. +// so we need to test with both prvalue and xvalues. +{ Copy c(C); } +{ Copy c((Copy(&f_eval))); } // expected-error {{cannot take address of consteval}} \ + // ref-error {{cannot take address of consteval}} +{ Copy c(std::move(C)); } +{ Copy c(std::move(Copy(&f_eval))); } // expected-error {{is not a constant expression}} \ + // expected-note {{to a consteval}} \ + // ref-error {{is not a constant expression}} \ + // ref-note {{to a consteval}} +{ Copy c(to_lvalue_ref((Copy(&f_eval; } // expected-error {{is not a constant expression}} \ +// expected-note {{to a consteval}} \ +// ref-error {{is not a constant expression}} \ +// ref-note {{to a consteval}} +{ Copy c(to_lvalue_ref(std::move(C))); } +{ Copy c(to_lvalue_ref(std::move(Copy(&f_eval; }
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: https://github.com/AaronBallman approved this pull request. LGTM assuming no surprises come up from the additional test coverage. https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: @@ -378,3 +378,92 @@ namespace Packs { static_assert(foo() == 2, ""); static_assert(foo<>() == 0, ""); } + +namespace std { +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template +constexpr typename std::remove_reference::type&& move(T &&t) noexcept { + return static_cast::type &&>(t); +} +} +/// The std::move declaration above gets translated to a builtin function. +namespace Move { AaronBallman wrote: I'd like to see test coverage involving a move constructor, a move assignment operator, a direct call to __builtin_move, and some testing for `std::as_const` and `std::forward`. Of special interest would be times when there's UB in the move constructor/move assignment that should be caught or a non-copyable object where move semantics are the only thing that should work. https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: tbaederr wrote: Ping https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: tbaederr wrote: Ping https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/70772 >From 5436d89e4ca3fbb1d53f27f8d5347f3eff100dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Tue, 31 Oct 2023 07:17:16 +0100 Subject: [PATCH 1/2] [clang][Interp] Handle std::move etc. builtins --- clang/lib/AST/Interp/InterpBuiltin.cpp | 18 ++ clang/test/AST/Interp/functions.cpp| 15 +++ 2 files changed, 33 insertions(+) diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 9cf206ecc212adb..58fedb6a96fb936 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -138,6 +138,7 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result, case X: \ return Ret(S, OpPC, Result); switch (*T) { +RET_CASE(PT_Ptr); RET_CASE(PT_Float); RET_CASE(PT_Bool); RET_CASE(PT_Sint8); @@ -533,6 +534,15 @@ static bool interp__builtin_classify_type(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_move(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + + const Pointer &Arg = S.Stk.peek(); + S.Stk.push(Arg); + return Func->getDecl()->isConstexpr(); +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { InterpFrame *Frame = S.Current; @@ -702,6 +712,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BIas_const: + case Builtin::BIforward: + case Builtin::BIforward_like: + case Builtin::BImove: +if (!interp__builtin_move(S, OpPC, Frame, F, Call)) + return false; +break; + default: return false; } diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index ab562e70606b672..2ce39de3415747a 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -378,3 +378,18 @@ namespace Packs { static_assert(foo() == 2, ""); static_assert(foo<>() == 0, ""); } + +namespace std { +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template +constexpr typename std::remove_reference::type&& move(T &&t) noexcept { + return static_cast::type &&>(t); +} +} +/// The std::move declaration above gets translated to a builtin function. +namespace Move { + constexpr int A = std::move(5); + static_assert(A == 5, ""); +} >From 63f4c0937da07f807eb3170eb84a77f069790cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Thu, 2 Nov 2023 09:17:41 +0100 Subject: [PATCH 2/2] Add more tests --- clang/test/AST/Interp/functions.cpp | 74 + 1 file changed, 74 insertions(+) diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 2ce39de3415747a..197a161b9763421 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -390,6 +390,80 @@ constexpr typename std::remove_reference::type&& move(T &&t) noexcept { } /// The std::move declaration above gets translated to a builtin function. namespace Move { +#if __cplusplus >= 202002L + consteval int f_eval() { // expected-note 12{{declared here}} \ + // ref-note 12{{declared here}} +return 0; + } + + /// From test/SemaCXX/cxx2a-consteval. + struct Copy { +int(*ptr)(); +constexpr Copy(int(*p)() = nullptr) : ptr(p) {} +consteval Copy(const Copy&) = default; + }; + + constexpr const Copy &to_lvalue_ref(const Copy &&a) { +return a; + } + + void test() { +constexpr const Copy C; +// there is no the copy constructor call when its argument is a prvalue because of garanteed copy elision. +// so we need to test with both prvalue and xvalues. +{ Copy c(C); } +{ Copy c((Copy(&f_eval))); } // expected-error {{cannot take address of consteval}} \ + // ref-error {{cannot take address of consteval}} +{ Copy c(std::move(C)); } +{ Copy c(std::move(Copy(&f_eval))); } // expected-error {{is not a constant expression}} \ + // expected-note {{to a consteval}} \ + // ref-error {{is not a constant expression}} \ + // ref-note {{to a consteval}} +{ Copy c(to_lvalue_ref((Copy(&f_eval; } // expected-error {{is not a constant expression}} \ +// expected-note {{to a consteval}} \ +
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: hnrklssn wrote: LGTM, but someone else should approve also. https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: tbaederr wrote: Ping https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: tbaederr wrote: Ping https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: tbaederr wrote: > Nice. I realise you're following the convention already established in the > test file, but have you considered compiling with `-verify=new,both` and > `-verify=ref,both`, respectively, and combining the shared diagnostics into > `both-error` etc. to make it easier to see when they do and don't align? That might be an interesting approach for the next new test file I add, thanks. https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: hnrklssn wrote: Nice. I realise you're following the convention already established in the test file, but have you considered compiling with `-verify=new,both` and `-verify=ref,both`, respectively, and combining the shared diagnostics into `both-error` etc. to make it easier to see when they do and don't align? https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/70772 >From b670986c19e412b3c140b610f2c26d957544b23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Tue, 31 Oct 2023 07:17:16 +0100 Subject: [PATCH 1/2] [clang][Interp] Handle std::move etc. builtins --- clang/lib/AST/Interp/InterpBuiltin.cpp | 17 + clang/test/AST/Interp/functions.cpp| 16 2 files changed, 33 insertions(+) diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index e329794cb79243d..10e703d868f168a 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -412,6 +412,15 @@ static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_move(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + + const Pointer &Arg = S.Stk.peek(); + S.Stk.push(Arg); + return Func->getDecl()->isConstexpr(); +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { InterpFrame *Frame = S.Current; @@ -537,6 +546,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return retInt(S, OpPC, Dummy); break; + case Builtin::BIas_const: + case Builtin::BIforward: + case Builtin::BIforward_like: + case Builtin::BImove: +if (interp__builtin_move(S, OpPC, Frame, F, Call)) + return Ret(S, OpPC, Dummy); +break; + default: return false; } diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 4bef9c2f7c0d1fa..364744203424380 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -371,3 +371,19 @@ namespace Variadic { constexpr int (*VFP)(...) = variadic_function2; static_assert(VFP() == 12, ""); } + + +namespace std { +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template +constexpr typename std::remove_reference::type&& move(T &&t) noexcept { + return static_cast::type &&>(t); +} +} +/// The std::move declaration above gets translated to a builtin function. +namespace Move { + constexpr int A = std::move(5); + static_assert(A == 5, ""); +} >From 84b0f98a1ab95f49d3f4fe10bb8c2add63e4d55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Thu, 2 Nov 2023 09:17:41 +0100 Subject: [PATCH 2/2] Add more tests --- clang/test/AST/Interp/functions.cpp | 74 + 1 file changed, 74 insertions(+) diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 364744203424380..c9a6b348adc0174 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -384,6 +384,80 @@ constexpr typename std::remove_reference::type&& move(T &&t) noexcept { } /// The std::move declaration above gets translated to a builtin function. namespace Move { +#if __cplusplus >= 202002L + consteval int f_eval() { // expected-note 12{{declared here}} \ + // ref-note 12{{declared here}} +return 0; + } + + /// From test/SemaCXX/cxx2a-consteval. + struct Copy { +int(*ptr)(); +constexpr Copy(int(*p)() = nullptr) : ptr(p) {} +consteval Copy(const Copy&) = default; + }; + + constexpr const Copy &to_lvalue_ref(const Copy &&a) { +return a; + } + + void test() { +constexpr const Copy C; +// there is no the copy constructor call when its argument is a prvalue because of garanteed copy elision. +// so we need to test with both prvalue and xvalues. +{ Copy c(C); } +{ Copy c((Copy(&f_eval))); } // expected-error {{cannot take address of consteval}} \ + // ref-error {{cannot take address of consteval}} +{ Copy c(std::move(C)); } +{ Copy c(std::move(Copy(&f_eval))); } // expected-error {{is not a constant expression}} \ + // expected-note {{to a consteval}} \ + // ref-error {{is not a constant expression}} \ + // ref-note {{to a consteval}} +{ Copy c(to_lvalue_ref((Copy(&f_eval; } // expected-error {{is not a constant expression}} \ +// expected-note {{to a consteval}} \ +// ref-error {{is not a constant expression}} \ +// ref-note {{to a consteval}} +{ Copy c(to_lvalue_ref(std::move(C))); } +{ Copy c(to_lvalue_ref(std::move(Copy(&f_eval; } // expected-error {{is not a constant expr
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
hnrklssn wrote: Would making a class with custom move and copy constructors with side effects, and moving/copying an instance around a bit to affect the results of static_asserts, work for testing? https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) Changes Only light testing here since I'm not sure how to properly test this. --- Full diff: https://github.com/llvm/llvm-project/pull/70772.diff 2 Files Affected: - (modified) clang/lib/AST/Interp/InterpBuiltin.cpp (+17) - (modified) clang/test/AST/Interp/functions.cpp (+16) ``diff diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index e329794cb79243d..10e703d868f168a 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -412,6 +412,15 @@ static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_move(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + + const Pointer &Arg = S.Stk.peek(); + S.Stk.push(Arg); + return Func->getDecl()->isConstexpr(); +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { InterpFrame *Frame = S.Current; @@ -537,6 +546,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return retInt(S, OpPC, Dummy); break; + case Builtin::BIas_const: + case Builtin::BIforward: + case Builtin::BIforward_like: + case Builtin::BImove: +if (interp__builtin_move(S, OpPC, Frame, F, Call)) + return Ret(S, OpPC, Dummy); +break; + default: return false; } diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 4bef9c2f7c0d1fa..364744203424380 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -371,3 +371,19 @@ namespace Variadic { constexpr int (*VFP)(...) = variadic_function2; static_assert(VFP() == 12, ""); } + + +namespace std { +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template +constexpr typename std::remove_reference::type&& move(T &&t) noexcept { + return static_cast::type &&>(t); +} +} +/// The std::move declaration above gets translated to a builtin function. +namespace Move { + constexpr int A = std::move(5); + static_assert(A == 5, ""); +} `` https://github.com/llvm/llvm-project/pull/70772 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Handle std::move etc. builtins (PR #70772)
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/70772 Only light testing here since I'm not sure how to properly test this. >From b670986c19e412b3c140b610f2c26d957544b23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Tue, 31 Oct 2023 07:17:16 +0100 Subject: [PATCH] [clang][Interp] Handle std::move etc. builtins --- clang/lib/AST/Interp/InterpBuiltin.cpp | 17 + clang/test/AST/Interp/functions.cpp| 16 2 files changed, 33 insertions(+) diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index e329794cb79243d..10e703d868f168a 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -412,6 +412,15 @@ static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_move(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *Func, + const CallExpr *Call) { + + const Pointer &Arg = S.Stk.peek(); + S.Stk.push(Arg); + return Func->getDecl()->isConstexpr(); +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { InterpFrame *Frame = S.Current; @@ -537,6 +546,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return retInt(S, OpPC, Dummy); break; + case Builtin::BIas_const: + case Builtin::BIforward: + case Builtin::BIforward_like: + case Builtin::BImove: +if (interp__builtin_move(S, OpPC, Frame, F, Call)) + return Ret(S, OpPC, Dummy); +break; + default: return false; } diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 4bef9c2f7c0d1fa..364744203424380 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -371,3 +371,19 @@ namespace Variadic { constexpr int (*VFP)(...) = variadic_function2; static_assert(VFP() == 12, ""); } + + +namespace std { +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template +constexpr typename std::remove_reference::type&& move(T &&t) noexcept { + return static_cast::type &&>(t); +} +} +/// The std::move declaration above gets translated to a builtin function. +namespace Move { + constexpr int A = std::move(5); + static_assert(A == 5, ""); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits