https://github.com/akash-manna-sky created 
https://github.com/llvm/llvm-project/pull/226386

Fixes #156186

A namespace-scope `const` variable has internal linkage in C++, so 
`__attribute__((weak))` on it is an error and Sema drops the attribute in 
`FinalizeDeclaration`. That happens after the initializer has already been 
evaluated, and with the new interpreter that evaluation creates the global 
block and copies the weak flag into it. From then on the AST says the variable 
is not weak, but the block still says it is. In C++03, `CheckICE` sees the 
up-to-date declaration and accepts the array bound, then 
`EvaluateKnownConstIntCheckOverflow` asserts because the interpreter refuses 
the load. In later standards there is no crash, but the interpreter reports 
bogus VLA diagnostics that the classic evaluator does not.

`Block::isWeak()` now treats the cached flag as "may be weak" and confirms with 
the declaration, so blocks agree with the AST at the time of the read. Blocks 
that were never flagged keep the zero-cost fast path. Every consumer of the 
flag goes through this method, so load checks, pointer comparisons, and 
dead-block copies all pick it up.


>From 88b0e46d8779df2666a332d2a17072b44e32e76b Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Fri, 25 Sep 2026 12:44:02 +0530
Subject: [PATCH] [clang][bytecode] Re-check the declaration before treating a
 block as weak

Sema drops an invalid weak attribute in FinalizeDeclaration, after the
initializer has already been evaluated. By then the interpreter has
created the global block and copied the weak flag into it, so later
reads keep failing even though the declaration is no longer weak. In
C++03 the ICE check sees the up-to-date declaration, accepts the
expression, and EvaluateKnownConstIntCheckOverflow asserts when the
interpreter refuses the load.

Make Block::isWeak() confirm with the declaration when the flag is set.

Fixes #156186
---
 clang/lib/AST/ByteCode/InterpBlock.cpp            | 10 ++++++++++
 clang/lib/AST/ByteCode/InterpBlock.h              |  2 +-
 clang/test/AST/ByteCode/weak-internal-linkage.cpp | 12 ++++++++++++
 3 files changed, 23 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/AST/ByteCode/weak-internal-linkage.cpp

diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp 
b/clang/lib/AST/ByteCode/InterpBlock.cpp
index 888a660719590d..6bd6d520e0037f 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.cpp
+++ b/clang/lib/AST/ByteCode/InterpBlock.cpp
@@ -55,6 +55,16 @@ void Block::removePointer(Pointer *P) {
 #endif
 }
 
+bool Block::isWeak() const {
+  if (!(AccessFlags & WeakFlag))
+    return false;
+
+  // Sema might have dropped the weak attribute after this block was created.
+  if (const ValueDecl *VD = Desc->asValueDecl())
+    return VD->isWeak();
+  return true;
+}
+
 void Block::cleanup() {
   if (Pointers == nullptr && !isDynamic() && isDead())
     (reinterpret_cast<DeadBlock *>(this + 1) - 1)->free();
diff --git a/clang/lib/AST/ByteCode/InterpBlock.h 
b/clang/lib/AST/ByteCode/InterpBlock.h
index 4d6a2ecf813218..469601eef9e28e 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.h
+++ b/clang/lib/AST/ByteCode/InterpBlock.h
@@ -79,7 +79,7 @@ class Block final {
   bool isStatic() const { return IsStatic; }
   /// Checks if the block is temporary.
   bool isTemporary() const { return Desc->IsTemporary; }
-  bool isWeak() const { return AccessFlags & WeakFlag; }
+  bool isWeak() const;
   bool isDynamic() const { return (DynAllocId != std::nullopt); }
   bool isDead() const { return AccessFlags & DeadFlag; }
   /// Returns the size of the block, including metadata.
diff --git a/clang/test/AST/ByteCode/weak-internal-linkage.cpp 
b/clang/test/AST/ByteCode/weak-internal-linkage.cpp
new file mode 100644
index 00000000000000..359f96d01788d1
--- /dev/null
+++ b/clang/test/AST/ByteCode/weak-internal-linkage.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++03 -fexperimental-new-constant-interpreter 
-verify=expected,both %s
+// RUN: %clang_cc1 -std=c++03 -verify=ref,both %s
+// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter 
-verify=expected,both %s
+// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s
+
+/// The weak attribute is dropped after the initializer has been evaluated.
+__attribute__((weak)) const unsigned int test10_bound = 10; // both-error 
{{weak declaration cannot have internal linkage}}
+char test10_global[test10_bound];
+void test10(void) {
+  char test10_local[test10_bound] = "help";
+}
+int test10_size_check[sizeof(test10_global) == 10 ? 1 : -1];

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

Reply via email to