[clang] 7a6c981 - [clang][bytecode] Add AccessFlags to Block (#152590)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 9 06:46:32 PDT 2025
Author: Timm Baeder
Date: 2025-08-09T15:46:28+02:00
New Revision: 7a6c9813d69bf390ab2db3b060305b6aade7703b
URL: https://github.com/llvm/llvm-project/commit/7a6c9813d69bf390ab2db3b060305b6aade7703b
DIFF: https://github.com/llvm/llvm-project/commit/7a6c9813d69bf390ab2db3b060305b6aade7703b.diff
LOG: [clang][bytecode] Add AccessFlags to Block (#152590)
This way, we can check a single uint8_t for != 0 to know whether this
block is accessible or not. If not, we still need to figure out why not
and diagnose appropriately of course.
Added:
Modified:
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Descriptor.cpp
clang/lib/AST/ByteCode/Descriptor.h
clang/lib/AST/ByteCode/Disasm.cpp
clang/lib/AST/ByteCode/DynamicAllocator.cpp
clang/lib/AST/ByteCode/Interp.cpp
clang/lib/AST/ByteCode/InterpBlock.cpp
clang/lib/AST/ByteCode/InterpBlock.h
clang/lib/AST/ByteCode/InterpBuiltin.cpp
clang/lib/AST/ByteCode/InterpState.cpp
clang/lib/AST/ByteCode/Pointer.h
clang/lib/AST/ByteCode/Program.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 9db2011417e71..f131ac17c11bb 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7140,10 +7140,6 @@ bool Compiler<Emitter>::emitDestruction(const Descriptor *Desc,
assert(!Desc->isPrimitive());
assert(!Desc->isPrimitiveArray());
- // Can happen if the decl is invalid.
- if (Desc->isDummy())
- return true;
-
// Arrays.
if (Desc->isArray()) {
const Descriptor *ElemDesc = Desc->ElemDesc;
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp
index 07df2b971070d..234fa2c8cd8fb 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -367,7 +367,7 @@ Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)
: Source(D), ElemSize(1), Size(1), MDSize(MD.value_or(0)),
AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),
- IsTemporary(false), IsDummy(true) {
+ IsTemporary(false) {
assert(Source && "Missing source");
}
@@ -455,7 +455,7 @@ SourceInfo Descriptor::getLoc() const {
}
bool Descriptor::hasTrivialDtor() const {
- if (isPrimitive() || isPrimitiveArray() || isDummy())
+ if (isPrimitive() || isPrimitiveArray())
return true;
if (isRecord()) {
@@ -464,8 +464,9 @@ bool Descriptor::hasTrivialDtor() const {
return !Dtor || Dtor->isTrivial();
}
+ if (!ElemDesc)
+ return true;
// Composite arrays.
- assert(ElemDesc);
return ElemDesc->hasTrivialDtor();
}
diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h
index cd34e11a67151..4a808c0a2d216 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -166,8 +166,6 @@ struct Descriptor final {
const bool IsVolatile = false;
/// Flag indicating if the block is an array.
const bool IsArray = false;
- /// Flag indicating if this is a dummy descriptor.
- bool IsDummy = false;
bool IsConstexprUnknown = false;
/// Storage management methods.
@@ -203,9 +201,6 @@ struct Descriptor final {
/// Allocates a dummy descriptor.
Descriptor(const DeclTy &D, MetadataSize MD = std::nullopt);
- /// Make this descriptor a dummy descriptor.
- void makeDummy() { IsDummy = true; }
-
QualType getType() const;
QualType getElemQualType() const;
QualType getDataType(const ASTContext &Ctx) const;
@@ -273,8 +268,6 @@ struct Descriptor final {
bool isRecord() const { return !IsArray && ElemRecord; }
/// Checks if the descriptor is of a union.
bool isUnion() const;
- /// Checks if this is a dummy descriptor.
- bool isDummy() const { return IsDummy; }
/// Whether variables of this descriptor need their destructor called or not.
bool hasTrivialDtor() const;
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp
index 5049a6545eef6..8eb785d4521a2 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -338,7 +338,7 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
}
OS << "\n";
- if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) {
+ if (GP.isInitialized() && Desc->isPrimitive() && !G->block()->isDummy()) {
OS << " ";
{
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});
@@ -394,8 +394,6 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {
else if (isUnknownSizeArray())
OS << " unknown-size-array";
- if (isDummy())
- OS << " dummy";
if (IsConstexprUnknown)
OS << " constexpr-unknown";
}
@@ -541,11 +539,12 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
else
OS << "-\n";
OS << " Pointers: " << NPointers << "\n";
- OS << " Dead: " << IsDead << "\n";
+ OS << " Dead: " << isDead() << "\n";
OS << " Static: " << IsStatic << "\n";
- OS << " Extern: " << IsExtern << "\n";
+ OS << " Extern: " << isExtern() << "\n";
OS << " Initialized: " << IsInitialized << "\n";
- OS << " Weak: " << IsWeak << "\n";
+ OS << " Weak: " << isWeak() << "\n";
+ OS << " Dummy: " << isDummy() << '\n';
OS << " Dynamic: " << IsDynamic << "\n";
}
diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
index f38d585336d96..2d62ce7c03a44 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
@@ -24,7 +24,7 @@ void DynamicAllocator::cleanup() {
auto &AllocSite = Iter.second;
for (auto &Alloc : AllocSite.Allocations) {
Block *B = Alloc.block();
- assert(!B->IsDead);
+ assert(!B->isDead());
assert(B->isInitialized());
B->invokeDtor();
@@ -121,7 +121,7 @@ bool DynamicAllocator::deallocate(const Expr *Source,
assert(!Site.empty());
// Find the Block to delete.
- auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
+ auto *AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
return BlockToDelete == A.block();
});
@@ -129,7 +129,7 @@ bool DynamicAllocator::deallocate(const Expr *Source,
Block *B = AllocIt->block();
assert(B->isInitialized());
- assert(!B->IsDead);
+ assert(!B->isDead());
B->invokeDtor();
// Almost all our dynamic allocations have a pointer pointing to them
@@ -139,7 +139,7 @@ bool DynamicAllocator::deallocate(const Expr *Source,
// over to a DeadBlock and simply keep the block in a separate DeadAllocations
// list.
if (B->hasPointers()) {
- B->IsDead = true;
+ B->AccessFlags |= Block::DeadFlag;
DeadAllocations.push_back(std::move(*AllocIt));
Site.Allocations.erase(AllocIt);
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index da8a65e90a2ae..73507d2725a3f 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -738,19 +738,21 @@ static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B) {
bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
const auto &Desc =
*reinterpret_cast<const GlobalInlineDescriptor *>(B->rawData());
- if (!CheckExtern(S, OpPC, Pointer(const_cast<Block *>(B))))
- return false;
+ if (!B->isAccessible()) {
+ if (!CheckExtern(S, OpPC, Pointer(const_cast<Block *>(B))))
+ return false;
+ if (!CheckDummy(S, OpPC, B, AK_Read))
+ return false;
+ return CheckWeak(S, OpPC, B);
+ }
+
if (!CheckConstant(S, OpPC, B->getDescriptor()))
return false;
- if (!CheckDummy(S, OpPC, B, AK_Read))
- return false;
if (Desc.InitState != GlobalInitState::Initialized)
return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(),
AK_Read);
if (!CheckTemporary(S, OpPC, B, AK_Read))
return false;
- if (!CheckWeak(S, OpPC, B))
- return false;
if (B->getDescriptor()->IsVolatile) {
if (!S.getLangOpts().CPlusPlus)
return Invalid(S, OpPC);
@@ -790,14 +792,32 @@ bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
- if (!CheckLive(S, OpPC, Ptr, AK))
- return false;
- if (!CheckExtern(S, OpPC, Ptr))
+ if (!Ptr.isBlockPointer()) {
+ if (Ptr.isZero()) {
+ const auto &Src = S.Current->getSource(OpPC);
+
+ if (Ptr.isField())
+ S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
+ else
+ S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
+ }
return false;
+ }
+
+ // Block pointers are the only ones we can actually read from.
+ if (!Ptr.block()->isAccessible()) {
+ if (!CheckLive(S, OpPC, Ptr, AK))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckDummy(S, OpPC, Ptr.block(), AK))
+ return false;
+ if (!CheckWeak(S, OpPC, Ptr.block()))
+ return false;
+ }
+
if (!CheckConstant(S, OpPC, Ptr))
return false;
- if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK))
- return false;
if (!CheckRange(S, OpPC, Ptr, AK))
return false;
if (!CheckActive(S, OpPC, Ptr, AK))
@@ -806,10 +826,9 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
if (!Ptr.isInitialized())
return DiagnoseUninitialized(S, OpPC, Ptr, AK);
- if (Ptr.isBlockPointer() && !CheckTemporary(S, OpPC, Ptr.block(), AK))
- return false;
- if (Ptr.isBlockPointer() && !CheckWeak(S, OpPC, Ptr.block()))
+ if (!CheckTemporary(S, OpPC, Ptr.block(), AK))
return false;
+
if (!CheckMutable(S, OpPC, Ptr))
return false;
if (!CheckVolatile(S, OpPC, Ptr, AK))
@@ -820,24 +839,39 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
/// 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) {
- if (!CheckLive(S, OpPC, Ptr, AK_Read))
+ if (!Ptr.isBlockPointer()) {
+ if (Ptr.isZero()) {
+ const auto &Src = S.Current->getSource(OpPC);
+
+ if (Ptr.isField())
+ S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
+ else
+ S.FFDiag(Src, diag::note_constexpr_access_null) << AK_Read;
+ }
return false;
+ }
+
+ assert(Ptr.isBlockPointer());
+ if (!Ptr.block()->isAccessible()) {
+ if (!CheckLive(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckDummy(S, OpPC, Ptr.block(), AK_Read))
+ return false;
+ return CheckWeak(S, OpPC, Ptr.block());
+ }
+
if (!CheckConstant(S, OpPC, Ptr))
return false;
- if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Read))
- return false;
- if (!CheckExtern(S, OpPC, Ptr))
- return false;
if (!CheckActive(S, OpPC, Ptr, AK_Read))
return false;
if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Read))
return false;
if (!Ptr.isInitialized())
return DiagnoseUninitialized(S, OpPC, Ptr, AK_Read);
- if (Ptr.isBlockPointer() && !CheckTemporary(S, OpPC, Ptr.block(), AK_Read))
- return false;
- if (Ptr.isBlockPointer() && !CheckWeak(S, OpPC, Ptr.block()))
+ if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Read))
return false;
if (!CheckMutable(S, OpPC, Ptr))
return false;
@@ -845,10 +879,14 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
}
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!CheckLive(S, OpPC, Ptr, AK_Assign))
- return false;
- if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Assign))
+ if (!Ptr.isBlockPointer())
return false;
+
+ if (!Ptr.block()->isAccessible()) {
+ if (!CheckLive(S, OpPC, Ptr, AK_Assign))
+ return false;
+ return CheckDummy(S, OpPC, Ptr.block(), AK_Assign);
+ }
if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Assign))
return false;
if (!CheckExtern(S, OpPC, Ptr))
@@ -1124,11 +1162,10 @@ bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
}
bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) {
- const Descriptor *Desc = B->getDescriptor();
- if (!Desc->isDummy())
+ if (!B->isDummy())
return true;
- const ValueDecl *D = Desc->asValueDecl();
+ const ValueDecl *D = B->getDescriptor()->asValueDecl();
if (!D)
return false;
@@ -1835,14 +1872,21 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
if (Ptr.inUnion() && Ptr.getBase().getRecord()->isUnion())
Ptr.activate();
+ if (!Ptr.isBlockPointer())
+ return false;
+
// Similar to CheckStore(), but with the additional CheckTemporary() call and
// the AccessKinds are
diff erent.
+
+ if (!Ptr.block()->isAccessible()) {
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckLive(S, OpPC, Ptr, AK_Construct))
+ return false;
+ return CheckDummy(S, OpPC, Ptr.block(), AK_Construct);
+ }
if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Construct))
return false;
- if (!CheckLive(S, OpPC, Ptr, AK_Construct))
- return false;
- if (!CheckDummy(S, OpPC, Ptr.block(), AK_Construct))
- return false;
// CheckLifetime for this and all base pointers.
for (Pointer P = Ptr;;) {
@@ -1853,8 +1897,7 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
break;
P = P.getBase();
}
- if (!CheckExtern(S, OpPC, Ptr))
- return false;
+
if (!CheckRange(S, OpPC, Ptr, AK_Construct))
return false;
if (!CheckGlobal(S, OpPC, Ptr))
diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp
index 8b7f6a750040b..69221d85d6715 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();
}
@@ -113,8 +113,8 @@ bool Block::hasPointer(const Pointer *P) const {
#endif
DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
- : Root(Root), B(~0u, Blk->Desc, Blk->IsStatic, Blk->IsExtern, Blk->IsWeak,
- /*isDead=*/true) {
+ : Root(Root), B(~0u, Blk->Desc, Blk->isExtern(), Blk->IsStatic,
+ Blk->isWeak(), Blk->isDummy(), /*IsDead=*/true) {
// Add the block to the chain of dead blocks.
if (Root)
Root->Prev = this;
diff --git a/clang/lib/AST/ByteCode/InterpBlock.h b/clang/lib/AST/ByteCode/InterpBlock.h
index 07194d6d1b3b2..7ded1e8649fdf 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.h
+++ b/clang/lib/AST/ByteCode/InterpBlock.h
@@ -42,21 +42,32 @@ enum PrimType : unsigned;
/// the data size and the metadata size.
///
class Block final {
+private:
+ static constexpr uint8_t ExternFlag = 1 << 0;
+ static constexpr uint8_t DeadFlag = 1 << 1;
+ static constexpr uint8_t WeakFlag = 1 << 2;
+ static constexpr uint8_t DummyFlag = 1 << 3;
+
public:
/// Creates a new block.
Block(unsigned EvalID, const std::optional<unsigned> &DeclID,
const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false,
- bool IsWeak = false)
- : EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern),
- IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
+ bool IsWeak = false, bool IsDummy = false)
+ : Desc(Desc), DeclID(DeclID), EvalID(EvalID), IsStatic(IsStatic) {
assert(Desc);
+ AccessFlags |= (ExternFlag * IsExtern);
+ AccessFlags |= (WeakFlag * IsWeak);
+ AccessFlags |= (DummyFlag * IsDummy);
}
Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,
- bool IsExtern = false, bool IsWeak = false)
- : EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic),
- IsExtern(IsExtern), IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
+ bool IsExtern = false, bool IsWeak = false, bool IsDummy = false)
+ : Desc(Desc), DeclID((unsigned)-1), EvalID(EvalID), IsStatic(IsStatic),
+ IsDynamic(false) {
assert(Desc);
+ AccessFlags |= (ExternFlag * IsExtern);
+ AccessFlags |= (WeakFlag * IsWeak);
+ AccessFlags |= (DummyFlag * IsDummy);
}
/// Returns the block's descriptor.
@@ -64,13 +75,15 @@ class Block final {
/// Checks if the block has any live pointers.
bool hasPointers() const { return Pointers; }
/// Checks if the block is extern.
- bool isExtern() const { return IsExtern; }
+ bool isExtern() const { return AccessFlags & ExternFlag; }
/// Checks if the block has static storage duration.
bool isStatic() const { return IsStatic; }
/// Checks if the block is temporary.
bool isTemporary() const { return Desc->IsTemporary; }
- bool isWeak() const { return IsWeak; }
+ bool isWeak() const { return AccessFlags & WeakFlag; }
bool isDynamic() const { return IsDynamic; }
+ bool isDummy() const { return AccessFlags & DummyFlag; }
+ bool isDead() const { return AccessFlags & DeadFlag; }
/// Returns the size of the block.
unsigned getSize() const { return Desc->getAllocSize(); }
/// Returns the declaration ID.
@@ -130,6 +143,8 @@ class Block final {
void dump() const { dump(llvm::errs()); }
void dump(llvm::raw_ostream &OS) const;
+ bool isAccessible() const { return AccessFlags == 0; }
+
private:
friend class Pointer;
friend class DeadBlock;
@@ -137,10 +152,13 @@ class Block final {
friend class DynamicAllocator;
Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic,
- bool IsWeak, bool IsDead)
- : EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true),
- IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
+ bool IsWeak, bool IsDummy, bool IsDead)
+ : Desc(Desc), EvalID(EvalID), IsStatic(IsStatic) {
assert(Desc);
+ AccessFlags |= (ExternFlag * IsExtern);
+ AccessFlags |= (DeadFlag * IsDead);
+ AccessFlags |= (WeakFlag * IsWeak);
+ AccessFlags |= (DummyFlag * IsDummy);
}
/// Deletes a dead block at the end of its lifetime.
@@ -154,27 +172,23 @@ class Block final {
bool hasPointer(const Pointer *P) const;
#endif
- const unsigned EvalID = ~0u;
+ /// Pointer to the stack slot descriptor.
+ const Descriptor *Desc;
/// Start of the chain of pointers.
Pointer *Pointers = nullptr;
/// Unique identifier of the declaration.
std::optional<unsigned> DeclID;
+ const unsigned EvalID = ~0u;
/// Flag indicating if the block has static storage duration.
bool IsStatic = false;
- /// Flag indicating if the block is an extern.
- bool IsExtern = false;
- /// Flag indicating if the pointer is dead. This is only ever
- /// set once, when converting the Block to a DeadBlock.
- bool IsDead = false;
/// 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;
- bool IsWeak = false;
- /// Pointer to the stack slot descriptor.
- const Descriptor *Desc;
+ /// AccessFlags containing IsExtern, IsDead, IsWeak, and IsDummy bits.
+ uint8_t AccessFlags = 0;
};
/// Descriptor for a dead block.
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index addda44ac717a..8dc22c453d1f2 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1785,6 +1785,13 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
return false;
QualType DestElemType = getElemType(DestPtr);
+ if (DestElemType->isIncompleteType()) {
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_ltor_incomplete_type)
+ << DestElemType;
+ return false;
+ }
+
size_t RemainingDestElems;
if (DestPtr.getFieldDesc()->isArray()) {
RemainingDestElems = DestPtr.isUnknownSizeArray()
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp
index 32f940c262325..b5f0f9a44f344 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -77,6 +77,9 @@ bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) {
void InterpState::deallocate(Block *B) {
assert(B);
assert(!B->isDynamic());
+ assert(!B->isStatic());
+ assert(!B->isDead());
+
// The block might have a pointer saved in a field in its data
// that points to the block itself. We call the dtor first,
// which will destroy all the data but leave InlineDescriptors
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 5bafc5b108ee9..94c83a0d87bc4 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -282,7 +282,7 @@ class Pointer {
bool isLive() const {
if (!isBlockPointer())
return true;
- return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead;
+ return asBlockPointer().Pointee && !asBlockPointer().Pointee->isDead();
}
/// Checks if the item is a field in an object.
bool isField() const {
@@ -568,10 +568,9 @@ class Pointer {
if (!isBlockPointer())
return false;
- if (!asBlockPointer().Pointee)
- return false;
-
- return getDeclDesc()->isDummy();
+ if (const Block *Pointee = asBlockPointer().Pointee)
+ return Pointee->isDummy();
+ return false;
}
/// Checks if an object or a subfield is mutable.
diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp
index ee9e8f24522b6..2843b325fe025 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -180,17 +180,15 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) {
Desc = allocateDescriptor(D);
assert(Desc);
- Desc->makeDummy();
-
- assert(Desc->isDummy());
// Allocate a block for storage.
unsigned I = Globals.size();
auto *G = new (Allocator, Desc->getAllocSize())
Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true,
- /*IsExtern=*/false, IsWeak);
+ /*IsExtern=*/false, IsWeak, /*IsDummy=*/true);
G->block()->invokeCtor();
+ assert(G->block()->isDummy());
Globals.push_back(G);
DummyVariables[D.getOpaqueValue()] = I;
More information about the cfe-commits
mailing list