[clang] [clang][bytecode] Remove a bitcast nullptr_t special case (PR #120188)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 16 22:30:00 PST 2024


https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/120188

We still need to check the input pointer, so let this go through BitCastPrim.

>From 98b30005491d5082e035bdf966e12ae7f2f205f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 17 Dec 2024 06:21:58 +0100
Subject: [PATCH] [clang][bytecode] Remove a bitcast nullptr_t special case

We still need to check the input pointer, so let this go through
BitCastPrim.
---
 clang/lib/AST/ByteCode/Compiler.cpp          | 16 ++----
 clang/lib/AST/ByteCode/Interp.h              | 56 +++++++++++---------
 clang/lib/AST/ByteCode/Opcodes.td            |  7 +--
 clang/test/AST/ByteCode/builtin-bit-cast.cpp |  8 +++
 4 files changed, 48 insertions(+), 39 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 7f6295e126dcfe..59c77f0ce78d2b 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -6483,14 +6483,6 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
   QualType ToType = E->getType();
   std::optional<PrimType> ToT = classify(ToType);
 
-  // Bitcasting TO nullptr_t is always fine.
-  if (ToType->isNullPtrType()) {
-    if (!this->discard(SubExpr))
-      return false;
-
-    return this->emitNullPtr(0, nullptr, E);
-  }
-
   assert(!ToType->isReferenceType());
 
   // Prepare storage for the result in case we discard.
@@ -6523,8 +6515,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
     return false;
   }
 
-  if (!ToT || ToT == PT_Ptr) {
-    if (!this->emitBitCastPtr(E))
+  if (!ToT) {
+    if (!this->emitBitCast(E))
       return false;
     return DiscardResult ? this->emitPopPtr(E) : true;
   }
@@ -6540,8 +6532,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
                         ToType->isSpecificBuiltinType(BuiltinType::Char_U));
   uint32_t ResultBitWidth = std::max(Ctx.getBitWidth(ToType), 8u);
 
-  if (!this->emitBitCast(*ToT, ToTypeIsUChar || ToType->isStdByteType(),
-                         ResultBitWidth, TargetSemantics, E))
+  if (!this->emitBitCastPrim(*ToT, ToTypeIsUChar || ToType->isStdByteType(),
+                             ResultBitWidth, TargetSemantics, E))
     return false;
 
   if (DiscardResult)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 2a6ea69475f787..8461d1e98f9777 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -3030,43 +3030,51 @@ bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
 bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
-inline bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
-                    uint32_t ResultBitWidth, const llvm::fltSemantics *Sem) {
+inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
+                        uint32_t ResultBitWidth,
+                        const llvm::fltSemantics *Sem) {
   const Pointer &FromPtr = S.Stk.pop<Pointer>();
 
   if (!CheckLoad(S, OpPC, FromPtr))
     return false;
 
-  size_t BuffSize = ResultBitWidth / 8;
-  llvm::SmallVector<std::byte> Buff(BuffSize);
-  bool HasIndeterminateBits = false;
+  if constexpr (std::is_same_v<T, Pointer>) {
+    // The only pointer type we can validly bitcast to is nullptr_t.
+    S.Stk.push<Pointer>();
+    return true;
+  } else {
 
-  Bits FullBitWidth(ResultBitWidth);
-  Bits BitWidth = FullBitWidth;
+    size_t BuffSize = ResultBitWidth / 8;
+    llvm::SmallVector<std::byte> Buff(BuffSize);
+    bool HasIndeterminateBits = false;
 
-  if constexpr (std::is_same_v<T, Floating>) {
-    assert(Sem);
-    BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
-  }
+    Bits FullBitWidth(ResultBitWidth);
+    Bits BitWidth = FullBitWidth;
 
-  if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
-                 HasIndeterminateBits))
-    return false;
+    if constexpr (std::is_same_v<T, Floating>) {
+      assert(Sem);
+      BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
+    }
 
-  if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
-    return false;
+    if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
+                   HasIndeterminateBits))
+      return false;
 
-  if constexpr (std::is_same_v<T, Floating>) {
-    assert(Sem);
-    S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
-  } else {
-    assert(!Sem);
-    S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
+    if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
+      return false;
+
+    if constexpr (std::is_same_v<T, Floating>) {
+      assert(Sem);
+      S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
+    } else {
+      assert(!Sem);
+      S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
+    }
+    return true;
   }
-  return true;
 }
 
-inline bool BitCastPtr(InterpState &S, CodePtr OpPC) {
+inline bool BitCast(InterpState &S, CodePtr OpPC) {
   const Pointer &FromPtr = S.Stk.pop<Pointer>();
   Pointer &ToPtr = S.Stk.peek<Pointer>();
 
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 0638f8249805f8..123c21fa43eceb 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -839,13 +839,14 @@ def IsConstantContext: Opcode;
 def CheckAllocations : Opcode;
 
 def BitCastTypeClass : TypeClass {
-  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, IntAP, IntAPS, Bool, Float];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64,
+               IntAP, IntAPS, Bool, Float, Ptr];
 }
 
-def BitCast : Opcode {
+def BitCastPrim : Opcode {
   let Types = [BitCastTypeClass];
   let Args = [ArgBool, ArgUint32, ArgFltSemantics];
   let HasGroup = 1;
 }
 
-def BitCastPtr : Opcode;
+def BitCast : Opcode;
diff --git a/clang/test/AST/ByteCode/builtin-bit-cast.cpp b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
index 8a5bef635b8fde..1428163d5d4d86 100644
--- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp
+++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
@@ -507,3 +507,11 @@ typedef bool bool9 __attribute__((ext_vector_type(9)));
 // both-error at +2 {{constexpr variable 'bad_bool9_to_short' must be initialized by a constant expression}}
 // both-note at +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}}
 constexpr unsigned short bad_bool9_to_short = __builtin_bit_cast(unsigned short, bool9{1,1,0,1,0,1,0,1,0});
+
+// both-warning at +2 {{returning reference to local temporary object}}
+// both-note at +1 {{temporary created here}}
+constexpr const long &returns_local() { return 0L; }
+
+// both-error at +2 {{constexpr variable 'test_nullptr_bad' must be initialized by a constant expression}}
+// both-note at +1 {{read of temporary whose lifetime has ended}}
+constexpr nullptr_t test_nullptr_bad = __builtin_bit_cast(nullptr_t, returns_local());



More information about the cfe-commits mailing list