[clang] 5fbb6d9 - [clang][bytecode] Allow up/down casts of nullptr (#127615)

via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 18 05:43:39 PST 2025


Author: Timm Baeder
Date: 2025-02-18T14:43:35+01:00
New Revision: 5fbb6d919d528d54538df3330e76f220ff52ab30

URL: https://github.com/llvm/llvm-project/commit/5fbb6d919d528d54538df3330e76f220ff52ab30
DIFF: https://github.com/llvm/llvm-project/commit/5fbb6d919d528d54538df3330e76f220ff52ab30.diff

LOG: [clang][bytecode] Allow up/down casts of nullptr (#127615)

If the target type is a pointer type.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Compiler.cpp
    clang/lib/AST/ByteCode/Interp.cpp
    clang/lib/AST/ByteCode/Interp.h
    clang/lib/AST/ByteCode/Opcodes.td
    clang/test/AST/ByteCode/records.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index b3a81f8ff1516..503c58a67adeb 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -272,7 +272,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
         CurType = B->getType();
       } else {
         unsigned DerivedOffset = collectBaseOffset(B->getType(), CurType);
-        if (!this->emitGetPtrBasePop(DerivedOffset, CE))
+        if (!this->emitGetPtrBasePop(
+                DerivedOffset, /*NullOK=*/CE->getType()->isPointerType(), CE))
           return false;
         CurType = B->getType();
       }
@@ -288,7 +289,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
     unsigned DerivedOffset =
         collectBaseOffset(SubExpr->getType(), CE->getType());
 
-    return this->emitGetPtrDerivedPop(DerivedOffset, CE);
+    return this->emitGetPtrDerivedPop(
+        DerivedOffset, /*NullOK=*/CE->getType()->isPointerType(), CE);
   }
 
   case CK_FloatingCast: {

diff  --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 0310870f7372e..c07690a3d941c 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1433,7 +1433,7 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
     unsigned Offset = S.getContext().collectBaseOffset(
         InitialPointeeType->getAsRecordDecl(),
         OverriderPointeeType->getAsRecordDecl());
-    return GetPtrBasePop(S, OpPC, Offset);
+    return GetPtrBasePop(S, OpPC, Offset, /*IsNullOK=*/true);
   }
 
   return true;

diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 10cf21e28437c..ca74046038072 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1568,10 +1568,20 @@ inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
   return true;
 }
 
-inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
+inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
+                             bool NullOK) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
-  if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
+  if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Derived))
     return false;
+
+  if (!Ptr.isBlockPointer()) {
+    // FIXME: We don't have the necessary information in integral pointers.
+    // The Descriptor only has a record, but that does of course not include
+    // the potential derived classes of said record.
+    S.Stk.push<Pointer>(Ptr);
+    return true;
+  }
+
   if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
     return false;
   if (!CheckDowncast(S, OpPC, Ptr, Off))
@@ -1600,10 +1610,11 @@ inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
   return true;
 }
 
-inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
+inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off,
+                          bool NullOK) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
 
-  if (!CheckNull(S, OpPC, Ptr, CSK_Base))
+  if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Base))
     return false;
 
   if (!Ptr.isBlockPointer()) {

diff  --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 088a3e40fe2a7..41e4bae65c195 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -312,7 +312,7 @@ def GetPtrThisField : OffsetOpcode;
 // [Pointer] -> [Pointer]
 def GetPtrBase : OffsetOpcode;
 // [Pointer] -> [Pointer]
-def GetPtrBasePop : OffsetOpcode;
+def GetPtrBasePop : OffsetOpcode { let Args = [ArgUint32, ArgBool]; }
 def GetMemberPtrBasePop : Opcode {
   // Offset of field, which is a base.
   let Args = [ArgSint32];
@@ -322,9 +322,7 @@ def GetMemberPtrBasePop : Opcode {
 def FinishInitPop : Opcode;
 def FinishInit    : Opcode;
 
-def GetPtrDerivedPop : Opcode {
-  let Args = [ArgUint32];
-}
+def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool]; }
 
 // [Pointer] -> [Pointer]
 def GetPtrVirtBasePop : Opcode {

diff  --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp
index 9470e7d8e3dcb..3cc3210841e0f 100644
--- a/clang/test/AST/ByteCode/records.cpp
+++ b/clang/test/AST/ByteCode/records.cpp
@@ -1656,12 +1656,28 @@ namespace ExprWithCleanups {
   static_assert(F == 1i, "");
 }
 
-namespace NullptrUpcast {
+namespace NullptrCast {
   struct A {};
   struct B : A { int n; };
+  constexpr A *na = nullptr;
   constexpr B *nb = nullptr;
   constexpr A &ra = *nb; // both-error {{constant expression}} \
                          // both-note {{cannot access base class of null pointer}}
+  constexpr B &rb = (B&)*na; // both-error {{constant expression}} \
+                             // both-note {{cannot access derived class of null pointer}}
+  constexpr bool test() {
+    auto a = (A*)(B*)nullptr;
+
+    return a == nullptr;
+  }
+  static_assert(test(), "");
+
+  constexpr bool test2() {
+    auto a = (B*)(A*)nullptr;
+
+    return a == nullptr;
+  }
+  static_assert(test2(), "");
 }
 
 namespace NonConst {


        


More information about the cfe-commits mailing list