[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