[clang] a699b25 - [clang][bytecode] Check reference initializers for one-past-the-end pointers (#195501)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 4 03:14:33 PDT 2026
Author: Timm Baeder
Date: 2026-05-04T12:14:29+02:00
New Revision: a699b25b924cbd1002f42d6d8e4a23e105c2f62d
URL: https://github.com/llvm/llvm-project/commit/a699b25b924cbd1002f42d6d8e4a23e105c2f62d
DIFF: https://github.com/llvm/llvm-project/commit/a699b25b924cbd1002f42d6d8e4a23e105c2f62d.diff
LOG: [clang][bytecode] Check reference initializers for one-past-the-end pointers (#195501)
Added:
Modified:
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Interp.h
clang/lib/AST/ByteCode/Opcodes.td
clang/test/AST/ByteCode/cxx14.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 2f78d2054c5a4..11c5478a5c748 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5238,8 +5238,9 @@ template <class Emitter>
VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
const Expr *Init,
bool Toplevel) {
+ QualType VarTy = VD->getType();
// We don't know what to do with these, so just return false.
- if (VD->getType().isNull())
+ if (VarTy.isNull())
return false;
// This case is EvalEmitter-only. If we won't create any instructions for the
@@ -5299,8 +5300,8 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
if (VarT) {
unsigned Offset = this->allocateLocalPrimitive(
- VD, *VarT, VD->getType().isConstQualified(),
- VD->getType().isVolatileQualified(), ScopeKind::Block);
+ VD, *VarT, VarTy.isConstQualified(), VarTy.isVolatileQualified(),
+ ScopeKind::Block);
if (!Init || Init->getType()->isVoidType())
return true;
@@ -5315,11 +5316,23 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
}
if (!this->visit(Init))
return false;
+
+ if (VarTy->isReferenceType()) {
+ // [C++26][decl.ref]
+ // The object designated by such a glvalue can be outside its lifetime
+ // Because a null pointer value or a pointer past the end of an object
+ // does not point to an object, a reference in a well-defined program
+ // cannot refer to such things;
+ assert(classifyPrim(VarTy) == PT_Ptr);
+ if (!this->emitCheckRefInit(Init))
+ return false;
+ }
+
return this->emitSetLocal(*VarT, Offset, VD);
}
// Local composite variables.
if (UnsignedOrNone Offset =
- this->allocateLocal(VD, VD->getType(), ScopeKind::Block)) {
+ this->allocateLocal(VD, VarTy, ScopeKind::Block)) {
if (!Init)
return true;
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index f89ff3f18ce9d..fca61e3b310f1 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1977,6 +1977,11 @@ inline bool GetRefLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
return handleReference(S, OpPC, LocalBlock);
}
+inline bool CheckRefInit(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ return CheckRange(S, OpPC, Ptr, AK_Read);
+}
+
inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t Index) {
if (S.Current->isBottomFrame())
return false;
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index ba2414590eacb..3fb25a5fa0884 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -325,6 +325,9 @@ def GetPtrLocal : OffsetOpcode {
def GetRefLocal : OffsetOpcode {
bit HasCustomEval = 1;
}
+
+def CheckRefInit : Opcode {}
+
// [] -> [Pointer]
def GetPtrParam : OffsetOpcode;
// [] -> [Pointer]
diff --git a/clang/test/AST/ByteCode/cxx14.cpp b/clang/test/AST/ByteCode/cxx14.cpp
index 57cb42ea4a98b..00a9cf5b00098 100644
--- a/clang/test/AST/ByteCode/cxx14.cpp
+++ b/clang/test/AST/ByteCode/cxx14.cpp
@@ -28,3 +28,10 @@ constexpr int foo() {
return s.b[0];
}
static_assert(foo() == 12, "");
+
+int arr[3]; // both-note {{declared here}}
+constexpr bool f() { // both-error {{constexpr function never produces a constant expression}}
+ int &r = arr[3]; // both-note {{read of dereferenced one-past-the-end pointer}} \
+ // both-warning {{array index 3 is past the end of the array}}
+ return true;
+}
More information about the cfe-commits
mailing list