Author: Timm Baeder
Date: 2026-07-13T11:04:33+02:00
New Revision: 3de2e4a3f11390db0c026f54edf86bd8f6997947

URL: 
https://github.com/llvm/llvm-project/commit/3de2e4a3f11390db0c026f54edf86bd8f6997947
DIFF: 
https://github.com/llvm/llvm-project/commit/3de2e4a3f11390db0c026f54edf86bd8f6997947.diff

LOG: [clang][bytecode] diagnose reads from non-constant local variables... 
(#208990)

... if we're in the bottom frame.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Compiler.cpp
    clang/lib/AST/ByteCode/Interp.cpp
    clang/test/AST/ByteCode/literals.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index a50980d23d3b2..54aa505a7d306 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5501,6 +5501,7 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl 
*VD, const Expr *Init,
     return false;
 
   OptPrimType VarT = classify(VD->getType());
+  bool IsReference = VD->getType()->isReferenceType();
   if (Context::shouldBeGloballyIndexed(VD)) {
     auto GlobalIndex = P.getGlobal(VD);
     assert(GlobalIndex); // visitVarDecl() didn't return false.
@@ -5515,7 +5516,10 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl 
*VD, const Expr *Init,
     auto Local = Locals.find(VD);
     assert(Local != Locals.end()); // Same here.
     if (VarT) {
-      if (!this->emitGetLocal(*VarT, Local->second.Offset, VD))
+      if (IsReference) {
+        if (!this->emitGetRefLocal(Local->second.Offset, VD))
+          return false;
+      } else if (!this->emitGetLocal(*VarT, Local->second.Offset, VD))
         return false;
     } else {
       if (!this->emitGetPtrLocal(Local->second.Offset, VD))

diff  --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index e4675978e2a18..20235b07fcc47 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -857,21 +857,31 @@ bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const 
Block *B) {
 bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
   assert(!B->isExtern());
   const auto &Desc = *reinterpret_cast<const InlineDescriptor *>(B->rawData());
+  const Descriptor *BlockDesc = B->getDescriptor();
   if (!CheckLifetime(S, OpPC, Desc.LifeState, B, AK_Read))
     return false;
   if (!Desc.IsInitialized)
     return DiagnoseUninitialized(S, OpPC, /*Extern=*/false, B, AK_Read);
-  if (B->getDescriptor()->IsVolatile) {
+  if (BlockDesc->IsVolatile) {
     if (!S.getLangOpts().CPlusPlus)
       return Invalid(S, OpPC);
 
-    const ValueDecl *D = B->getDescriptor()->asValueDecl();
+    const ValueDecl *D = BlockDesc->asValueDecl();
     S.FFDiag(S.Current->getLocation(OpPC),
              diag::note_constexpr_access_volatile_obj, 1)
         << AK_Read << 1 << D;
     S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1;
     return false;
   }
+
+  // A non-const local variable while we don't have a parent frame. This must 
be
+  // a local variable in a statement expression.
+  if (S.Current->isBottomFrame() && !BlockDesc->IsConst &&
+      !BlockDesc->IsTemporary && !S.checkingPotentialConstantExpression()) {
+    if (const ValueDecl *VD = BlockDesc->asValueDecl())
+      diagnoseNonConstVariable(S, OpPC, VD);
+    return false;
+  }
   return true;
 }
 

diff  --git a/clang/test/AST/ByteCode/literals.cpp 
b/clang/test/AST/ByteCode/literals.cpp
index eafab2e1ab64d..3b24b166e39a7 100644
--- a/clang/test/AST/ByteCode/literals.cpp
+++ b/clang/test/AST/ByteCode/literals.cpp
@@ -1326,17 +1326,29 @@ namespace StmtExprs {
     constexpr long a(bool x) { return x ? 0 : (intptr_t)&&lbl + (0 && ({lbl: 
0;})); }
   }
 
-  /// GCC agrees with the bytecode interpreter here.
+  /// FIXME: This should be accepted.
+  /// BUT accepting this breaks test/OpenMP/for_codegen.cpp
   void switchInSE() {
-    static_assert(({ // ref-error {{not an integral constant expression}}
-          int i = 20;
+    static_assert(({ // both-error {{not an integral constant expression}}
+          int i = 20; // expected-note {{declared here}}
            switch(10) {
-             case 10: i = 300; // ref-note {{a constant expression cannot 
modify an object that is visible outside that expression}}
+             case 10: i = 300; // ref-note {{a constant expression cannot 
modify an object that is visible outside that expression}} \
+                               //  expected-note {{read of non-const variable 
'i'}}
            }
            i;
         }) == 300);
   }
 
+  /// We reject the test above because of the read from i, not because of the 
modification.
+  /// FIXME: The sourcelocation for the broken read is incorrect.
+  void switchInSE2() {
+    static_assert(({ // both-error {{not an integral constant expression}}
+          int i = 20; // expected-note {{read of non-const variable}} \
+                      // both-note {{declared here}}
+           i; // ref-note {{read of non-const variable}}
+        }) == 300);
+  }
+
   constexpr int f(int k) {
     switch (k) {
     case 0:


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

Reply via email to