Skip to content

Commit 7cfa0e0

Browse files
authored
Fix translation of nullptr creation and comparison (#81)
This PR translates default pointers using `GetDefaultAsString`, resulting in `Ptr::<T>::null()` being generated instead of `Default::default()`. This is useful for contexts where `Default::default()` cannot be correctly deduced as a `Ptr`. Pointer comparisson is also fixed to allow C NULL comparissons such as `p != NULL` or `p != 0`.
1 parent 5cc91f7 commit 7cfa0e0

38 files changed

Lines changed: 336 additions & 130 deletions

cpp2rust/converter/converter.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,13 +1871,7 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
18711871
ConvertEqualsNullPtr(sub_expr);
18721872
break;
18731873
case clang::CastKind::CK_NullToPointer:
1874-
if (type->isFunctionPointerType()) {
1875-
StrCat("None");
1876-
} else {
1877-
StrCat(type->getPointeeType().isConstQualified()
1878-
? "std::ptr::null()"
1879-
: "std::ptr::null_mut()");
1880-
}
1874+
StrCat(GetDefaultAsString(type));
18811875
computed_expr_type_ = ComputedExprType::FreshPointer;
18821876
break;
18831877
default:

cpp2rust/converter/converter_lib.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,21 @@ bool IsBuiltinConstantP(const clang::Expr *expr) {
105105
}
106106

107107
bool IsComparisonWithNullOp(const clang::BinaryOperator *expr) {
108-
const auto *rhs = expr->getRHS()->IgnoreCasts();
109-
switch (rhs->getStmtClass()) {
110-
case clang::Stmt::CXXNullPtrLiteralExprClass:
111-
return expr->isComparisonOp();
112-
default:
108+
if (!expr->isComparisonOp()) {
113109
return false;
114110
}
111+
auto rhs = expr->getRHS()->IgnoreParenCasts();
112+
// C++ nullptr/NULL
113+
if (clang::isa<clang::CXXNullPtrLiteralExpr>(rhs) ||
114+
clang::isa<clang::GNUNullExpr>(rhs)) {
115+
return true;
116+
}
117+
// C NULL
118+
if (auto lit = clang::dyn_cast<clang::IntegerLiteral>(rhs)) {
119+
return lit->getValue() == 0 &&
120+
expr->getLHS()->IgnoreParenImpCasts()->getType()->isPointerType();
121+
}
122+
return false;
115123
}
116124

117125
bool IsInMainFile(const clang::Decl *decl) {

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,11 +1048,8 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
10481048
}
10491049

10501050
if (expr->getCastKind() == clang::CastKind::CK_NullToPointer) {
1051-
if (expr->getType()->isFunctionPointerType()) {
1052-
StrCat("FnPtr::null()");
1053-
} else {
1054-
StrCat("Default::default()");
1055-
}
1051+
PushConversionKind push(*this, ConversionKind::Unboxed);
1052+
StrCat(GetDefaultAsString(expr->getType()));
10561053
computed_expr_type_ = ComputedExprType::FreshPointer;
10571054
return false;
10581055
}
@@ -1142,7 +1139,7 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) {
11421139
return false;
11431140
}
11441141
if (expr->getCastKind() == clang::CK_NullToPointer) {
1145-
StrCat("Default::default()");
1142+
StrCat(GetDefaultAsString(expr->getType()));
11461143
computed_expr_type_ = ComputedExprType::FreshPointer;
11471144
return false;
11481145
}
@@ -1163,7 +1160,7 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) {
11631160
Convert(expr->getSubExpr());
11641161
PushConversionKind push(*this, ConversionKind::Unboxed);
11651162
StrCat(std::format(".cast::<{}>().expect(\"ub:wrong type\")",
1166-
ToString(expr->getType()->getPointeeType())));
1163+
ConvertPointeeType(expr->getType())));
11671164
return false;
11681165
} else if (expr->getSubExpr()->getType()->isPointerType() &&
11691166
!expr->getSubExpr()->isNullPointerConstant(
@@ -1612,7 +1609,10 @@ bool ConverterRefCount::VisitVAArgExpr(clang::VAArgExpr *expr) {
16121609
}
16131610
StrCat(ConvertLValue(va_list_expr));
16141611
StrCat(".arg::<");
1615-
StrCat(GetUnsafeTypeAsString(expr->getType()));
1612+
{
1613+
PushConversionKind push(*this, ConversionKind::Unboxed);
1614+
StrCat(ToString(expr->getType()));
1615+
}
16161616
StrCat(">()");
16171617
return false;
16181618
}
@@ -2241,8 +2241,9 @@ std::string ConverterRefCount::ConvertMappedMethodCall(
22412241

22422242
std::string ConverterRefCount::ConvertPointeeType(clang::QualType ptr_type) {
22432243
assert(!ptr_type.isNull() && ptr_type->isPointerType());
2244-
if (ptr_type->getPointeeType()->isIntegerType()) {
2245-
return ToString(ptr_type->getPointeeType());
2244+
auto pointee = ptr_type->getPointeeType();
2245+
if (!pointee->isRecordType()) {
2246+
return ToString(pointee);
22462247
}
22472248

22482249
// Pointee of a pointer to incomplete type is an incomplete type that does

tests/benchmarks/out/refcount/bfs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ fn main_0() -> i32 {
206206
'loop_: while (((*i.borrow()) as u64) < (*V.borrow())) {
207207
(*(*graph.borrow()).adj.borrow())
208208
.offset((*i.borrow()) as isize)
209-
.write(Default::default());
209+
.write(Ptr::<GraphNode>::null());
210210
(*i.borrow_mut()).prefix_inc();
211211
}
212212
let i: Value<u32> = Rc::new(RefCell::new(0_u32));

tests/benchmarks/out/refcount/bst.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn find_0(node: Ptr<node_t>, value: i32) -> Ptr<node_t> {
5353
} {
5454
return (*node.borrow()).clone();
5555
}
56-
return Default::default();
56+
return Ptr::<node_t>::null();
5757
}
5858
pub fn insert_1(node: Ptr<node_t>, new_node: Ptr<node_t>) -> Ptr<node_t> {
5959
let node: Value<Ptr<node_t>> = Rc::new(RefCell::new(node));
@@ -91,17 +91,17 @@ pub fn main() {
9191
fn main_0() -> i32 {
9292
let N: Value<i32> = Rc::new(RefCell::new(25000));
9393
let tree: Value<Ptr<node_t>> = Rc::new(RefCell::new(Ptr::alloc(node_t {
94-
left: Rc::new(RefCell::new(Default::default())),
95-
right: Rc::new(RefCell::new(Default::default())),
94+
left: Rc::new(RefCell::new(Ptr::<node_t>::null())),
95+
right: Rc::new(RefCell::new(Ptr::<node_t>::null())),
9696
value: Rc::new(RefCell::new(0)),
9797
})));
9898
let i: Value<i32> = Rc::new(RefCell::new(0));
9999
'loop_: while ((*i.borrow()) < (*N.borrow())) {
100100
({
101101
let _node: Ptr<node_t> = (*tree.borrow()).clone();
102102
let _new_node: Ptr<node_t> = Ptr::alloc(node_t {
103-
left: Rc::new(RefCell::new(Default::default())),
104-
right: Rc::new(RefCell::new(Default::default())),
103+
left: Rc::new(RefCell::new(Ptr::<node_t>::null())),
104+
right: Rc::new(RefCell::new(Ptr::<node_t>::null())),
105105
value: Rc::new(RefCell::new((*i.borrow()))),
106106
});
107107
insert_1(_node, _new_node)

tests/ub/out/refcount/ub2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::io::{Read, Seek, Write};
77
use std::os::fd::AsFd;
88
use std::rc::{Rc, Weak};
99
pub fn null_0() -> Ptr<i32> {
10-
let p: Value<Ptr<i32>> = Rc::new(RefCell::new(Default::default()));
10+
let p: Value<Ptr<i32>> = Rc::new(RefCell::new(Ptr::<i32>::null()));
1111
return (*p.borrow()).clone();
1212
}
1313
pub fn main() {

tests/ub/out/refcount/ub4.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub fn main() {
2020
std::process::exit(main_0());
2121
}
2222
fn main_0() -> i32 {
23-
let out: Value<Ptr<i32>> = Rc::new(RefCell::new(Default::default()));
23+
let out: Value<Ptr<i32>> = Rc::new(RefCell::new(Ptr::<i32>::null()));
2424
let x1: Value<i32> = Rc::new(RefCell::new(1));
2525
if ((*x1.borrow()) != 0) {
2626
let x2: Value<i32> = Rc::new(RefCell::new(-1_i32));

tests/ub/out/refcount/ub5.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::os::fd::AsFd;
88
use std::rc::{Rc, Weak};
99
pub fn null_0(p: Ptr<Ptr<i32>>) {
1010
let p: Value<Ptr<Ptr<i32>>> = Rc::new(RefCell::new(p));
11-
(*p.borrow()).write(Default::default());
11+
(*p.borrow()).write(Ptr::<i32>::null());
1212
}
1313
pub fn main() {
1414
std::process::exit(main_0());

tests/unit/null_compare.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
int main() {
4+
int a = 0;
5+
int *p = &a;
6+
assert(p != NULL);
7+
assert(p != 0);
8+
9+
p = NULL;
10+
assert(p == NULL);
11+
assert(p == 0);
12+
return 0;
13+
}

tests/unit/out/refcount/10_struct.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub fn main() {
6666
fn main_0() -> i32 {
6767
let g: Value<Graph> = Rc::new(RefCell::new(Graph {
6868
V: Rc::new(RefCell::new(5_u32)),
69-
adj: Rc::new(RefCell::new(Default::default())),
69+
adj: Rc::new(RefCell::new(Ptr::<Ptr<GraphNode>>::null())),
7070
}));
7171
return 0;
7272
}

0 commit comments

Comments
 (0)