Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>, Timm =?utf-8?q?Bäder?= <tbae...@redhat.com> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/70...@github.com>
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?= <tbae...@redhat.com> 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<Pointer>(); + S.Stk.push<Pointer>(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 <typename T> struct remove_reference { using type = T; }; +template <typename T> struct remove_reference<T &> { using type = T; }; +template <typename T> struct remove_reference<T &&> { using type = T; }; +template <typename T> +constexpr typename std::remove_reference<T>::type&& move(T &&t) noexcept { + return static_cast<typename std::remove_reference<T>::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?= <tbae...@redhat.com> 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<T>::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 expression}} \ + // expected-note {{to a consteval}} \ + // ref-error {{is not a constant expression}} \ + // ref-note {{to a consteval}} + { Copy c = Copy(C); } + { Copy c = Copy(Copy(&f_eval)); } // expected-error {{cannot take address of consteval}} \ + // ref-error {{cannot take address of consteval}} + { Copy c = Copy(std::move(C)); } + { Copy c = Copy(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 = Copy(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 = Copy(to_lvalue_ref(std::move(C))); } + { Copy c = Copy(to_lvalue_ref(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; c = Copy(C); } + { Copy c; c = Copy(Copy(&f_eval)); } // expected-error {{cannot take address of consteval}} \ + // ref-error {{cannot take address of consteval}} + { Copy c; c = Copy(std::move(C)); } + { Copy c; c = Copy(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; c = Copy(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; c = Copy(to_lvalue_ref(std::move(C))); } + { Copy c; c = Copy(to_lvalue_ref(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}} + } +#endif constexpr int A = std::move(5); static_assert(A == 5, ""); } >From 3c6a990b75c67a4cc143f251da0ea42adf018bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Mon, 11 Dec 2023 15:08:32 +0100 Subject: [PATCH 3/5] [clang][Interp] Don't diagnose undefined functions when checking... ... for a potential constant expression. They are not defined now, but might be defined later when the function is actually called. --- clang/lib/AST/Interp/Interp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 9de0926b9dba9c..4352e78be45bf0 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 constant 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; >From 4a684b8ef93b4898e1daa5360bf0a045e7822bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Mon, 15 Jan 2024 07:57:36 +0100 Subject: [PATCH 4/5] Adapt std::move changes after addressof changes --- 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 | 8 +++++--- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index bbb13e97e72569..9757f5dd9b8e34 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -128,15 +128,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, // If the function does not exist yet, it is compiled. const Function *getFunction(const FunctionDecl *FD); - /// Classifies a type. std::optional<PrimType> 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<PrimType> 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 7649caef224281..0284b7580318bc 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -67,9 +67,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<PrimType> classify(QualType T) const; + /// Classifies an expression. + std::optional<PrimType> 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 4352e78be45bf0..3956eec6cd6c56 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -122,7 +122,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<T>()); } diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 142f92ffc337c3..ac0a373ede7ac1 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -638,8 +638,10 @@ static bool interp__builtin_move(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call) { - const Pointer &Arg = S.Stk.peek<Pointer>(); - S.Stk.push<Pointer>(Arg); + PrimType ArgT = S.getContext().classify(Call->getArg(0)).value_or(PT_Ptr); + + TYPE_SWITCH(ArgT, const T &Arg = S.Stk.peek<T>(); S.Stk.push<T>(Arg);); + return Func->getDecl()->isConstexpr(); } @@ -648,7 +650,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, InterpFrame *Frame = S.Current; APValue Dummy; - std::optional<PrimType> ReturnT = S.getContext().classify(Call->getType()); + std::optional<PrimType> ReturnT = S.getContext().classify(Call); // If classify failed, we assume void. assert(ReturnT || Call->getType()->isVoidType()); >From f4f4dd022d09dee65b6152d083af1c7fba9c8052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Mon, 15 Jan 2024 09:35:36 +0100 Subject: [PATCH 5/5] Enable SemaCXX/builtin-std-move.cpp as well --- clang/lib/AST/Interp/InterpBuiltin.cpp | 1 + clang/test/SemaCXX/builtin-std-move.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index ac0a373ede7ac1..280aa39398c8e9 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -863,6 +863,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, 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; diff --git a/clang/test/SemaCXX/builtin-std-move.cpp b/clang/test/SemaCXX/builtin-std-move.cpp index adad66afc2cbd9..647dfbcd6a5bc1 100644 --- a/clang/test/SemaCXX/builtin-std-move.cpp +++ b/clang/test/SemaCXX/builtin-std-move.cpp @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -std=c++17 -verify %s +// RUN: %clang_cc1 -std=c++17 -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s // RUN: %clang_cc1 -std=c++17 -verify %s -DNO_CONSTEXPR +// RUN: %clang_cc1 -std=c++17 -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s -DNO_CONSTEXPR // RUN: %clang_cc1 -std=c++20 -verify %s +// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -DNEW_INTERP -verify %s namespace std { #ifndef NO_CONSTEXPR @@ -105,7 +108,7 @@ constexpr bool f(A a) { // #f #ifndef NO_CONSTEXPR static_assert(f({}), "should be constexpr"); -#else +#elif !defined(NEW_INTERP) // expected-error@#f {{never produces a constant expression}} // expected-note@#call {{}} #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits