Skip to content

Commit 1814bb5

Browse files
authored
Translate reference to array (#357)
Reference to array is translated as `Ptr<Box<[T]>>` in refcount and `*const/mut [T; N]` in unsafe. I added a new ConversionKind called Pointee to translate reference to array in refcount. The semantics are: * `FullRefCount`: `Value<Pointee>` * `Pointee`: the object itself * `Unboxed`: same as `Pointee`, except arrays which are `[T; N]` intead `Box<[T]>` I also added `Ptr::from_string_literal_array` which is similar to `Ptr::from_string_literal`, the only difference is that that the new function returns `Ptr<Box<[u8]>>` instead of `Ptr<u8>`.
1 parent 7df70fb commit 1814bb5

7 files changed

Lines changed: 451 additions & 23 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,8 +2186,11 @@ std::string Converter::GetEscapedStringLiteral(clang::Expr *expr,
21862186
}
21872187

21882188
bool Converter::VisitStringLiteral(clang::StringLiteral *expr) {
2189-
if (!curr_init_type_.empty() && curr_init_type_.back()->isArrayType()) {
2190-
if (auto *arr_ty = ctx_.getAsConstantArrayType(curr_init_type_.back())) {
2189+
auto init_type = curr_init_type_.empty()
2190+
? clang::QualType()
2191+
: curr_init_type_.back().getNonReferenceType();
2192+
if (!init_type.isNull() && init_type->isArrayType()) {
2193+
if (auto *arr_ty = ctx_.getAsConstantArrayType(init_type)) {
21912194
uint64_t arr_size = arr_ty->getSize().getZExtValue();
21922195
if (expr->getString().empty()) {
21932196
StrCat(std::format("[0 as libc::c_char; {}]", arr_size));

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ bool ConverterRefCount::NeedsMut(const clang::VarDecl *decl,
129129
std::string ConverterRefCount::BoxType(std::string &&str) const {
130130
switch (getConversionKind()) {
131131
case ConversionKind::Unboxed:
132+
case ConversionKind::Pointee:
132133
case ConversionKind::Ptr:
133134
return std::move(str);
134135
case ConversionKind::FullRefCount:
@@ -140,6 +141,7 @@ std::string ConverterRefCount::BoxType(std::string &&str) const {
140141
std::string ConverterRefCount::BoxValue(std::string &&str) const {
141142
switch (getConversionKind()) {
142143
case ConversionKind::Unboxed:
144+
case ConversionKind::Pointee:
143145
case ConversionKind::Ptr:
144146
return std::move(str);
145147
case ConversionKind::FullRefCount:
@@ -178,7 +180,7 @@ bool ConverterRefCount::VisitIncompleteArrayType(
178180
}
179181

180182
bool ConverterRefCount::VisitReferenceType(clang::ReferenceType *type) {
181-
PushConversionKind push(*this, ConversionKind::Unboxed);
183+
PushConversionKind push(*this, ConversionKind::Pointee);
182184
StrCat("Ptr<");
183185
Convert(type->getPointeeType());
184186
StrCat(token::kGt);
@@ -297,6 +299,7 @@ bool ConverterRefCount::VisitConstantArrayType(clang::ConstantArrayType *type) {
297299
case ConversionKind::Ptr:
298300
Convert(type->getElementType());
299301
break;
302+
case ConversionKind::Pointee:
300303
case ConversionKind::FullRefCount:
301304
StrCat("Box<[");
302305
Convert(type->getElementType());
@@ -396,7 +399,9 @@ bool ConverterRefCount::VisitArraySubscriptExpr(
396399
clang::ArraySubscriptExpr *expr) {
397400
auto *base = expr->getBase();
398401
if (base->IgnoreCasts()->getType()->isPointerType() ||
399-
IsUnionArrayMember(base)) {
402+
IsUnionArrayMember(base) ||
403+
(IsReferenceType(base) &&
404+
base->IgnoreCasts()->getType()->isArrayType())) {
400405
ConvertPointerSubscript(expr);
401406
} else {
402407
if (!base->IgnoreCasts()->getType()->isArrayType()) {
@@ -846,7 +851,8 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
846851
// std::vector<T>& gets converted to Ptr<vec<T>>
847852
// So we need to make a pointer to the vector itself
848853
if (isObject()) {
849-
if (IsBoxedType(ref->getPointeeType())) {
854+
if (IsBoxedType(ref->getPointeeType()) ||
855+
ref->getPointeeType()->isArrayType()) {
850856
StrCat(str, ".to_strong().as_pointer()");
851857
computed_expr_type_ = ComputedExprType::FreshPointer;
852858
return false;
@@ -1227,7 +1233,9 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
12271233
// smart enough to pick the right specialization
12281234
PushConversionKind push(*this, ConversionKind::Unboxed);
12291235
PushParen paren(*this);
1230-
StrCat(ConvertPointer(sub_expr), keyword::kAs, ToString(expr->getType()));
1236+
StrCat(IsReferenceType(sub_expr) ? ConvertObject(sub_expr)
1237+
: ConvertPointer(sub_expr),
1238+
keyword::kAs, ToString(expr->getType()));
12311239
return false;
12321240
}
12331241
}
@@ -1590,6 +1598,7 @@ bool ConverterRefCount::VisitInitListExpr(clang::InitListExpr *expr) {
15901598
case ConversionKind::Ptr:
15911599
Converter::VisitInitListExpr(expr);
15921600
break;
1601+
case ConversionKind::Pointee:
15931602
case ConversionKind::FullRefCount:
15941603
StrCat("Box::new(");
15951604
Converter::VisitInitListExpr(expr);
@@ -2078,6 +2087,14 @@ std::string ConverterRefCount::ConvertVarInitValue(clang::QualType qual_type,
20782087
if (llvm::isa<clang::MaterializeTemporaryExpr>(expr->IgnoreImpCasts())) {
20792088
return EmitMaterializedTempBinding(qual_type, expr);
20802089
}
2090+
if (qual_type.getNonReferenceType()->isArrayType()) {
2091+
if (IsStringLiteralExpr(expr)) {
2092+
return std::format("Ptr::from_string_literal_array({})",
2093+
ToString(expr->IgnoreParens()->IgnoreImplicit()));
2094+
}
2095+
return std::format("({} as {})", ConvertFreshPointer(expr),
2096+
ToString(qual_type));
2097+
}
20812098
return ConvertFreshPointer(expr);
20822099
}
20832100
return ConvertFreshRValue(expr, qual_type);
@@ -2449,7 +2466,7 @@ void ConverterRefCount::ConvertDeref(clang::Expr *expr) {
24492466
}
24502467

24512468
if (isObject()) {
2452-
if (IsBoxedType(pointee_type)) {
2469+
if (IsBoxedType(pointee_type) || pointee_type->isArrayType()) {
24532470
StrCat(".to_strong().as_pointer()");
24542471
computed_expr_type_ = ComputedExprType::FreshPointer;
24552472
}

‎cpp2rust/converter/models/converter_refcount.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ class ConverterRefCount final : public Converter {
285285
/// The kind of conversion that should be performed.
286286
enum class ConversionKind : uint8_t {
287287
Unboxed,
288+
Pointee,
288289
Ptr,
289290
FullRefCount,
290291
};
@@ -293,6 +294,8 @@ class ConverterRefCount final : public Converter {
293294
switch (k) {
294295
case ConversionKind::Unboxed:
295296
return "Unboxed";
297+
case ConversionKind::Pointee:
298+
return "Pointee";
296299
case ConversionKind::Ptr:
297300
return "Ptr";
298301
case ConversionKind::FullRefCount:

‎libcc2rs/src/cstr.rs‎

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::fmt;
77
use std::rc::Rc;
88

99
use crate::CStringIterator;
10-
use crate::rc::{Ptr, PtrKind};
10+
use crate::rc::{AsPointer, Ptr, PtrKind};
1111

1212
impl fmt::Display for Ptr<u8> {
1313
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -27,12 +27,32 @@ impl fmt::Display for Ptr<u8> {
2727
}
2828
}
2929

30-
type StringLiteralMap = HashMap<&'static [u8], Rc<RefCell<Vec<u8>>>>;
30+
type StringLiteralMap = HashMap<&'static [u8], Rc<RefCell<Box<[u8]>>>>;
3131

3232
thread_local! {
3333
static STRING_LITERALS: RefCell<StringLiteralMap> = RefCell::new(HashMap::new());
3434
}
3535

36+
impl Ptr<Box<[u8]>> {
37+
#[inline]
38+
pub fn from_string_literal_array(s: &'static [u8]) -> Self {
39+
STRING_LITERALS.with(|literals| {
40+
let mut literals = literals.borrow_mut();
41+
let weak = Rc::downgrade(literals.entry(s).or_insert_with(|| {
42+
Rc::new(RefCell::new({
43+
let mut v = s.to_vec();
44+
v.push(0);
45+
v.into_boxed_slice()
46+
}))
47+
}));
48+
Ptr {
49+
offset: 0,
50+
kind: PtrKind::StackSingle(weak),
51+
}
52+
})
53+
}
54+
}
55+
3656
impl Ptr<u8> {
3757
#[allow(clippy::explicit_counter_loop)]
3858
pub fn memcpy(&self, src: &Self, len: usize) {
@@ -86,20 +106,9 @@ impl Ptr<u8> {
86106

87107
#[inline]
88108
pub fn from_string_literal(s: &'static [u8]) -> Self {
89-
STRING_LITERALS.with(|literals| {
90-
let mut literals = literals.borrow_mut();
91-
let weak = Rc::downgrade(literals.entry(s).or_insert_with(|| {
92-
Rc::new(RefCell::new({
93-
let mut v = s.to_vec();
94-
v.push(0);
95-
v
96-
}))
97-
}));
98-
Ptr {
99-
offset: 0,
100-
kind: PtrKind::Vec(weak),
101-
}
102-
})
109+
Ptr::<Box<[u8]>>::from_string_literal_array(s)
110+
.to_strong()
111+
.as_pointer()
103112
}
104113

105114
pub fn to_c_string_iterator(&self) -> CStringIterator {

‎tests/unit/array_reference.cpp‎

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include <cassert>
2+
3+
int len(const char (&s)[5]) {
4+
int n = 0;
5+
while (s[n] != '\0') {
6+
++n;
7+
}
8+
return n;
9+
}
10+
11+
int len5(const char *s) {
12+
int n = 0;
13+
while (s[n] != '\0') {
14+
++n;
15+
}
16+
return n;
17+
}
18+
19+
int sum(const int (&a)[3]) { return a[0] + a[1] + a[2]; }
20+
21+
void fill(int (&a)[3], int v) {
22+
for (int i = 0; i < 3; ++i) {
23+
a[i] = v;
24+
}
25+
}
26+
27+
int sum_twice(const int (&a)[3]) { return sum(a) + sum(a); }
28+
29+
void fill_and_sum(int (&a)[3], int v, int &out) {
30+
fill(a, v);
31+
out = sum_twice(a);
32+
}
33+
34+
const char (&pick(const char (&s)[5]))[5] { return s; }
35+
36+
struct Point {
37+
int x;
38+
int y;
39+
};
40+
41+
int sum_points(const Point (&p)[2]) {
42+
return p[0].x + p[0].y + p[1].x + p[1].y;
43+
}
44+
45+
void shift_points(Point (&p)[2], int d) {
46+
p[0].x += d;
47+
p[1].y += d;
48+
}
49+
50+
int total_len(const char *(&names)[2]) {
51+
return len5(names[0]) + len5(names[1]);
52+
}
53+
54+
int main() {
55+
assert(len("beta") == 4);
56+
char buf[5] = "abcd";
57+
assert(len(buf) == 4);
58+
int arr[3] = {1, 2, 3};
59+
assert(sum(arr) == 6);
60+
fill(arr, 7);
61+
assert(sum(arr) == 21);
62+
assert(sum_twice(arr) == 42);
63+
int out = 0;
64+
fill_and_sum(arr, 2, out);
65+
assert(out == 12);
66+
assert(arr[0] == 2);
67+
const char (&lit)[5] = "beta";
68+
assert(len(lit) == 4);
69+
assert(pick("beta")[0] == 'b');
70+
assert(len(pick(buf)) == 4);
71+
Point pts[2] = {{1, 2}, {3, 4}};
72+
assert(sum_points(pts) == 10);
73+
shift_points(pts, 10);
74+
assert(pts[0].x == 11);
75+
assert(pts[1].y == 14);
76+
assert(sum_points(pts) == 30);
77+
const char *names[2] = {"ab", "cde"};
78+
assert(total_len(names) == 5);
79+
return 0;
80+
}

0 commit comments

Comments
 (0)