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
