Skip to content

Commit 56fd46e

Browse files
authored
[clang][bytecode] Remove a bitcast nullptr_t special case (llvm#120188)
We still need to check the input pointer, so let this go through BitCastPrim.
1 parent 8ea9576 commit 56fd46e

File tree

4 files changed

+48
-39
lines changed

4 files changed

+48
-39
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6483,14 +6483,6 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
64836483
QualType ToType = E->getType();
64846484
std::optional<PrimType> ToT = classify(ToType);
64856485

6486-
// Bitcasting TO nullptr_t is always fine.
6487-
if (ToType->isNullPtrType()) {
6488-
if (!this->discard(SubExpr))
6489-
return false;
6490-
6491-
return this->emitNullPtr(0, nullptr, E);
6492-
}
6493-
64946486
assert(!ToType->isReferenceType());
64956487

64966488
// Prepare storage for the result in case we discard.
@@ -6523,8 +6515,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
65236515
return false;
65246516
}
65256517

6526-
if (!ToT || ToT == PT_Ptr) {
6527-
if (!this->emitBitCastPtr(E))
6518+
if (!ToT) {
6519+
if (!this->emitBitCast(E))
65286520
return false;
65296521
return DiscardResult ? this->emitPopPtr(E) : true;
65306522
}
@@ -6540,8 +6532,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
65406532
ToType->isSpecificBuiltinType(BuiltinType::Char_U));
65416533
uint32_t ResultBitWidth = std::max(Ctx.getBitWidth(ToType), 8u);
65426534

6543-
if (!this->emitBitCast(*ToT, ToTypeIsUChar || ToType->isStdByteType(),
6544-
ResultBitWidth, TargetSemantics, E))
6535+
if (!this->emitBitCastPrim(*ToT, ToTypeIsUChar || ToType->isStdByteType(),
6536+
ResultBitWidth, TargetSemantics, E))
65456537
return false;
65466538

65476539
if (DiscardResult)

clang/lib/AST/ByteCode/Interp.h

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3030,43 +3030,51 @@ bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
30303030
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
30313031

30323032
template <PrimType Name, class T = typename PrimConv<Name>::T>
3033-
inline bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
3034-
uint32_t ResultBitWidth, const llvm::fltSemantics *Sem) {
3033+
inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
3034+
uint32_t ResultBitWidth,
3035+
const llvm::fltSemantics *Sem) {
30353036
const Pointer &FromPtr = S.Stk.pop<Pointer>();
30363037

30373038
if (!CheckLoad(S, OpPC, FromPtr))
30383039
return false;
30393040

3040-
size_t BuffSize = ResultBitWidth / 8;
3041-
llvm::SmallVector<std::byte> Buff(BuffSize);
3042-
bool HasIndeterminateBits = false;
3041+
if constexpr (std::is_same_v<T, Pointer>) {
3042+
// The only pointer type we can validly bitcast to is nullptr_t.
3043+
S.Stk.push<Pointer>();
3044+
return true;
3045+
} else {
30433046

3044-
Bits FullBitWidth(ResultBitWidth);
3045-
Bits BitWidth = FullBitWidth;
3047+
size_t BuffSize = ResultBitWidth / 8;
3048+
llvm::SmallVector<std::byte> Buff(BuffSize);
3049+
bool HasIndeterminateBits = false;
30463050

3047-
if constexpr (std::is_same_v<T, Floating>) {
3048-
assert(Sem);
3049-
BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
3050-
}
3051+
Bits FullBitWidth(ResultBitWidth);
3052+
Bits BitWidth = FullBitWidth;
30513053

3052-
if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3053-
HasIndeterminateBits))
3054-
return false;
3054+
if constexpr (std::is_same_v<T, Floating>) {
3055+
assert(Sem);
3056+
BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
3057+
}
30553058

3056-
if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3057-
return false;
3059+
if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3060+
HasIndeterminateBits))
3061+
return false;
30583062

3059-
if constexpr (std::is_same_v<T, Floating>) {
3060-
assert(Sem);
3061-
S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
3062-
} else {
3063-
assert(!Sem);
3064-
S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3063+
if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3064+
return false;
3065+
3066+
if constexpr (std::is_same_v<T, Floating>) {
3067+
assert(Sem);
3068+
S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
3069+
} else {
3070+
assert(!Sem);
3071+
S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3072+
}
3073+
return true;
30653074
}
3066-
return true;
30673075
}
30683076

3069-
inline bool BitCastPtr(InterpState &S, CodePtr OpPC) {
3077+
inline bool BitCast(InterpState &S, CodePtr OpPC) {
30703078
const Pointer &FromPtr = S.Stk.pop<Pointer>();
30713079
Pointer &ToPtr = S.Stk.peek<Pointer>();
30723080

clang/lib/AST/ByteCode/Opcodes.td

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -839,13 +839,14 @@ def IsConstantContext: Opcode;
839839
def CheckAllocations : Opcode;
840840

841841
def BitCastTypeClass : TypeClass {
842-
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, IntAP, IntAPS, Bool, Float];
842+
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64,
843+
IntAP, IntAPS, Bool, Float, Ptr];
843844
}
844845

845-
def BitCast : Opcode {
846+
def BitCastPrim : Opcode {
846847
let Types = [BitCastTypeClass];
847848
let Args = [ArgBool, ArgUint32, ArgFltSemantics];
848849
let HasGroup = 1;
849850
}
850851

851-
def BitCastPtr : Opcode;
852+
def BitCast : Opcode;

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,3 +507,11 @@ typedef bool bool9 __attribute__((ext_vector_type(9)));
507507
// both-error@+2 {{constexpr variable 'bad_bool9_to_short' must be initialized by a constant expression}}
508508
// both-note@+1 {{bit_cast involving type 'bool __attribute__((ext_vector_type(9)))' (vector of 9 'bool' values) is not allowed in a constant expression; element size 1 * element count 9 is not a multiple of the byte size 8}}
509509
constexpr unsigned short bad_bool9_to_short = __builtin_bit_cast(unsigned short, bool9{1,1,0,1,0,1,0,1,0});
510+
511+
// both-warning@+2 {{returning reference to local temporary object}}
512+
// both-note@+1 {{temporary created here}}
513+
constexpr const intptr_t &returns_local() { return 0L; }
514+
515+
// both-error@+2 {{constexpr variable 'test_nullptr_bad' must be initialized by a constant expression}}
516+
// both-note@+1 {{read of temporary whose lifetime has ended}}
517+
constexpr nullptr_t test_nullptr_bad = __builtin_bit_cast(nullptr_t, returns_local());

0 commit comments

Comments
 (0)