[clang] [clang][bytecode] Add a CheckLoad overload taking a PtrView (PR #225741)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 23 05:02:42 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
We sometimes create intermediate pointers, which always insert themselves into the pointer list of a block. Which is slow.
This adds a `CheckLoad()` overload taking a `PtrView`, which we can use in those cases.
---
Full diff: https://github.com/llvm/llvm-project/pull/225741.diff
4 Files Affected:
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+89-28)
- (modified) clang/lib/AST/ByteCode/Interp.h (+10-13)
- (modified) clang/lib/AST/ByteCode/InterpHelpers.h (+2)
- (modified) clang/lib/AST/ByteCode/Pointer.h (+2-1)
``````````diff
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 7afed0e05c886..b0c4c9b66c308 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -370,16 +370,16 @@ bool CheckBCPResult(InterpState &S, const Pointer &Ptr) {
return false;
}
-bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK, bool WillActivate) {
+static bool CheckActive(InterpState &S, CodePtr OpPC, PtrView Ptr,
+ AccessKinds AK, bool WillActivate = false) {
if (Ptr.isActive())
return true;
assert(Ptr.inUnion());
// Find the outermost union.
- PtrView U = Ptr.view().getBase();
- PtrView C = Ptr.view();
+ PtrView U = Ptr.getBase();
+ PtrView C = Ptr;
while (!U.isRoot() && !U.isActive()) {
// A little arbitrary, but this is what the current interpreter does.
// See the AnonymousUnion test in test/AST/ByteCode/unions.cpp.
@@ -413,7 +413,7 @@ bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
// non-trivial default constructor.
if (WillActivate) {
bool Fails = false;
- PtrView It = Ptr.view();
+ PtrView It = Ptr;
while (!It.isRoot() && !It.isActive()) {
if (const Record *R = It.getRecord(); R && R->isUnion()) {
if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(R->getDecl());
@@ -452,6 +452,13 @@ bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
+static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK, bool WillActivate = false) {
+ if (!Ptr.isBlockPointer())
+ return true;
+ return CheckActive(S, OpPC, Ptr.view(), AK, WillActivate);
+}
+
static bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!Ptr.isExtern())
return true;
@@ -585,6 +592,18 @@ static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return CheckConstant(S, OpPC, Ptr.getDeclDesc(), AK);
}
+static bool CheckConstant(InterpState &S, CodePtr OpPC, PtrView Ptr,
+ AccessKinds AK = AK_Read) {
+ if (S.checkingConstantDestruction(Ptr.getDeclDesc()->asVarDecl()))
+ return CheckConstant(S, OpPC, Ptr.getDeclDesc(), AK);
+
+ if (!Ptr.block()->isStatic())
+ return true;
+ if (!Ptr.block()->getDeclID())
+ return true;
+ return CheckConstant(S, OpPC, Ptr.getDeclDesc(), AK);
+}
+
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
CheckSubobjectKind CSK) {
if (!Ptr.isZero())
@@ -834,6 +853,14 @@ bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
return false;
}
+static bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, PtrView Ptr,
+ AccessKinds AK) {
+ assert(Ptr.isLive());
+ assert(!Ptr.isInitialized());
+ return diagnoseUninitialized(S, OpPC, Ptr.isExtern(), Ptr.block(),
+ Ptr.getLifetime(), AK);
+}
+
static bool CheckLifetime(InterpState &S, CodePtr OpPC, Lifetime LT,
const Block *B, AccessKinds AK) {
if (LT == Lifetime::Started)
@@ -928,25 +955,32 @@ bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
return true;
}
-bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK) {
+bool CheckLoad(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK) {
if (Ptr.isZero()) {
- const auto &Src = S.Current->getSource(OpPC);
+ SourceInfo Loc = S.Current->getSource(OpPC);
if (Ptr.isField())
- S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
+ S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK_Field;
else
- S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
+ S.FFDiag(Loc, diag::note_constexpr_access_null) << AK;
return false;
}
- // Block and string pointers are the only ones we can actually read from.
- if (!Ptr.isReadablePointerType())
- return CheckDummy(S, OpPC, Ptr, AK);
- if (Ptr.isBlockPointer() && !Ptr.block()->isAccessible()) {
- if (!CheckLive(S, OpPC, Ptr, AK))
+ if (!Ptr.block()->isAccessible()) {
+ if (!Ptr.isLive()) {
+ if (Ptr.block()->isDynamic()) {
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_access_deleted_object)
+ << AK;
+ } else if (!S.checkingPotentialConstantExpression()) {
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
+ << AK << /*uninitialized=*/false << S.Current->getRange(OpPC);
+ noteValueLocation(S, Ptr.block());
+ }
+
return false;
- if (!CheckExtern(S, OpPC, Ptr))
+ }
+ if (!CheckExtern(S, OpPC, Ptr.block()))
return false;
return CheckWeak(S, OpPC, Ptr.block());
}
@@ -960,21 +994,19 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
if (!Ptr.isInitialized())
return diagnoseUninitialized(S, OpPC, Ptr, AK);
- if (Ptr.isBlockPointer()) {
- if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), Ptr.block(), AK))
- return false;
- if (!CheckTemporary(S, OpPC, Ptr.block(), AK))
- return false;
+ if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), Ptr.block(), AK))
+ return false;
+ if (!CheckTemporary(S, OpPC, Ptr.block(), AK))
+ return false;
- if (!CheckMutable(S, OpPC, Ptr.view(), AK))
- return false;
- if (!CheckVolatile(S, OpPC, Ptr.view(), AK))
- return false;
- }
- if (isConstexprUnknown(Ptr))
+ if (!CheckMutable(S, OpPC, Ptr, AK))
+ return false;
+ if (!CheckVolatile(S, OpPC, Ptr, AK))
+ return false;
+ if (isConstexprUnknown(Ptr.block()))
return false;
- if (Ptr.isBlockPointer() && !Ptr.isArrayRoot()) {
+ if (!Ptr.isArrayRoot()) {
// According to GCC info page:
//
// 6.28 Compound Literals
@@ -1004,6 +1036,35 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return true;
}
+bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (Ptr.isBlockPointer())
+ return CheckLoad(S, OpPC, Ptr.view(), AK);
+
+ if (Ptr.isZero()) {
+ SourceInfo Loc = S.Current->getSource(OpPC);
+ if (Ptr.isField())
+ S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK_Field;
+ else
+ S.FFDiag(Loc, diag::note_constexpr_access_null) << AK;
+ return false;
+ }
+
+ // Block and string pointers are the only ones we can actually read from.
+ if (!Ptr.isReadablePointerType())
+ return CheckDummy(S, OpPC, Ptr, AK);
+
+ assert(Ptr.isStringPointer());
+
+ if (!CheckConstant(S, OpPC, Ptr, AK))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, AK))
+ return false;
+ if (!Ptr.isInitialized())
+ return diagnoseUninitialized(S, OpPC, Ptr, AK);
+ return true;
+}
+
/// This is not used by any of the opcodes directly. It's used by
/// EvalEmitter to do the final lvalue-to-rvalue conversion.
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 2eab69431c94c..aec352bc08b32 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -107,9 +107,6 @@ bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
const Pointer &Ptr);
-bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK, bool WillActivate = false);
-
/// Sets the given integral value to the pointer, which is of
/// a std::{weak,partial,strong}_ordering type.
bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
@@ -1687,10 +1684,10 @@ bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
if (!Obj.getFieldDesc()->isRecord() && !Obj.isUnknownSizeArray())
return false;
- const Pointer &Field = Obj.atField(I);
- if (!CheckLoad(S, OpPC, Field))
+ PtrView FieldPtr = Obj.view().atField(I);
+ if (!CheckLoad(S, OpPC, FieldPtr))
return false;
- S.Stk.push<T>(Field.deref<T>());
+ S.Stk.push<T>(FieldPtr.deref<T>());
return true;
}
@@ -1713,10 +1710,10 @@ bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
if (!Obj.getFieldDesc()->isRecord() && !Obj.isUnknownSizeArray())
return false;
- const Pointer &Field = Obj.atField(I);
- if (!CheckLoad(S, OpPC, Field))
+ PtrView FieldPtr = Obj.view().atField(I);
+ if (!CheckLoad(S, OpPC, FieldPtr))
return false;
- S.Stk.push<T>(Field.deref<T>());
+ S.Stk.push<T>(FieldPtr.deref<T>());
return true;
}
@@ -1731,10 +1728,10 @@ bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
if (!This.isBlockPointer())
return false;
- const Pointer &Field = This.atField(I);
- if (!CheckLoad(S, OpPC, Field))
+ PtrView FieldPtr = This.view().atField(I);
+ if (!CheckLoad(S, OpPC, FieldPtr))
return false;
- S.Stk.push<T>(Field.deref<T>());
+ S.Stk.push<T>(FieldPtr.deref<T>());
return true;
}
@@ -3598,7 +3595,7 @@ inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
return false;
for (uint32_t I = 0; I != Size; ++I) {
- const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
+ PtrView SP = SrcPtr.view().atIndex(SrcIndex + I);
if (!CheckLoad(S, OpPC, SP))
return false;
diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h b/clang/lib/AST/ByteCode/InterpHelpers.h
index 77d06598c8e2e..38a69b72e0c12 100644
--- a/clang/lib/AST/ByteCode/InterpHelpers.h
+++ b/clang/lib/AST/ByteCode/InterpHelpers.h
@@ -76,6 +76,8 @@ inline bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
/// Checks if a value can be loaded from a block.
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK = AK_Read);
+bool CheckLoad(InterpState &S, CodePtr OpPC, PtrView Ptr,
+ AccessKinds AK = AK_Read);
/// Diagnose mismatched new[]/delete or new/delete[] pairs.
bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index be59580577d14..35a0645ff34c6 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -49,6 +49,7 @@ struct PtrView {
bool isMutable() const {
return !isRoot() && getInlineDesc()->IsFieldMutable;
}
+ bool isExtern() const { return Pointee && Pointee->isExtern(); }
bool isVolatile() const {
return isRoot() ? getDeclDesc()->IsVolatile : getInlineDesc()->IsVolatile;
}
@@ -874,7 +875,7 @@ class Pointer {
/// Checks if the storage is extern.
bool isExtern() const {
if (isBlockPointer())
- return BS.Pointee && BS.Pointee->isExtern();
+ return view().isExtern();
return false;
}
/// Checks if the storage is static.
``````````
</details>
https://github.com/llvm/llvm-project/pull/225741
More information about the cfe-commits
mailing list