Skip to content

Commit 7aec6dc

Browse files
authored
[clang][bytecode] Initialize bases when bitcasting (#117179)
Base pointers do not get passed to the callback, so initialize them when iterating bases.
1 parent 3b904ae commit 7aec6dc

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
@@ -127,6 +127,8 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
127127
bool Ok = true;
128128

129129
for (const Record::Field &Fi : R->fields()) {
130+
if (Fi.isUnnamedBitField())
131+
continue;
130132
Pointer Elem = P.atField(Fi.Offset);
131133
Bits BitOffset =
132134
Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex()));
@@ -138,6 +140,10 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
138140
Layout.getBaseClassOffset(cast<CXXRecordDecl>(B.Decl));
139141
Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset));
140142
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F);
143+
// FIXME: We should only (need to) do this when bitcasting OUT of the
144+
// buffer, not when copying data into it.
145+
if (Ok)
146+
Elem.initialize();
141147
}
142148

143149
return Ok;
@@ -229,19 +235,29 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
229235
FromPtr, Ctx, Buffer.size(),
230236
[&](const Pointer &P, PrimType T, Bits BitOffset,
231237
bool PackedBools) -> bool {
232-
// if (!P.isInitialized()) {
233-
// assert(false && "Implement uninitialized value tracking");
234-
// return ReturnOnUninit;
235-
// }
238+
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
239+
Bits BitWidth = Bits(ASTCtx.toBits(ObjectReprChars));
240+
Bits FullBitWidth = BitWidth;
241+
242+
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) {
243+
BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx),
244+
(unsigned)FullBitWidth.getQuantity()));
245+
} else if (T == PT_Bool && PackedBools)
246+
BitWidth = Bits(1);
236247

237-
// assert(P.isInitialized());
248+
if (BitWidth.isZero())
249+
return true;
250+
251+
if (!P.isInitialized()) {
252+
assert(false && "Implement uninitialized value tracking");
253+
return ReturnOnUninit;
254+
}
255+
256+
assert(P.isInitialized());
238257
// nullptr_t is a PT_Ptr for us, but it's still not std::is_pointer_v.
239258
if (T == PT_Ptr)
240259
assert(false && "Implement casting to pointer types");
241260

242-
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
243-
Bits BitWidth = Bits(ASTCtx.toBits(ObjectReprChars));
244-
Bits FullBitWidth = BitWidth;
245261
auto Buff =
246262
std::make_unique<std::byte[]>(ObjectReprChars.getQuantity());
247263
// Work around floating point types that contain unused padding bytes.
@@ -260,12 +276,6 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
260276
swapBytes(Buff.get(), NumBits.roundToBytes());
261277

262278
} else {
263-
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
264-
BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx),
265-
(unsigned)FullBitWidth.getQuantity()));
266-
else if (T == PT_Bool && PackedBools)
267-
BitWidth = Bits(1);
268-
269279
BITCAST_TYPE_SWITCH(T, { P.deref<T>().bitcastToMemory(Buff.get()); });
270280

271281
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
@@ -350,9 +350,8 @@ void test_record() {
350350
static_assert(t4 == tuple4{1, 2, 3, 4});
351351
static_assert(check_round_trip<tuple4>(b));
352352

353-
/// FIXME: We need to initialize the base pointers in the pointer we're bitcasting to.
354-
// constexpr auto b2 = bit_cast<bases>(t4);
355-
// static_assert(t4 == b2);
353+
constexpr auto b2 = bit_cast<bases>(t4);
354+
static_assert(t4 == b2);
356355
}
357356

358357
void test_partially_initialized() {

0 commit comments

Comments
 (0)