Skip to content

Commit f3b7d35

Browse files
committed
Access unions through Ptr<Self>
1 parent 8e7a199 commit f3b7d35

6 files changed

Lines changed: 64 additions & 56 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

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

3339-
// Returns the inner member and the replacement string.
3340-
static std::pair<clang::MemberExpr *, std::string>
3341-
replaceNonUniformLibcField(clang::MemberExpr *expr) {
3342-
// Example: ::struct stat::st_mtim::tv_sec -> ::libc::stat::st_mtime
3343-
struct Mapping {
3344-
const char *record;
3345-
const char *inner_field;
3346-
const char *leaf_field;
3347-
const char *replacement;
3348-
};
3349-
static constexpr Mapping kFields[] = {
3350-
{"stat", "st_mtim", "tv_sec", "st_mtime"}, // Linux
3351-
{"stat", "st_mtimespec", "tv_sec", "st_mtime"}, // macOS
3352-
{"in6_addr", "__in6_u", "__u6_addr8", "s6_addr"},
3353-
};
3354-
3355-
auto getNamedIdentifierOrNull = [](auto *decl) {
3356-
return decl && decl->getDeclName().isIdentifier() ? decl : nullptr;
3357-
};
3358-
3359-
if (auto leaf = getNamedIdentifierOrNull(expr->getMemberDecl())) {
3360-
if (auto inner = clang::dyn_cast<clang::MemberExpr>(
3361-
expr->getBase()->IgnoreParenImpCasts())) {
3362-
if (auto field = getNamedIdentifierOrNull(
3363-
clang::dyn_cast<clang::FieldDecl>(inner->getMemberDecl()))) {
3364-
if (getNamedIdentifierOrNull(field->getParent())) {
3365-
for (const auto &m : kFields) {
3366-
if (field->getParent()->getName() == m.record &&
3367-
field->getName() == m.inner_field &&
3368-
leaf->getName() == m.leaf_field) {
3369-
return {inner, m.replacement};
3370-
}
3371-
}
3372-
}
3373-
}
3374-
}
3375-
}
3376-
return {nullptr, ""};
3377-
}
3378-
33793339
void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
33803340
if (auto mapped = GetMappedAsString(expr); !mapped.empty()) {
33813341
if (RuleRegistry::ReturnsPointer(ctx_, expr)) {
@@ -3387,7 +3347,7 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
33873347
}
33883348

33893349
auto *member = expr->getMemberDecl();
3390-
auto [inner, name_override] = replaceNonUniformLibcField(expr);
3350+
auto [inner, record, name_override] = ReplaceNonUniformLibcField(expr);
33913351
if (inner) {
33923352
expr = inner;
33933353
}

‎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, 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

0 commit comments

Comments
 (0)