Author: Timm Baeder
Date: 2026-11-03T14:06:19+01:00
New Revision: 0224aac7e79571993dfbf565c1ba77bf762a17d2

URL: 
https://github.com/llvm/llvm-project/commit/0224aac7e79571993dfbf565c1ba77bf762a17d2
DIFF: 
https://github.com/llvm/llvm-project/commit/0224aac7e79571993dfbf565c1ba77bf762a17d2.diff

LOG: [clang][bytecode] Clean up ConstexprUnknown handling (#238281)

Move the `IsConstexprUnknown` flag to `interp::Block`. This makes it
part of `Block::isAccessible()`.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Block.h
    clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
    clang/lib/AST/ByteCode/ByteCodeEmitter.h
    clang/lib/AST/ByteCode/Compiler.cpp
    clang/lib/AST/ByteCode/Descriptor.h
    clang/lib/AST/ByteCode/Disasm.cpp
    clang/lib/AST/ByteCode/EvalEmitter.cpp
    clang/lib/AST/ByteCode/EvalEmitter.h
    clang/lib/AST/ByteCode/Interp.cpp
    clang/lib/AST/ByteCode/Interp.h
    clang/lib/AST/ByteCode/Pointer.h
    clang/lib/AST/ByteCode/Program.cpp
    clang/lib/AST/ByteCode/Program.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Block.h b/clang/lib/AST/ByteCode/Block.h
index afdf726e8be26..25514ac126807 100644
--- a/clang/lib/AST/ByteCode/Block.h
+++ b/clang/lib/AST/ByteCode/Block.h
@@ -28,6 +28,7 @@ struct BlockFlags {
   static constexpr uint8_t Extern = 1u << 0u;
   static constexpr uint8_t Dead = 1u << 1u;
   static constexpr uint8_t Weak = 1u << 2u;
+  static constexpr uint8_t ConstexprUnknown = 1u << 3u;
 
   uint8_t V = 0;
   constexpr BlockFlags(uint8_t V = 0) : V(V) {}
@@ -42,6 +43,9 @@ struct BlockFlags {
   constexpr BlockFlags withWeak(bool B = true) const {
     return BlockFlags(V | (B * Weak));
   }
+  constexpr BlockFlags withConstexprUnknown(bool B = true) const {
+    return BlockFlags(V | (B * ConstexprUnknown));
+  }
 };
 
 /// A memory block, either on the stack or in the heap.
@@ -111,6 +115,9 @@ class Block final {
     return Result;
   }
   bool isDead() const { return Flags.V & BlockFlags::Dead; }
+  bool isConstexprUnknown() const {
+    return Flags.V & BlockFlags::ConstexprUnknown;
+  }
   bool isAccessible() const { return Flags.V == 0; }
   /// Returns the size of the block, excluding metadata.
   unsigned getSize() const { return DescSize; }

diff  --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp 
b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
index 0e1544baa97de..fb7b6919c8528 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
@@ -88,7 +88,7 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl 
*FuncDecl,
   Func->setIsFullyCompiled(true);
 }
 
-Scope::Local ByteCodeEmitter::createLocal(const Descriptor *D) {
+Scope::Local ByteCodeEmitter::createLocal(const Descriptor *D, bool) {
   NextLocalOffset += sizeof(Block);
   unsigned Location = NextLocalOffset;
   assert(aligned(Block::getMetadataSize(Block::Local) + D->getAllocSize()));

diff  --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h 
b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
index 4174a26b80464..f76da92553308 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
@@ -71,7 +71,7 @@ class ByteCodeEmitter {
   bool constantFolding() const { return false; }
 
   /// Callback for local registration.
-  Local createLocal(const Descriptor *D);
+  Local createLocal(const Descriptor *D, bool IsConstexprUnknown = false);
 
   /// Parameter indices.
   llvm::DenseMap<const ParmVarDecl *, FuncParam> Params;

diff  --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index 12647df7bb5b9..e3232d943ee4d 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5474,8 +5474,7 @@ unsigned 
Compiler<Emitter>::allocateLocalPrimitive(DeclOrExpr Src, PrimType Ty,
   //   or isa<MaterializeTemporaryExpr>().
   Descriptor *D = P.createDescriptor(Src, Ty, nullptr, IsConst, Src.isExpr(),
                                      /*IsMutable=*/false, IsVolatile);
-  D->IsConstexprUnknown = this->VariablesAreConstexprUnknown;
-  Scope::Local Local = this->createLocal(D);
+  Scope::Local Local = this->createLocal(D, 
this->VariablesAreConstexprUnknown);
   if (auto *VD = Src.asValueDecl())
     Locals.insert({VD, Local});
   VarScope->addForScopeKind(Local, SC);
@@ -5505,9 +5504,8 @@ UnsignedOrNone 
Compiler<Emitter>::allocateLocal(DeclOrExpr Src, QualType Ty,
       /*IsMutable=*/false, /*IsVolatile=*/Ty.isVolatileQualified(), Init);
   if (!D)
     return std::nullopt;
-  D->IsConstexprUnknown = this->VariablesAreConstexprUnknown;
 
-  Scope::Local Local = this->createLocal(D);
+  Scope::Local Local = this->createLocal(D, 
this->VariablesAreConstexprUnknown);
   if (Key)
     Locals.insert({Key, Local});
   VarScope->addForScopeKind(Local, SC);
@@ -6278,7 +6276,9 @@ bool Compiler<Emitter>::registerRedecl(const VarDecl *VD, 
const APValue &Val) {
   if (P.getGlobal(VD))
     return true;
 
-  UnsignedOrNone GlobalIndex = P.createGlobal(VD, /*Init=*/nullptr);
+  UnsignedOrNone GlobalIndex =
+      P.createGlobal(VD, /*Init=*/nullptr, /*IsConstexprUnknown=*/false,
+                     /*CanBeExtern=*/false);
   if (!GlobalIndex) {
     llvm_unreachable("Why didn't that work?");
   }

diff  --git a/clang/lib/AST/ByteCode/Descriptor.h 
b/clang/lib/AST/ByteCode/Descriptor.h
index 7af548df7c481..d344f68ef318e 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -158,7 +158,6 @@ struct Descriptor final {
   const bool IsVolatile = false;
   /// Flag indicating if the block is an array.
   const bool IsArray = 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 af115e8bdc0b0..db5c116d8b3c8 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -456,9 +456,6 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream 
&OS) const {
     OS << " zero-size-array";
   else if (isUnknownSizeArray())
     OS << " unknown-size-array";
-
-  if (IsConstexprUnknown)
-    OS << " constexpr-unknown";
 }
 
 /// Dump descriptor, including all valid offsets.

diff  --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp 
b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index 6a18c8cfee71e..d3d0b9677bc96 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -147,11 +147,14 @@ void EvalEmitter::emitLabel(LabelTy Label) { CurrentLabel 
= Label; }
 
 EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
 
-Scope::Local EvalEmitter::createLocal(const Descriptor *D) {
+Scope::Local EvalEmitter::createLocal(const Descriptor *D,
+                                      bool IsConstexprUnknown) {
+
+  BlockFlags Flags = BlockFlags().withConstexprUnknown(IsConstexprUnknown);
   // Allocate memory for a local.
   char *Memory =
       reinterpret_cast<char *>(S.allocate(Block::allocSize(D, Block::Local)));
-  auto *B = new (Memory) Block(Ctx.getEvalID(), D, Block::Local);
+  auto *B = new (Memory) Block(Ctx.getEvalID(), D, Block::Local, Flags);
   B->invokeCtor();
 
   // Initialize local variable inline descriptor.
@@ -301,7 +304,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo 
Info) {
       ((DeclDesc->asVarDecl() == S.EvaluatingDecl &&
         S.getLangOpts().CPlusPlus23 &&
         S.EvaluatingDecl->getType()->isReferenceType()) ||
-       DeclDesc->IsConstexprUnknown)) {
+       Ptr.isConstexprUnknown())) {
     S.FFDiag(Info, diag::note_constexpr_var_init_non_constant, 1)
         << DeclDesc->asVarDecl();
     S.Note(DeclDesc->asVarDecl()->getLocation(), diag::note_declared_at);

diff  --git a/clang/lib/AST/ByteCode/EvalEmitter.h 
b/clang/lib/AST/ByteCode/EvalEmitter.h
index 2f9507c04628c..023b1d6d1fdb5 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.h
+++ b/clang/lib/AST/ByteCode/EvalEmitter.h
@@ -112,7 +112,7 @@ class EvalEmitter : public SourceMapper {
   }
 
   /// Callback for registering a local.
-  Local createLocal(const Descriptor *D);
+  Local createLocal(const Descriptor *D, bool IsConstexprUnknown = false);
 
   /// Parameter indices.
   llvm::DenseMap<const ParmVarDecl *, FuncParam> Params;

diff  --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index b759897b83f96..5caede7d1a149 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -339,16 +339,6 @@ void cleanupAfterFunctionCall(InterpState &S, const 
Function *Func) {
     S.Stk.discard<Pointer>();
 }
 
-bool isConstexprUnknown(const Block *B) {
-  return B->getDescriptor()->IsConstexprUnknown;
-}
-
-bool isConstexprUnknown(const Pointer &P) {
-  if (!P.isBlockPointer() || P.isZero())
-    return false;
-  return isConstexprUnknown(P.block());
-}
-
 bool CheckBCPResult(InterpState &S, const Pointer &Ptr) {
   if (Ptr.isDummy())
     return false;
@@ -874,7 +864,9 @@ bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const 
Block *B) {
   if (!B->isAccessible()) {
     if (!CheckExtern(S, OpPC, B))
       return false;
-    return CheckWeak(S, OpPC, B);
+    if (!CheckWeak(S, OpPC, B))
+      return false;
+    return false;
   }
 
   if (!CheckConstant(S, OpPC, B->getDescriptor()))
@@ -956,7 +948,9 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, PtrView Ptr, 
AccessKinds AK) {
     }
     if (!CheckExtern(S, OpPC, Ptr.block()))
       return false;
-    return CheckWeak(S, OpPC, Ptr.block());
+    if (!CheckWeak(S, OpPC, Ptr.block()))
+      return false;
+    return false;
   }
 
   if (!CheckConstant(S, OpPC, Ptr, AK))
@@ -977,8 +971,6 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, PtrView Ptr, 
AccessKinds AK) {
     return false;
   if (!CheckVolatile(S, OpPC, Ptr, AK))
     return false;
-  if (isConstexprUnknown(Ptr.block()))
-    return false;
 
   if (!Ptr.isArrayRoot()) {
     // According to GCC info page:
@@ -1051,7 +1043,9 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr) {
       return false;
     if (!CheckExtern(S, OpPC, Ptr))
       return false;
-    return CheckWeak(S, OpPC, Ptr.block());
+    if (!CheckWeak(S, OpPC, Ptr.block()))
+      return false;
+    return false;
   }
 
   if (Ptr.isPastEnd())
@@ -1073,8 +1067,6 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr) {
     if (!CheckMutable(S, OpPC, Ptr.view()))
       return false;
   }
-  if (!S.inConstantContext() && isConstexprUnknown(Ptr))
-    return false;
   return true;
 }
 
@@ -1092,7 +1084,9 @@ bool CheckStore(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr,
   if (!Ptr.block()->isAccessible()) {
     if (!CheckLive(S, OpPC, Ptr, AK))
       return false;
-    return CheckExtern(S, OpPC, Ptr);
+    if (!CheckExtern(S, OpPC, Ptr))
+      return false;
+    return false;
   }
   if (!WillBeActivated && !CheckLifetime(S, OpPC, Ptr, AK))
     return false;
@@ -1108,14 +1102,12 @@ bool CheckStore(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr,
     return false;
   if (!CheckMutable(S, OpPC, Ptr.view(), AK))
     return false;
-  if (isConstexprUnknown(Ptr))
-    return false;
   return true;
 }
 
 static bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
                         bool IsCtor, bool IsDtor) {
-  if (!Ptr.isDummy() && !isConstexprUnknown(Ptr)) {
+  if (!Ptr.isDummy() && !Ptr.isConstexprUnknown()) {
     if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
       return false;
     if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
@@ -2881,8 +2873,6 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, 
const Expr *E,
     return false;
   if (!CheckConst(S, OpPC, Ptr))
     return false;
-  if (!S.inConstantContext() && isConstexprUnknown(Ptr))
-    return false;
 
   const auto *NewExpr = cast<CXXNewExpr>(E);
   const ASTContext &ASTCtx = S.getASTContext();
@@ -3066,7 +3056,7 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool 
HasIndeterminateBits,
 }
 
 bool handleReference(InterpState &S, CodePtr OpPC, Block *B) {
-  if (isConstexprUnknown(B)) {
+  if (B->isConstexprUnknown()) {
     S.Stk.push<Pointer>(B);
     return true;
   }

diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 5c02dedcce920..b96b50fe9e69f 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -133,8 +133,6 @@ bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
                               const FixedPoint &FP);
 
 bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I);
-bool isConstexprUnknown(const Pointer &P);
-bool isConstexprUnknown(const Block *B);
 bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestType,
                  bool IsReferenceCast);
 bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth,
@@ -886,11 +884,6 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr,
                   bool CanOverflow, UnsignedOrNone BitWidth = std::nullopt) {
   assert(!Ptr.isDummy());
 
-  if (!S.inConstantContext()) {
-    if (isConstexprUnknown(Ptr))
-      return false;
-  }
-
   if constexpr (std::is_same_v<T, Boolean>) {
     if (!S.getLangOpts().CPlusPlus14)
       return Invalid(S, OpPC);
@@ -1321,7 +1314,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr 
OpPC, CompareFn Fn) {
   assert(!RHS.isZero());
 
   if (!S.inConstantContext()) {
-    if (isConstexprUnknown(LHS) || isConstexprUnknown(RHS))
+    if (LHS.isConstexprUnknown() || RHS.isConstexprUnknown())
       return false;
   }
 
@@ -2054,7 +2047,7 @@ inline bool GetRefGlobal(InterpState &S, CodePtr OpPC, 
uint32_t I) {
     return true;
   }
 
-  if (isConstexprUnknown(B)) {
+  if (B->isConstexprUnknown()) {
     S.Stk.push<Pointer>(B);
     return true;
   }

diff  --git a/clang/lib/AST/ByteCode/Pointer.h 
b/clang/lib/AST/ByteCode/Pointer.h
index 35f1339be6b40..3e923a9c1a4c9 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -1198,7 +1198,7 @@ class Pointer {
     if (isOpaquePointer())
       return Opaque.isConstexprUnknown();
     if (isBlockPointer())
-      return getDeclDesc()->IsConstexprUnknown;
+      return block()->isConstexprUnknown();
     return false;
   }
 

diff  --git a/clang/lib/AST/ByteCode/Program.cpp 
b/clang/lib/AST/ByteCode/Program.cpp
index 4f7daf450b5ff..de4314b405283 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -10,7 +10,6 @@
 #include "Context.h"
 #include "Function.h"
 #include "PrimType.h"
-#include "Reflect.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
@@ -80,11 +79,12 @@ UnsignedOrNone Program::getOrCreateGlobal(const ValueDecl 
*VD,
 }
 
 UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init,
-                                     bool IsConstexprUnknown) {
+                                     bool IsConstexprUnknown,
+                                     bool CanBeExtern) {
   bool IsExtern;
   bool IsWeak = VD->isWeak();
   if (const auto *Var = dyn_cast<VarDecl>(VD)) {
-    IsExtern = Var->hasExternalStorage();
+    IsExtern = CanBeExtern && !Init && Var->hasExternalStorage();
   } else {
     assert((isa<UnnamedGlobalConstantDecl, MSGuidDecl, 
TemplateParamObjectDecl>(
         VD)));
@@ -163,12 +163,13 @@ UnsignedOrNone Program::createGlobal(DeclOrExpr D, 
QualType Ty, bool IsExtern,
 
   if (!Desc)
     return std::nullopt;
-  Desc->IsConstexprUnknown = IsConstexprUnknown;
 
   // Allocate a block for storage.
   unsigned I = Globals.size();
 
-  BlockFlags Flags = BlockFlags().withExtern(IsExtern).withWeak(IsWeak);
+  BlockFlags Flags =
+      BlockFlags().withExtern(IsExtern).withWeak(IsWeak).withConstexprUnknown(
+          IsConstexprUnknown);
   auto *G = new (Allocator,
                  Desc->getAllocSize() + Block::getMetadataSize(Block::Global))
       Global(Ctx.getEvalID(), getCurrentDecl(), Desc, Block::Global, Flags);

diff  --git a/clang/lib/AST/ByteCode/Program.h 
b/clang/lib/AST/ByteCode/Program.h
index 3cae337a6bc76..82f22579d45fe 100644
--- a/clang/lib/AST/ByteCode/Program.h
+++ b/clang/lib/AST/ByteCode/Program.h
@@ -84,7 +84,8 @@ class Program final {
 
   /// Creates a global and returns its index.
   UnsignedOrNone createGlobal(const ValueDecl *VD, const Expr *Init,
-                              bool IsConstexprUnknown = false);
+                              bool IsConstexprUnknown = false,
+                              bool CanBeExtern = true);
 
   /// Creates a global from a lifetime-extended temporary.
   UnsignedOrNone createGlobal(const Expr *E, QualType ExprType);


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to