[clang] [clang][bytecode] Save a per-block dynamic allocation ID (PR #154094)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 18 04:12:51 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
This fixes an old todo item about wrong allocation counting and some diagnostic differences.
---
Full diff: https://github.com/llvm/llvm-project/pull/154094.diff
7 Files Affected:
- (modified) clang/lib/AST/ByteCode/Disasm.cpp (+1-1)
- (modified) clang/lib/AST/ByteCode/DynamicAllocator.cpp (+8-4)
- (modified) clang/lib/AST/ByteCode/DynamicAllocator.h (+2)
- (modified) clang/lib/AST/ByteCode/InterpBlock.cpp (+2-2)
- (modified) clang/lib/AST/ByteCode/InterpBlock.h (+7-6)
- (modified) clang/lib/AST/ByteCode/Pointer.cpp (+1-4)
- (modified) clang/test/AST/ByteCode/new-delete.cpp (+2-4)
``````````diff
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp
index 8eb785d4521a2..58e6d1a722afa 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -545,7 +545,7 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
OS << " Initialized: " << IsInitialized << "\n";
OS << " Weak: " << isWeak() << "\n";
OS << " Dummy: " << isDummy() << '\n';
- OS << " Dynamic: " << IsDynamic << "\n";
+ OS << " Dynamic: " << isDynamic() << "\n";
}
LLVM_DUMP_METHOD void EvaluationResult::dump() const {
diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
index 2d62ce7c03a44..3874e4db27007 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
@@ -101,13 +101,17 @@ Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,
ID->LifeState =
AllocForm == Form::Operator ? Lifetime::Ended : Lifetime::Started;
- B->IsDynamic = true;
-
- if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end())
+ if (auto It = AllocationSites.find(D->asExpr());
+ It != AllocationSites.end()) {
It->second.Allocations.emplace_back(std::move(Memory));
- else
+ B->setDynAllocId(It->second.NumAllocs);
+ ++It->second.NumAllocs;
+ } else {
AllocationSites.insert(
{D->asExpr(), AllocationSite(std::move(Memory), AllocForm)});
+ B->setDynAllocId(0);
+ }
+ assert(B->isDynamic());
return B;
}
diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.h b/clang/lib/AST/ByteCode/DynamicAllocator.h
index 31d0e58667c11..0f4d9bbc55b3e 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.h
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.h
@@ -47,12 +47,14 @@ class DynamicAllocator final {
};
struct AllocationSite {
+ unsigned NumAllocs = 0;
llvm::SmallVector<Allocation> Allocations;
Form AllocForm;
AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm)
: AllocForm(AllocForm) {
Allocations.push_back({std::move(Memory)});
+ ++NumAllocs;
}
size_t size() const { return Allocations.size(); }
diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp
index 69221d85d6715..345544a29b159 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.cpp
+++ b/clang/lib/AST/ByteCode/InterpBlock.cpp
@@ -64,7 +64,7 @@ void Block::removePointer(Pointer *P) {
}
void Block::cleanup() {
- if (Pointers == nullptr && !IsDynamic && isDead())
+ if (Pointers == nullptr && !isDynamic() && isDead())
(reinterpret_cast<DeadBlock *>(this + 1) - 1)->free();
}
@@ -123,7 +123,7 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
Prev = nullptr;
Root = this;
- B.IsDynamic = Blk->IsDynamic;
+ B.DynAllocId = Blk->DynAllocId;
// Transfer pointers.
B.Pointers = Blk->Pointers;
diff --git a/clang/lib/AST/ByteCode/InterpBlock.h b/clang/lib/AST/ByteCode/InterpBlock.h
index 7ded1e8649fdf..711c530528306 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.h
+++ b/clang/lib/AST/ByteCode/InterpBlock.h
@@ -62,8 +62,7 @@ class Block final {
Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,
bool IsExtern = false, bool IsWeak = false, bool IsDummy = false)
- : Desc(Desc), DeclID((unsigned)-1), EvalID(EvalID), IsStatic(IsStatic),
- IsDynamic(false) {
+ : Desc(Desc), DeclID((unsigned)-1), EvalID(EvalID), IsStatic(IsStatic) {
assert(Desc);
AccessFlags |= (ExternFlag * IsExtern);
AccessFlags |= (WeakFlag * IsWeak);
@@ -81,7 +80,7 @@ class Block final {
/// Checks if the block is temporary.
bool isTemporary() const { return Desc->IsTemporary; }
bool isWeak() const { return AccessFlags & WeakFlag; }
- bool isDynamic() const { return IsDynamic; }
+ bool isDynamic() const { return (DynAllocId != std::nullopt); }
bool isDummy() const { return AccessFlags & DummyFlag; }
bool isDead() const { return AccessFlags & DeadFlag; }
/// Returns the size of the block.
@@ -161,6 +160,9 @@ class Block final {
AccessFlags |= (DummyFlag * IsDummy);
}
+ /// To be called by DynamicAllocator.
+ void setDynAllocId(unsigned ID) { DynAllocId = ID; }
+
/// Deletes a dead block at the end of its lifetime.
void cleanup();
@@ -184,9 +186,8 @@ class Block final {
/// Flag indicating if the block contents have been initialized
/// via invokeCtor.
bool IsInitialized = false;
- /// Flag indicating if this block has been allocated via dynamic
- /// memory allocation (e.g. malloc).
- bool IsDynamic = false;
+ /// Allocation ID for this dynamic allocation, if it is one.
+ UnsignedOrNone DynAllocId = std::nullopt;
/// AccessFlags containing IsExtern, IsDead, IsWeak, and IsDummy bits.
uint8_t AccessFlags = 0;
};
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 4d70ae5974d44..7c6eb74da205c 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -179,10 +179,7 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
else if (const auto *E = Desc->asExpr()) {
if (block()->isDynamic()) {
QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);
- // FIXME: Suboptimal counting of dynamic allocations. Move this to Context
- // or InterpState?
- static int ReportedDynamicAllocs = 0;
- DynamicAllocLValue DA(ReportedDynamicAllocs++);
+ DynamicAllocLValue DA(*block()->DynAllocId);
Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
} else {
Base = E;
diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp
index c5f1878c41734..3f0e928c7664e 100644
--- a/clang/test/AST/ByteCode/new-delete.cpp
+++ b/clang/test/AST/ByteCode/new-delete.cpp
@@ -82,8 +82,7 @@ static_assert(noInit() == 0, "");
/// Try to delete a pointer that hasn't been heap allocated.
constexpr int notHeapAllocated() { // both-error {{never produces a constant expression}}
int A = 0; // both-note 2{{declared here}}
- delete &A; // ref-note 2{{delete of pointer '&A' that does not point to a heap-allocated object}} \
- // expected-note 2{{delete of pointer '&A' that does not point to a heap-allocated object}}
+ delete &A; // both-note 2{{delete of pointer '&A' that does not point to a heap-allocated object}}
return 1;
}
@@ -374,8 +373,7 @@ namespace delete_random_things {
static_assert((delete &(new A)->n, true)); // both-error {{}} \
// both-note {{delete of pointer to subobject }}
static_assert((delete (new int + 1), true)); // both-error {{}} \
- // ref-note {{delete of pointer '&{*new int#0} + 1' that does not point to complete object}} \
- // expected-note {{delete of pointer '&{*new int#1} + 1' that does not point to complete object}}
+ // both-note {{delete of pointer '&{*new int#0} + 1' that does not point to complete object}}
static_assert((delete[] (new int[3] + 1), true)); // both-error {{}} \
// both-note {{delete of pointer to subobject}}
static_assert((delete &(int&)(int&&)0, true)); // both-error {{}} \
``````````
</details>
https://github.com/llvm/llvm-project/pull/154094
More information about the cfe-commits
mailing list