Skip to content

Commit b6b8479

Browse files
authored
Access unions through Ptr<Self> (#474)
Fixes #311
1 parent a88cbec commit b6b8479

25 files changed

Lines changed: 418 additions & 279 deletions

‎cpp2rust/converter/converter.cpp‎

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3346,46 +3346,6 @@ void Converter::SetUFCSReceiver(clang::Expr *base, bool is_arrow,
33463346
ufcs_receiver_ = std::move(buf).str();
33473347
}
33483348

3349-
// Returns the inner member and the replacement string.
3350-
static std::pair<clang::MemberExpr *, std::string>
3351-
replaceNonUniformLibcField(clang::MemberExpr *expr) {
3352-
// Example: ::struct stat::st_mtim::tv_sec -> ::libc::stat::st_mtime
3353-
struct Mapping {
3354-
const char *record;
3355-
const char *inner_field;
3356-
const char *leaf_field;
3357-
const char *replacement;
3358-
};
3359-
static constexpr Mapping kFields[] = {
3360-
{"stat", "st_mtim", "tv_sec", "st_mtime"}, // Linux
3361-
{"stat", "st_mtimespec", "tv_sec", "st_mtime"}, // macOS
3362-
{"in6_addr", "__in6_u", "__u6_addr8", "s6_addr"},
3363-
};
3364-
3365-
auto getNamedIdentifierOrNull = [](auto *decl) {
3366-
return decl && decl->getDeclName().isIdentifier() ? decl : nullptr;
3367-
};
3368-
3369-
if (auto leaf = getNamedIdentifierOrNull(expr->getMemberDecl())) {
3370-
if (auto inner = clang::dyn_cast<clang::MemberExpr>(
3371-
expr->getBase()->IgnoreParenImpCasts())) {
3372-
if (auto field = getNamedIdentifierOrNull(
3373-
clang::dyn_cast<clang::FieldDecl>(inner->getMemberDecl()))) {
3374-
if (getNamedIdentifierOrNull(field->getParent())) {
3375-
for (const auto &m : kFields) {
3376-
if (field->getParent()->getName() == m.record &&
3377-
field->getName() == m.inner_field &&
3378-
leaf->getName() == m.leaf_field) {
3379-
return {inner, m.replacement};
3380-
}
3381-
}
3382-
}
3383-
}
3384-
}
3385-
}
3386-
return {nullptr, ""};
3387-
}
3388-
33893349
void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
33903350
if (auto mapped = GetMappedAsString(expr); !mapped.empty()) {
33913351
if (RuleRegistry::ReturnsPointer(ctx_, expr)) {
@@ -3397,7 +3357,7 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
33973357
}
33983358

33993359
auto *member = expr->getMemberDecl();
3400-
auto [inner, name_override] = replaceNonUniformLibcField(expr);
3360+
auto [inner, record, name_override] = ReplaceNonUniformLibcField(expr);
34013361
if (inner) {
34023362
expr = inner;
34033363
}

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,46 @@ bool IsUnionArrayMember(const clang::Expr *base) {
211211
return false;
212212
}
213213

214+
// TODO: this will be gone when the AST matcher lands
215+
std::tuple<clang::MemberExpr *, clang::RecordDecl *, std::string>
216+
ReplaceNonUniformLibcField(clang::MemberExpr *expr) {
217+
// Example: ::struct stat::st_mtim::tv_sec -> ::libc::stat::st_mtime
218+
struct Mapping {
219+
const char *record;
220+
const char *inner_field;
221+
const char *leaf_field;
222+
const char *replacement;
223+
};
224+
static constexpr Mapping kFields[] = {
225+
{"stat", "st_mtim", "tv_sec", "st_mtime"}, // Linux
226+
{"stat", "st_mtimespec", "tv_sec", "st_mtime"}, // macOS
227+
{"in6_addr", "__in6_u", "__u6_addr8", "s6_addr"},
228+
};
229+
230+
auto getNamedIdentifierOrNull = [](auto *decl) {
231+
return decl && decl->getDeclName().isIdentifier() ? decl : nullptr;
232+
};
233+
234+
if (auto leaf = getNamedIdentifierOrNull(expr->getMemberDecl())) {
235+
if (auto inner = clang::dyn_cast<clang::MemberExpr>(
236+
expr->getBase()->IgnoreParenImpCasts())) {
237+
if (auto field = getNamedIdentifierOrNull(
238+
clang::dyn_cast<clang::FieldDecl>(inner->getMemberDecl()))) {
239+
if (getNamedIdentifierOrNull(field->getParent())) {
240+
for (const auto &m : kFields) {
241+
if (field->getParent()->getName() == m.record &&
242+
field->getName() == m.inner_field &&
243+
leaf->getName() == m.leaf_field) {
244+
return {inner, field->getParent(), m.replacement};
245+
}
246+
}
247+
}
248+
}
249+
}
250+
}
251+
return {nullptr, nullptr, ""};
252+
}
253+
214254
bool IsStringLiteralExpr(const clang::Expr *expr) {
215255
const auto *stripped = expr->IgnoreParens()->IgnoreImplicit();
216256
return clang::isa<clang::StringLiteral>(stripped) ||

‎cpp2rust/converter/converter_lib.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <optional>
1616
#include <string>
1717
#include <string_view>
18+
#include <tuple>
1819
#include <unordered_set>
1920
#include <vector>
2021

@@ -56,6 +57,9 @@ bool IsInMainFile(const clang::Decl *decl);
5657

5758
bool IsUnionArrayMember(const clang::Expr *base);
5859

60+
std::tuple<clang::MemberExpr *, clang::RecordDecl *, std::string>
61+
ReplaceNonUniformLibcField(clang::MemberExpr *expr);
62+
5963
bool IsStringLiteralExpr(const clang::Expr *expr);
6064

6165
bool IsCodeUnitStringLiteral(const clang::StringLiteral *expr);

‎cpp2rust/converter/models/boxed_vars.cpp‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,9 @@ class AddressTakenVisitor
214214
void AddValueUse(clang::Expr *expr, bool write = false) {
215215
expr = expr->IgnoreParens();
216216
if (auto *member = clang::dyn_cast<clang::MemberExpr>(expr)) {
217-
if (!member->isArrow() &&
218-
clang::isa<clang::FieldDecl>(member->getMemberDecl())) {
217+
auto *field = clang::dyn_cast<clang::FieldDecl>(member->getMemberDecl());
218+
// A union member is accessed through a pointer to the union.
219+
if (!member->isArrow() && field && !field->getParent()->isUnion()) {
219220
AddValueUse(member->getBase(), write);
220221
}
221222
} else if (auto *subscript =

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -726,8 +726,7 @@ void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) {
726726
field->getType()->getAsArrayTypeUnsafe()->getElementType())
727727
: ToString(field->getType());
728728
StrCat(std::format(
729-
"pub fn {}(&self) -> Ptr<{}> {{ (self.__bytes.as_pointer() "
730-
"as Ptr<u8>).reinterpret_cast() }}",
729+
"pub fn {}(this: Ptr<Self>) -> Ptr<{}> {{ this.reinterpret_cast() }}",
731730
GetNamedDeclAsString(field), ty));
732731
}
733732
}
@@ -1918,14 +1917,18 @@ bool ConverterRefCount::VisitCXXStdInitializerListExpr(
19181917

19191918
void ConverterRefCount::ConvertUnionMemberAccessor(clang::MemberExpr *expr) {
19201919
auto member = expr->getMemberDecl();
1921-
std::string str;
1922-
{
1923-
Buffer buf(*this);
1924-
PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue);
1925-
Converter::ConvertMemberExpr(expr);
1926-
str = std::move(buf).str();
1927-
}
1928-
str += "()";
1920+
auto *record = clang::cast<clang::RecordDecl>(member->getDeclContext());
1921+
auto name = GetNamedDeclAsString(member);
1922+
auto *accessed = expr;
1923+
if (auto [inner, libc_record, libc_name] = ReplaceNonUniformLibcField(expr);
1924+
inner) {
1925+
record = libc_record;
1926+
name = libc_name;
1927+
accessed = inner;
1928+
}
1929+
auto ptr = ConvertRecordPtr(accessed);
1930+
auto str = std::format("{}::{}({}{})", GetRecordName(record), name, ptr,
1931+
isFresh() ? "" : ".clone()");
19291932

19301933
if (isAddrOf()) {
19311934
if (member->getType()->isArrayType()) {

‎rules/ip/shim.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2022-present INESC-ID.
22
// Distributed under the MIT license that can be found in the LICENSE file.
33

4-
use crate::{AsPointer, ByteRepr, DeepClone, Ptr, Record, Value};
4+
use crate::{ByteRepr, DeepClone, Ptr, Record, Value};
55
use std::cell::RefCell;
66
use std::rc::Rc;
77

@@ -21,8 +21,8 @@ pub struct In6Addr {
2121
}
2222

2323
impl In6Addr {
24-
pub fn s6_addr(&self) -> Ptr<u8> {
25-
self.s6_addr.as_pointer()
24+
pub fn s6_addr(this: Ptr<Self>) -> Ptr<u8> {
25+
this.reinterpret_cast()
2626
}
2727
}
2828

‎tests/unit/out/refcount/tag_vs_identifier_collision.rs‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ pub struct point {
3434
__bytes: Value<Box<[u8]>>,
3535
}
3636
impl point {
37-
pub fn whole(&self) -> Ptr<i32> {
38-
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
37+
pub fn whole(this: Ptr<Self>) -> Ptr<i32> {
38+
this.reinterpret_cast()
3939
}
40-
pub fn half(&self) -> Ptr<i16> {
41-
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
40+
pub fn half(this: Ptr<Self>) -> Ptr<i16> {
41+
this.reinterpret_cast()
4242
}
4343
}
4444
impl Default for point {
@@ -56,11 +56,11 @@ pub struct slot_union {
5656
__bytes: Value<Box<[u8]>>,
5757
}
5858
impl slot_union {
59-
pub fn i(&self) -> Ptr<i32> {
60-
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
59+
pub fn i(this: Ptr<Self>) -> Ptr<i32> {
60+
this.reinterpret_cast()
6161
}
62-
pub fn u(&self) -> Ptr<u32> {
63-
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
62+
pub fn u(this: Ptr<Self>) -> Ptr<u32> {
63+
this.reinterpret_cast()
6464
}
6565
}
6666
impl Default for slot_union {
@@ -114,11 +114,11 @@ fn main_0() -> i32 {
114114
p.y = 4;
115115
assert!(((((p.x + p.y) == 7) as i32) != 0));
116116
let up: Value<point> = <Value<point>>::default();
117-
(*up.borrow_mut()).whole().write(5);
118-
assert!((((((*up.borrow()).whole().read()) == 5) as i32) != 0));
117+
point::whole(up.as_pointer()).write(5);
118+
assert!(((((point::whole(up.as_pointer()).read()) == 5) as i32) != 0));
119119
let b: Value<slot_union> = <Value<slot_union>>::default();
120-
(*b.borrow_mut()).i().write(9);
121-
assert!((((((*b.borrow()).i().read()) == 9) as i32) != 0));
120+
slot_union::i(b.as_pointer()).write(9);
121+
assert!(((((slot_union::i(b.as_pointer()).read()) == 9) as i32) != 0));
122122
let mut e: slot = slot_SLOT_B;
123123
assert!(((((e as u32) == ((slot_SLOT_B as i32) as u32)) as i32) != 0));
124124
let mut inner_tag: Inner = <Inner>::default();

‎tests/unit/out/refcount/union_addrof_external.rs‎

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ pub struct anon_0 {
3737
__bytes: Value<Box<[u8]>>,
3838
}
3939
impl anon_0 {
40-
pub fn h(&self) -> Ptr<record> {
41-
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
40+
pub fn h(this: Ptr<Self>) -> Ptr<record> {
41+
this.reinterpret_cast()
4242
}
43-
pub fn raw_(&self) -> Ptr<i8> {
44-
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
43+
pub fn raw_(this: Ptr<Self>) -> Ptr<i8> {
44+
this.reinterpret_cast()
4545
}
4646
}
4747
impl Default for anon_0 {
@@ -101,10 +101,14 @@ fn main_0() -> i32 {
101101
let _cap: usize = 128usize;
102102
fill_1(_out, _cap)
103103
});
104-
assert!((((((*c.borrow()).view.h().with(|__s| __s.code) as i32) == 2) as i32) != 0));
104+
assert!(
105+
((((anon_0::h(field_ptr!(c.as_pointer(), view)).with(|__s| __s.code) as i32) == 2) as i32)
106+
!= 0)
107+
);
105108
assert!(
106109
(((((elem!(
107-
((field_ptr!((*c.borrow()).view.h(), lo)).reinterpret_cast::<u8>()),
110+
((field_ptr!(anon_0::h(field_ptr!(c.as_pointer(), view)), lo))
111+
.reinterpret_cast::<u8>()),
108112
0
109113
)
110114
.read()) as i32)
@@ -113,7 +117,8 @@ fn main_0() -> i32 {
113117
);
114118
assert!(
115119
(((((elem!(
116-
((field_ptr!((*c.borrow()).view.h(), lo)).reinterpret_cast::<u8>()),
120+
((field_ptr!(anon_0::h(field_ptr!(c.as_pointer(), view)), lo))
121+
.reinterpret_cast::<u8>()),
117122
1
118123
)
119124
.read()) as i32)
@@ -122,7 +127,7 @@ fn main_0() -> i32 {
122127
);
123128
assert!(
124129
(((((elem!(
125-
((*c.borrow()).view.raw_().reinterpret_cast::<i8>() as Ptr::<i8>),
130+
(anon_0::raw_(field_ptr!(c.as_pointer(), view)).reinterpret_cast::<i8>() as Ptr::<i8>),
126131
0
127132
)
128133
.read()) as i32)
@@ -131,7 +136,7 @@ fn main_0() -> i32 {
131136
);
132137
assert!(
133138
((((((elem!(
134-
((*c.borrow()).view.raw_().reinterpret_cast::<i8>() as Ptr::<i8>),
139+
(anon_0::raw_(field_ptr!(c.as_pointer(), view)).reinterpret_cast::<i8>() as Ptr::<i8>),
135140
3
136141
)
137142
.read()) as u8) as i32)

‎tests/unit/out/refcount/union_basic.rs‎

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ pub struct basic {
1414
__bytes: Value<Box<[u8]>>,
1515
}
1616
impl basic {
17-
pub fn i(&self) -> Ptr<i32> {
18-
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
17+
pub fn i(this: Ptr<Self>) -> Ptr<i32> {
18+
this.reinterpret_cast()
1919
}
20-
pub fn f(&self) -> Ptr<f32> {
21-
(self.__bytes.as_pointer() as Ptr<u8>).reinterpret_cast()
20+
pub fn f(this: Ptr<Self>) -> Ptr<f32> {
21+
this.reinterpret_cast()
2222
}
2323
}
2424
impl Default for basic {
@@ -51,10 +51,26 @@ fn main_0() -> i32 {
5151
let u: Value<basic> = Rc::new(RefCell::new(<basic>::default()));
5252
let e: Value<empty> = Rc::new(RefCell::new(<empty>::default()));
5353
&(*e.borrow_mut());
54-
(*u.borrow_mut()).i().write(42);
55-
assert!((((*u.borrow()).i().read()) == 42));
56-
(*u.borrow_mut()).f().write(3.140000105E+0);
57-
assert!((((*u.borrow()).f().read()) == 3.140000105E+0));
54+
basic::i(u.as_pointer()).write(42);
55+
assert!(((basic::i(u.as_pointer()).read()) == 42));
56+
basic::f(u.as_pointer()).write(3.140000105E+0);
57+
assert!(((basic::f(u.as_pointer()).read()) == 3.140000105E+0));
58+
let buf: Value<Box<[u8]>> = Rc::new(RefCell::new((0..4).map(|_| 0_u8).collect::<Box<[u8]>>()));
59+
{
60+
((buf.as_pointer() as Ptr<u8>) as Ptr<u8>)
61+
.to_any()
62+
.memset((0) as u8, ::std::mem::size_of::<[u8; 4]>() as usize);
63+
((buf.as_pointer() as Ptr<u8>) as Ptr<u8>).to_any()
64+
};
65+
let mut ru: Ptr<basic> = (buf.as_pointer() as Ptr<u8>).reinterpret_cast::<basic>();
66+
let mut pi: Ptr<i32> = (basic::i(ru.clone())).clone();
67+
let mut pf: Ptr<f32> = (basic::f(ru.clone())).clone();
68+
basic::i(ru.clone()).write(7);
69+
assert!(((pi.read()) == 7));
70+
pi.write(1065353216);
71+
assert!(((basic::i(ru.clone()).read()) == 1065353216));
72+
assert!(((pf.read()) == 1.0E+0));
73+
assert!((((*buf.borrow())[(3) as usize] as i32) == 63));
5874
return 0;
5975
}
6076
pub fn __cpp2rust_init_globals() {}

0 commit comments

Comments
 (0)