[clang] [clang][bytecode] Allow up/down casts of nullptr (PR #127615)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 18 02:52:43 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
If the target type is a pointer type.
---
Full diff: https://github.com/llvm/llvm-project/pull/127615.diff
5 Files Affected:
- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+4-2)
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+1-1)
- (modified) clang/lib/AST/ByteCode/Interp.h (+15-4)
- (modified) clang/lib/AST/ByteCode/Opcodes.td (+2-4)
- (modified) clang/test/AST/ByteCode/records.cpp (+17-1)
``````````diff
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 59c236c9da8c8..c58e884c77d6b 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 c80be094856b0..f09081101f086 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1432,7 +1432,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 73cc107b7dbff..0f24c83d03029 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 {
``````````
</details>
https://github.com/llvm/llvm-project/pull/127615
More information about the cfe-commits
mailing list