[clang] [clang][bytecode] Initialize bases when bitcasting (PR #117179)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 4 03:24:55 PST 2024
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/117179
>From 7c6ce4a06c822c59553dc701dc876b71f33397ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 21 Nov 2024 16:56:08 +0100
Subject: [PATCH] [clang][bytecode] Initialize bases when bitcasting
When bitcasting into a composite type, we might be initialzing all the
fields of a base, but we still need to mark the base pointer itself
as initialized.
I have a feeling we need to do the same with composite fields, too.
---
clang/lib/AST/ByteCode/BitcastBuffer.h | 1 +
.../lib/AST/ByteCode/InterpBuiltinBitCast.cpp | 38 ++++++++++++-------
clang/lib/AST/ByteCode/Record.h | 1 +
clang/test/AST/ByteCode/builtin-bit-cast.cpp | 5 +--
4 files changed, 28 insertions(+), 17 deletions(-)
diff --git a/clang/lib/AST/ByteCode/BitcastBuffer.h b/clang/lib/AST/ByteCode/BitcastBuffer.h
index 8442df5c60cf56..c7b170ceb168fa 100644
--- a/clang/lib/AST/ByteCode/BitcastBuffer.h
+++ b/clang/lib/AST/ByteCode/BitcastBuffer.h
@@ -28,6 +28,7 @@ struct Bits {
size_t getOffsetInByte() const { return N % 8; }
bool isFullByte() const { return N % 8 == 0; }
bool nonZero() const { return N != 0; }
+ bool isZero() const { return N == 0; }
Bits operator-(Bits Other) { return Bits(N - Other.N); }
Bits operator+(Bits Other) { return Bits(N + Other.N); }
diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
index 2fae7f873ab11b..8f7edaa18c74b4 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
@@ -127,6 +127,8 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
bool Ok = true;
for (const Record::Field &Fi : R->fields()) {
+ if (Fi.isUnnamedBitField())
+ continue;
Pointer Elem = P.atField(Fi.Offset);
Bits BitOffset =
Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex()));
@@ -138,6 +140,10 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
Layout.getBaseClassOffset(cast<CXXRecordDecl>(B.Decl));
Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset));
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F);
+ // FIXME: We should only (need to) do this when bitcasting OUT of the
+ // buffer, not when copying data into it.
+ if (Ok)
+ Elem.initialize();
}
return Ok;
@@ -229,19 +235,29 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
FromPtr, Ctx, Buffer.size(),
[&](const Pointer &P, PrimType T, Bits BitOffset,
bool PackedBools) -> bool {
- // if (!P.isInitialized()) {
- // assert(false && "Implement uninitialized value tracking");
- // return ReturnOnUninit;
- // }
+ CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
+ Bits BitWidth = Bits(ASTCtx.toBits(ObjectReprChars));
+ Bits FullBitWidth = BitWidth;
+
+ if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) {
+ BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx),
+ (unsigned)FullBitWidth.getQuantity()));
+ } else if (T == PT_Bool && PackedBools)
+ BitWidth = Bits(1);
- // assert(P.isInitialized());
+ if (BitWidth.isZero())
+ return true;
+
+ if (!P.isInitialized()) {
+ assert(false && "Implement uninitialized value tracking");
+ return ReturnOnUninit;
+ }
+
+ assert(P.isInitialized());
// nullptr_t is a PT_Ptr for us, but it's still not std::is_pointer_v.
if (T == PT_Ptr)
assert(false && "Implement casting to pointer types");
- CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
- Bits BitWidth = Bits(ASTCtx.toBits(ObjectReprChars));
- Bits FullBitWidth = BitWidth;
auto Buff =
std::make_unique<std::byte[]>(ObjectReprChars.getQuantity());
// Work around floating point types that contain unused padding bytes.
@@ -260,12 +276,6 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
swapBytes(Buff.get(), NumBits.roundToBytes());
} else {
- if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
- BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx),
- (unsigned)FullBitWidth.getQuantity()));
- else if (T == PT_Bool && PackedBools)
- BitWidth = Bits(1);
-
BITCAST_TYPE_SWITCH(T, { P.deref<T>().bitcastToMemory(Buff.get()); });
if (llvm::sys::IsBigEndianHost)
diff --git a/clang/lib/AST/ByteCode/Record.h b/clang/lib/AST/ByteCode/Record.h
index 7a5c482e4efccd..686b5dbc431d99 100644
--- a/clang/lib/AST/ByteCode/Record.h
+++ b/clang/lib/AST/ByteCode/Record.h
@@ -30,6 +30,7 @@ class Record final {
unsigned Offset;
const Descriptor *Desc;
bool isBitField() const { return Decl->isBitField(); }
+ bool isUnnamedBitField() const { return Decl->isUnnamedBitField(); }
};
/// Describes a base class.
diff --git a/clang/test/AST/ByteCode/builtin-bit-cast.cpp b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
index e956675b18b85f..d3935b4f921b3f 100644
--- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp
+++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
@@ -350,9 +350,8 @@ void test_record() {
static_assert(t4 == tuple4{1, 2, 3, 4});
static_assert(check_round_trip<tuple4>(b));
- /// FIXME: We need to initialize the base pointers in the pointer we're bitcasting to.
-// constexpr auto b2 = bit_cast<bases>(t4);
-// static_assert(t4 == b2);
+ constexpr auto b2 = bit_cast<bases>(t4);
+ static_assert(t4 == b2);
}
void test_partially_initialized() {
More information about the cfe-commits
mailing list