[clang] 29c55d0 - [clang][bytecode] Improve error detection in BitCastPrim op (#158575)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 16 01:02:23 PDT 2025
Author: Timm Baeder
Date: 2025-09-16T10:02:18+02:00
New Revision: 29c55d0f7bb993668243efad0dbbc3fc1a9a5d2a
URL: https://github.com/llvm/llvm-project/commit/29c55d0f7bb993668243efad0dbbc3fc1a9a5d2a
DIFF: https://github.com/llvm/llvm-project/commit/29c55d0f7bb993668243efad0dbbc3fc1a9a5d2a.diff
LOG: [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
Added:
Modified:
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Interp.h
clang/lib/AST/ByteCode/Opcodes.td
clang/test/AST/ByteCode/builtin-bit-cast.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index c9ce113c4701f..1340a84a7d44d 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7398,7 +7398,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
uint32_t ResultBitWidth = std::max(Ctx.getBitWidth(ToType), 8u);
if (!this->emitBitCastPrim(*ToT, ToTypeIsUChar || ToType->isStdByteType(),
- ResultBitWidth, TargetSemantics, E))
+ ResultBitWidth, TargetSemantics,
+ ToType.getTypePtr(), E))
return false;
if (DiscardResult)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index d8362ee3176a0..b15281b65cd61 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -3569,17 +3569,28 @@ bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
- uint32_t ResultBitWidth,
- const llvm::fltSemantics *Sem) {
+ uint32_t ResultBitWidth, const llvm::fltSemantics *Sem,
+ const Type *TargetType) {
const Pointer &FromPtr = S.Stk.pop<Pointer>();
if (!CheckLoad(S, OpPC, FromPtr))
return false;
if constexpr (std::is_same_v<T, Pointer>) {
+ if (!TargetType->isNullPtrType()) {
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_bit_cast_invalid_type)
+ << /*IsToType=*/true << /*IsReference=*/false << 1 /*Pointer*/;
+ return false;
+ }
// The only pointer type we can validly bitcast to is nullptr_t.
S.Stk.push<Pointer>();
return true;
+ } else if constexpr (std::is_same_v<T, MemberPointer>) {
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_bit_cast_invalid_type)
+ << /*IsToType=*/true << /*IsReference=*/false << 2 /*MemberPointer*/;
+ return false;
} else {
size_t BuffSize = ResultBitWidth / 8;
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 95a44333e8e04..7af2df5318106 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -872,12 +872,12 @@ def CheckNull : Opcode;
def BitCastTypeClass : TypeClass {
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64,
- IntAP, IntAPS, Bool, Float, Ptr];
+ IntAP, IntAPS, Bool, Float, Ptr, MemberPtr];
}
def BitCastPrim : Opcode {
let Types = [BitCastTypeClass];
- let Args = [ArgBool, ArgUint32, ArgFltSemantics];
+ let Args = [ArgBool, ArgUint32, ArgFltSemantics, ArgTypePtr];
let HasGroup = 1;
}
diff --git a/clang/test/AST/ByteCode/builtin-bit-cast.cpp b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
index 32c1f41e0e059..a12f305caf877 100644
--- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp
+++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
@@ -530,7 +530,6 @@ constexpr const intptr_t &returns_local() { return 0L; }
// both-note at +1 {{read of temporary whose lifetime has ended}}
constexpr nullptr_t test_nullptr_bad = __builtin_bit_cast(nullptr_t, returns_local());
-
#ifdef __SIZEOF_INT128__
namespace VectorCast {
typedef unsigned X __attribute__ ((vector_size (64)));
@@ -572,3 +571,19 @@ namespace VectorCast {
#endif
}
#endif
+
+namespace ToPrimPtrs {
+ struct S { int foo () { return 0; } };
+ auto ptr = __builtin_bit_cast(int *, ((__INTPTR_TYPE__) 0));
+ auto nptr = __builtin_bit_cast(nullptr_t, ((__INTPTR_TYPE__)0));
+
+ constexpr auto cptr = __builtin_bit_cast(int *, ((__INTPTR_TYPE__) 0)); // both-error {{must be initialized by a constant expression}} \
+ // both-note {{bit_cast to a pointer type is not allowed in a constant expression}}
+ constexpr auto cnptr = __builtin_bit_cast(nullptr_t, ((__INTPTR_TYPE__)0));
+
+#if !defined(_WIN32)
+ auto memptr = __builtin_bit_cast(int S::*, ((__INTPTR_TYPE__) 0));
+ constexpr auto cmemptr = __builtin_bit_cast(int S::*, ((__INTPTR_TYPE__) 0)); // both-error {{must be initialized by a constant expression}} \
+ // both-note {{bit_cast to a member pointer type is not allowed in a constant expression}}
+#endif
+}
More information about the cfe-commits
mailing list