Skip to content

Commit 59a435b

Browse files
committed
[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.
1 parent f5fa371 commit 59a435b

File tree

4 files changed

+28
-17
lines changed

4 files changed

+28
-17
lines changed

clang/lib/AST/ByteCode/BitcastBuffer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct Bits {
2828
size_t getOffsetInByte() const { return N % 8; }
2929
bool isFullByte() const { return N % 8 == 0; }
3030
bool nonZero() const { return N != 0; }
31+
bool isZero() const { return N == 0; }
3132

3233
Bits operator-(Bits Other) { return Bits(N - Other.N); }
3334
Bits operator+(Bits Other) { return Bits(N + Other.N); }

clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
123123
bool Ok = true;
124124

125125
for (const Record::Field &Fi : R->fields()) {
126+
if (Fi.isUnnamedBitField())
127+
continue;
126128
Pointer Elem = P.atField(Fi.Offset);
127129
Bits BitOffset =
128130
Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex()));
@@ -134,6 +136,10 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
134136
Layout.getBaseClassOffset(cast<CXXRecordDecl>(B.Decl));
135137
Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset));
136138
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, F);
139+
// FIXME: We should only (need to) do this when bitcasting OUT of the
140+
// buffer, not when copying data into it.
141+
if (Ok)
142+
Elem.initialize();
137143
}
138144

139145
return Ok;
@@ -225,19 +231,29 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
225231
FromPtr, Ctx,
226232
[&](const Pointer &P, PrimType T, Bits BitOffset,
227233
bool PackedBools) -> bool {
228-
// if (!P.isInitialized()) {
229-
// assert(false && "Implement uninitialized value tracking");
230-
// return ReturnOnUninit;
231-
// }
234+
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
235+
Bits BitWidth = Bits(ASTCtx.toBits(ObjectReprChars));
236+
Bits FullBitWidth = BitWidth;
237+
238+
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) {
239+
BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx),
240+
(unsigned)FullBitWidth.getQuantity()));
241+
} else if (T == PT_Bool && PackedBools)
242+
BitWidth = Bits(1);
232243

233-
// assert(P.isInitialized());
244+
if (BitWidth.isZero())
245+
return true;
246+
247+
if (!P.isInitialized()) {
248+
assert(false && "Implement uninitialized value tracking");
249+
return ReturnOnUninit;
250+
}
251+
252+
assert(P.isInitialized());
234253
// nullptr_t is a PT_Ptr for us, but it's still not std::is_pointer_v.
235254
if (T == PT_Ptr)
236255
assert(false && "Implement casting to pointer types");
237256

238-
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
239-
Bits BitWidth = Bits(ASTCtx.toBits(ObjectReprChars));
240-
Bits FullBitWidth = BitWidth;
241257
auto Buff =
242258
std::make_unique<std::byte[]>(ObjectReprChars.getQuantity());
243259
// Work around floating point types that contain unused padding bytes.
@@ -256,12 +272,6 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
256272
swapBytes(Buff.get(), NumBits.roundToBytes());
257273

258274
} else {
259-
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
260-
BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx),
261-
(unsigned)FullBitWidth.getQuantity()));
262-
else if (T == PT_Bool && PackedBools)
263-
BitWidth = Bits(1);
264-
265275
BITCAST_TYPE_SWITCH(T, { P.deref<T>().bitcastToMemory(Buff.get()); });
266276

267277
if (llvm::sys::IsBigEndianHost)

clang/lib/AST/ByteCode/Record.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Record final {
3030
unsigned Offset;
3131
const Descriptor *Desc;
3232
bool isBitField() const { return Decl->isBitField(); }
33+
bool isUnnamedBitField() const { return Decl->isUnnamedBitField(); }
3334
};
3435

3536
/// Describes a base class.

clang/test/AST/ByteCode/builtin-bit-cast.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,8 @@ void test_record() {
335335
static_assert(t4 == tuple4{1, 2, 3, 4});
336336
static_assert(check_round_trip<tuple4>(b));
337337

338-
/// FIXME: We need to initialize the base pointers in the pointer we're bitcasting to.
339-
// constexpr auto b2 = bit_cast<bases>(t4);
340-
// static_assert(t4 == b2);
338+
constexpr auto b2 = bit_cast<bases>(t4);
339+
static_assert(t4 == b2);
341340
}
342341

343342
void test_partially_initialized() {

0 commit comments

Comments
 (0)