https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/208990
>From 97bb802f522a084ee4694e5af2c41613a7af5cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Sun, 12 Jul 2026 08:22:49 +0200 Subject: [PATCH] diagnose reads from non-const locals --- clang/lib/AST/ByteCode/Compiler.cpp | 7 ++++++- clang/lib/AST/ByteCode/Interp.cpp | 14 ++++++++++++-- clang/test/AST/ByteCode/literals.cpp | 20 ++++++++++++++++---- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 869d3a8767617..24b44a1d02d34 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,11 @@ 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
