https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/135806
>From 038f7cbb3cfa03045e1ccdc10ea68842ec85232c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Mon, 14 Apr 2025 17:18:50 +0200 Subject: [PATCH] [clang][bytecode] Explicitly mark constexpr-unknown variables as such Instead of trying to figure out what's constexpr-unknown later on. --- clang/lib/AST/ByteCode/Compiler.cpp | 24 +++++++++++++------- clang/lib/AST/ByteCode/Compiler.h | 12 ++++++---- clang/lib/AST/ByteCode/Descriptor.h | 1 + clang/lib/AST/ByteCode/Disasm.cpp | 2 ++ clang/lib/AST/ByteCode/Interp.cpp | 9 ++++---- clang/lib/AST/ByteCode/Program.cpp | 2 +- clang/test/AST/ByteCode/codegen.cpp | 35 +++++++++++++++++++++++++++-- 7 files changed, 65 insertions(+), 20 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 2e22c85ed5f6d..afd8d09a088cd 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -4293,7 +4293,8 @@ bool Compiler<Emitter>::emitConst(const APSInt &Value, const Expr *E) { template <class Emitter> unsigned Compiler<Emitter>::allocateLocalPrimitive( - DeclTy &&Src, PrimType Ty, bool IsConst, const ValueDecl *ExtendingDecl) { + DeclTy &&Src, PrimType Ty, bool IsConst, const ValueDecl *ExtendingDecl, + bool IsConstexprUnknown) { // Make sure we don't accidentally register the same decl twice. if (const auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) { @@ -4307,6 +4308,7 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive( // or isa<MaterializeTemporaryExpr>(). Descriptor *D = P.createDescriptor(Src, Ty, nullptr, Descriptor::InlineDescMD, IsConst, isa<const Expr *>(Src)); + D->IsConstexprUnknown = IsConstexprUnknown; Scope::Local Local = this->createLocal(D); if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) Locals.insert({VD, Local}); @@ -4320,7 +4322,8 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive( template <class Emitter> std::optional<unsigned> Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty, - const ValueDecl *ExtendingDecl) { + const ValueDecl *ExtendingDecl, + bool IsConstexprUnknown) { // Make sure we don't accidentally register the same decl twice. if ([[maybe_unused]] const auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) { @@ -4349,6 +4352,7 @@ Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty, IsTemporary, /*IsMutable=*/false, Init); if (!D) return std::nullopt; + D->IsConstexprUnknown = IsConstexprUnknown; Scope::Local Local = this->createLocal(D); if (Key) @@ -4460,9 +4464,10 @@ bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) { } template <class Emitter> -VarCreationState Compiler<Emitter>::visitDecl(const VarDecl *VD) { +VarCreationState Compiler<Emitter>::visitDecl(const VarDecl *VD, + bool IsConstexprUnknown) { - auto R = this->visitVarDecl(VD, /*Toplevel=*/true); + auto R = this->visitVarDecl(VD, /*Toplevel=*/true, IsConstexprUnknown); if (R.notCreated()) return R; @@ -4550,7 +4555,8 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl *VD, template <class Emitter> VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, - bool Toplevel) { + bool Toplevel, + bool IsConstexprUnknown) { // We don't know what to do with these, so just return false. if (VD->getType().isNull()) return false; @@ -4620,7 +4626,8 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, if (VarT) { unsigned Offset = this->allocateLocalPrimitive( - VD, *VarT, VD->getType().isConstQualified()); + VD, *VarT, VD->getType().isConstQualified(), nullptr, + IsConstexprUnknown); if (Init) { // If this is a toplevel declaration, create a scope for the // initializer. @@ -4636,7 +4643,8 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, } } } else { - if (std::optional<unsigned> Offset = this->allocateLocal(VD)) { + if (std::optional<unsigned> Offset = this->allocateLocal( + VD, VD->getType(), nullptr, IsConstexprUnknown)) { if (!Init) return true; @@ -6461,7 +6469,7 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { // In case we need to re-visit a declaration. auto revisit = [&](const VarDecl *VD) -> bool { - auto VarState = this->visitDecl(VD); + auto VarState = this->visitDecl(VD, /*IsConstexprUnknown=*/true); if (VarState.notCreated()) return true; diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 858957367d85d..a3090a8a31189 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -286,8 +286,10 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, /// intact. bool delegate(const Expr *E); /// Creates and initializes a variable from the given decl. - VarCreationState visitVarDecl(const VarDecl *VD, bool Toplevel = false); - VarCreationState visitDecl(const VarDecl *VD); + VarCreationState visitVarDecl(const VarDecl *VD, bool Toplevel = false, + bool IsConstexprUnknown = false); + VarCreationState visitDecl(const VarDecl *VD, + bool IsConstexprUnknown = false); /// Visit an APValue. bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E); bool visitAPValueInitializer(const APValue &Val, const Expr *E, QualType T); @@ -303,12 +305,14 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, /// Creates a local primitive value. unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst, - const ValueDecl *ExtendingDecl = nullptr); + const ValueDecl *ExtendingDecl = nullptr, + bool IsConstexprUnknown = false); /// Allocates a space storing a local given its type. std::optional<unsigned> allocateLocal(DeclTy &&Decl, QualType Ty = QualType(), - const ValueDecl *ExtendingDecl = nullptr); + const ValueDecl *ExtendingDecl = nullptr, + bool IsConstexprUnknown = false); std::optional<unsigned> allocateTemporary(const Expr *E); private: diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index 9acabfd31d80b..a0705cc8c377f 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -168,6 +168,7 @@ struct Descriptor final { const bool IsArray = false; /// Flag indicating if this is a dummy descriptor. bool IsDummy = false; + bool IsConstexprUnknown = false; /// Storage management methods. const BlockCtorFn CtorFn = nullptr; diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp index d4c9ce6050b85..4bdf0f0afb1b0 100644 --- a/clang/lib/AST/ByteCode/Disasm.cpp +++ b/clang/lib/AST/ByteCode/Disasm.cpp @@ -376,6 +376,8 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const { if (isDummy()) OS << " dummy"; + if (IsConstexprUnknown) + OS << " constexpr-unknown"; } /// Dump descriptor, including all valid offsets. diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 3e1f36da8925f..4625154ac353d 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -299,15 +299,14 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, TYPE_SWITCH(Ty, S.Stk.discard<T>()); } -// FIXME: Instead of using this fairly expensive test, we should -// just mark constexpr-unknown values when creating them. bool isConstexprUnknown(const Pointer &P) { if (!P.isBlockPointer()) return false; + if (P.isDummy()) - return false; - const VarDecl *VD = P.block()->getDescriptor()->asVarDecl(); - return VD && VD->hasLocalStorage() && !isa<ParmVarDecl>(VD); + return isa_and_nonnull<ParmVarDecl>(P.getDeclDesc()->asValueDecl()); + + return P.getDeclDesc()->IsConstexprUnknown; } bool CheckBCPResult(InterpState &S, const Pointer &Ptr) { diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index c83f5579fd55f..fdb7b960ff06d 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -156,7 +156,7 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) { if (const auto *E = dyn_cast<const Expr *>(D)) { QT = E->getType(); } else { - const ValueDecl *VD = cast<ValueDecl>(cast<const Decl *>(D)); + const auto *VD = cast<ValueDecl>(cast<const Decl *>(D)); IsWeak = VD->isWeak(); QT = VD->getType(); if (const auto *RT = QT->getAs<ReferenceType>()) diff --git a/clang/test/AST/ByteCode/codegen.cpp b/clang/test/AST/ByteCode/codegen.cpp index 7c853a20362b8..6f9e75eac6026 100644 --- a/clang/test/AST/ByteCode/codegen.cpp +++ b/clang/test/AST/ByteCode/codegen.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fcxx-exceptions | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fcxx-exceptions -fexperimental-new-constant-interpreter | FileCheck %s #ifdef __SIZEOF_INT128__ // CHECK: @PR11705 = global i128 0 @@ -104,3 +104,34 @@ int notdead() { } // CHECK: _ZZ7notdeadvEN3$_0clEv // CHECK: ret i32 %cond + +/// The conmparison of those two parameters should NOT work. +bool paramcmp(const int& lhs, const int& rhs) { + if (&lhs == &rhs) + return true; + return false; +} +// CHECK: _Z8paramcmpRKiS0_ +// CHECK: if.then +// CHECK: if.end + +/// &x == &OuterX should work and return 0. +class X { +public: + X(); + X(const X&); + X(const volatile X &); + ~X(); +}; + +extern X OuterX; + +X test24() { + X x; + if (&x == &OuterX) + throw 0; + return x; +} +// CHECK: _Z6test24v +// CHECK-NOT: eh.resume +// CHECK-NOT: unreachable _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits