[clang] [clang][bytecode] Explicitly mark constexpr-unknown variables as such (PR #135806)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 15 09:20:49 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
Instead of trying to figure out what's constexpr-unknown later on.
---
Full diff: https://github.com/llvm/llvm-project/pull/135806.diff
7 Files Affected:
- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+16-8)
- (modified) clang/lib/AST/ByteCode/Compiler.h (+8-4)
- (modified) clang/lib/AST/ByteCode/Descriptor.h (+1)
- (modified) clang/lib/AST/ByteCode/Disasm.cpp (+2)
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+4-5)
- (modified) clang/lib/AST/ByteCode/Program.cpp (+1-1)
- (modified) clang/test/AST/ByteCode/codegen.cpp (+33-2)
``````````diff
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/135806
More information about the cfe-commits
mailing list