Skip to content

Commit 29c55d0

Browse files
authored
[clang][bytecode] Improve error detection in BitCastPrim op (#158575)
Reject bitcasts to pointer types unless it's to `nullptr_t` and always reject bitcasts to member pointer types. Fixes #156174
1 parent 7ba7021 commit 29c55d0

File tree

4 files changed

+33
-6
lines changed

4 files changed

+33
-6
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7398,7 +7398,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
73987398
uint32_t ResultBitWidth = std::max(Ctx.getBitWidth(ToType), 8u);
73997399

74007400
if (!this->emitBitCastPrim(*ToT, ToTypeIsUChar || ToType->isStdByteType(),
7401-
ResultBitWidth, TargetSemantics, E))
7401+
ResultBitWidth, TargetSemantics,
7402+
ToType.getTypePtr(), E))
74027403
return false;
74037404

74047405
if (DiscardResult)

clang/lib/AST/ByteCode/Interp.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3569,17 +3569,28 @@ bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
35693569

35703570
template <PrimType Name, class T = typename PrimConv<Name>::T>
35713571
inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
3572-
uint32_t ResultBitWidth,
3573-
const llvm::fltSemantics *Sem) {
3572+
uint32_t ResultBitWidth, const llvm::fltSemantics *Sem,
3573+
const Type *TargetType) {
35743574
const Pointer &FromPtr = S.Stk.pop<Pointer>();
35753575

35763576
if (!CheckLoad(S, OpPC, FromPtr))
35773577
return false;
35783578

35793579
if constexpr (std::is_same_v<T, Pointer>) {
3580+
if (!TargetType->isNullPtrType()) {
3581+
S.FFDiag(S.Current->getSource(OpPC),
3582+
diag::note_constexpr_bit_cast_invalid_type)
3583+
<< /*IsToType=*/true << /*IsReference=*/false << 1 /*Pointer*/;
3584+
return false;
3585+
}
35803586
// The only pointer type we can validly bitcast to is nullptr_t.
35813587
S.Stk.push<Pointer>();
35823588
return true;
3589+
} else if constexpr (std::is_same_v<T, MemberPointer>) {
3590+
S.FFDiag(S.Current->getSource(OpPC),
3591+
diag::note_constexpr_bit_cast_invalid_type)
3592+
<< /*IsToType=*/true << /*IsReference=*/false << 2 /*MemberPointer*/;
3593+
return false;
35833594
} else {
35843595

35853596
size_t BuffSize = ResultBitWidth / 8;

clang/lib/AST/ByteCode/Opcodes.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -872,12 +872,12 @@ def CheckNull : Opcode;
872872

873873
def BitCastTypeClass : TypeClass {
874874
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64,
875-
IntAP, IntAPS, Bool, Float, Ptr];
875+
IntAP, IntAPS, Bool, Float, Ptr, MemberPtr];
876876
}
877877

878878
def BitCastPrim : Opcode {
879879
let Types = [BitCastTypeClass];
880-
let Args = [ArgBool, ArgUint32, ArgFltSemantics];
880+
let Args = [ArgBool, ArgUint32, ArgFltSemantics, ArgTypePtr];
881881
let HasGroup = 1;
882882
}
883883

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,6 @@ constexpr const intptr_t &returns_local() { return 0L; }
530530
// both-note@+1 {{read of temporary whose lifetime has ended}}
531531
constexpr nullptr_t test_nullptr_bad = __builtin_bit_cast(nullptr_t, returns_local());
532532

533-
534533
#ifdef __SIZEOF_INT128__
535534
namespace VectorCast {
536535
typedef unsigned X __attribute__ ((vector_size (64)));
@@ -572,3 +571,19 @@ namespace VectorCast {
572571
#endif
573572
}
574573
#endif
574+
575+
namespace ToPrimPtrs {
576+
struct S { int foo () { return 0; } };
577+
auto ptr = __builtin_bit_cast(int *, ((__INTPTR_TYPE__) 0));
578+
auto nptr = __builtin_bit_cast(nullptr_t, ((__INTPTR_TYPE__)0));
579+
580+
constexpr auto cptr = __builtin_bit_cast(int *, ((__INTPTR_TYPE__) 0)); // both-error {{must be initialized by a constant expression}} \
581+
// both-note {{bit_cast to a pointer type is not allowed in a constant expression}}
582+
constexpr auto cnptr = __builtin_bit_cast(nullptr_t, ((__INTPTR_TYPE__)0));
583+
584+
#if !defined(_WIN32)
585+
auto memptr = __builtin_bit_cast(int S::*, ((__INTPTR_TYPE__) 0));
586+
constexpr auto cmemptr = __builtin_bit_cast(int S::*, ((__INTPTR_TYPE__) 0)); // both-error {{must be initialized by a constant expression}} \
587+
// both-note {{bit_cast to a member pointer type is not allowed in a constant expression}}
588+
#endif
589+
}

0 commit comments

Comments
 (0)