Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3518,6 +3518,7 @@ void Converter::SetUFCSReceiver(clang::Expr *base, bool is_arrow,
void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
if (auto mapped = GetMappedAsString(expr); !mapped.empty()) {
if (RuleRegistry::ReturnsPointer(ctx_, expr)) {
PushParen paren(*this);
StrCat(token::kStar, mapped);
} else {
StrCat(mapped);
Expand All @@ -3526,11 +3527,6 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
}

auto *member = expr->getMemberDecl();
auto [inner, record, name_override] = ReplaceNonUniformLibcField(expr);
if (inner) {
expr = inner;
}

auto *base = expr->getBase();
bool base_is_this = clang::isa<clang::CXXThisExpr>(base->IgnoreCasts()) &&
!ThisIsRustPtr() && !AsLambdaOperatorCall(curr_function_);
Expand All @@ -3549,8 +3545,6 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) {
method && IsOverloadedMethod(method)) {
StrCat(token::kDot);
StrCat(GetMethodName(method));
} else if (!name_override.empty()) {
StrCat(token::kDot, name_override);
} else if (member->getDeclName().isIdentifier()) {
StrCat(token::kDot);
StrCat(GetNamedDeclAsString(member));
Expand Down
45 changes: 5 additions & 40 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "converter/lex.h"
#include "converter/mapper.h"
#include "converter/rules/decls.h"
#include "converter/rules/registry.h"

// https://doc.rust-lang.org/reference/keywords.html
Expand Down Expand Up @@ -222,45 +223,6 @@ clang::Expr *SubscriptedArray(clang::Expr *base) {
}

// TODO: this will be gone when the AST matcher lands
std::tuple<clang::MemberExpr *, clang::RecordDecl *, std::string>
ReplaceNonUniformLibcField(clang::MemberExpr *expr) {
// Example: ::struct stat::st_mtim::tv_sec -> ::libc::stat::st_mtime
struct Mapping {
const char *record;
const char *inner_field;
const char *leaf_field;
const char *replacement;
};
static constexpr Mapping kFields[] = {
{"stat", "st_mtim", "tv_sec", "st_mtime"}, // Linux
{"stat", "st_mtimespec", "tv_sec", "st_mtime"}, // macOS
{"in6_addr", "__in6_u", "__u6_addr8", "s6_addr"},
};

auto getNamedIdentifierOrNull = [](auto *decl) {
return decl && decl->getDeclName().isIdentifier() ? decl : nullptr;
};

if (auto leaf = getNamedIdentifierOrNull(expr->getMemberDecl())) {
if (auto inner = clang::dyn_cast<clang::MemberExpr>(
expr->getBase()->IgnoreParenImpCasts())) {
if (auto field = getNamedIdentifierOrNull(
clang::dyn_cast<clang::FieldDecl>(inner->getMemberDecl()))) {
if (getNamedIdentifierOrNull(field->getParent())) {
for (const auto &m : kFields) {
if (field->getParent()->getName() == m.record &&
field->getName() == m.inner_field &&
leaf->getName() == m.leaf_field) {
return {inner, field->getParent(), m.replacement};
}
}
}
}
}
}
return {nullptr, nullptr, ""};
}

bool IsStringLiteralExpr(const clang::Expr *expr) {
const auto *stripped = expr->IgnoreParens()->IgnoreImplicit();
return clang::isa<clang::StringLiteral>(stripped) ||
Expand Down Expand Up @@ -1883,7 +1845,10 @@ BuildUnifiedArgs(clang::Expr *expr, clang::Expr **args, unsigned num_args) {
if (auto *mcall = clang::dyn_cast<clang::CXXMemberCallExpr>(expr)) {
all_args.push_back(mcall->getImplicitObjectArgument());
} else if (auto *member = clang::dyn_cast<clang::MemberExpr>(expr)) {
all_args.push_back(member->getBase());
auto *base = RuleDecls::GetMacroMemberBase(
member->getMemberDecl()->getASTContext().getSourceManager(), member);
all_args.push_back(
const_cast<clang::Expr *>(base ? base : member->getBase()));
}
for (unsigned i = 0; i < num_args; ++i) {
all_args.push_back(args[i]);
Expand Down
3 changes: 0 additions & 3 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@ bool IsUnionArrayMember(const clang::Expr *base);

clang::Expr *SubscriptedArray(clang::Expr *base);

std::tuple<clang::MemberExpr *, clang::RecordDecl *, std::string>
ReplaceNonUniformLibcField(clang::MemberExpr *expr);

bool IsStringLiteralExpr(const clang::Expr *expr);

bool IsCodeUnitStringLiteral(const clang::StringLiteral *expr);
Expand Down
25 changes: 17 additions & 8 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1981,14 +1981,7 @@ void ConverterRefCount::ConvertUnionMemberAccessor(clang::MemberExpr *expr) {
auto member = expr->getMemberDecl();
auto *record = clang::cast<clang::RecordDecl>(member->getDeclContext());
auto name = GetNamedDeclAsString(member);
auto *accessed = expr;
if (auto [inner, libc_record, libc_name] = ReplaceNonUniformLibcField(expr);
inner) {
record = libc_record;
name = libc_name;
accessed = inner;
}
auto ptr = ConvertRecordPtr(accessed);
auto ptr = ConvertRecordPtr(expr);
auto str = std::format("{}::{}({}{})", GetRecordName(record), name, ptr,
isFresh() ? "" : ".clone()");

Expand Down Expand Up @@ -2028,6 +2021,22 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) {
}
bool known = Mapper::Contains(ctx_, expr);

if (known && RuleRegistry::ReturnsPointer(ctx_, expr)) {
auto str = GetMappedAsString(expr);
if (isAddrOf()) {
StrCat(str);
computed_expr_type_ = ComputedExprType::FreshPointer;
return false;
}
if (isLValue()) {
pending_deref_.set(str, /*fresh=*/true);
return false;
}
StrCat(DerefPtrExpr(str, expr->getType()));
SetDerefFreshness(expr->getType());
return false;
}

if (auto *method = clang::dyn_cast<clang::CXXMethodDecl>(member);
method && !known) {
if (IsMethodOnPtr(method)) {
Expand Down
27 changes: 27 additions & 0 deletions cpp2rust/converter/rules/decls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,33 @@ const clang::Expr *GetReturned(const clang::FunctionDecl *rule) {
return returned;
}

namespace {
clang::FileID getMacroExpansion(const clang::SourceManager &sm,
clang::SourceLocation loc) {
while (loc.isMacroID() && sm.isMacroArgExpansion(loc)) {
loc = sm.getImmediateSpellingLoc(loc);
}
return loc.isMacroID() ? sm.getFileID(loc) : clang::FileID();
}
} // namespace

const clang::Expr *GetMacroMemberBase(const clang::SourceManager &sm,
const clang::MemberExpr *member) {
auto file = getMacroExpansion(sm, member->getMemberLoc());
if (file.isInvalid() ||
sm.getSLocEntry(file).getExpansion().isFunctionMacroExpansion()) {
return nullptr;
}
const clang::Expr *base = member->getBase();
while (true) {
auto inner = llvm::dyn_cast<clang::MemberExpr>(base->IgnoreParenImpCasts());
if (!inner || getMacroExpansion(sm, inner->getMemberLoc()) != file) {
return base;
}
base = inner->getBase();
}
}

clang::QualType EnableIfSameType(const clang::Decl *rule) {
auto tmpl = llvm::dyn_cast<clang::TemplateDecl>(rule);
if (!tmpl) {
Expand Down
4 changes: 4 additions & 0 deletions cpp2rust/converter/rules/decls.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <clang/AST/TemplateBase.h>
#include <clang/AST/Type.h>
#include <clang/Basic/Diagnostic.h>
#include <clang/Basic/SourceManager.h>
#include <clang/Sema/Sema.h>

#include <optional>
Expand Down Expand Up @@ -38,6 +39,9 @@ const clang::Expr *SkipImplicit(const clang::Expr *expr);

const clang::Expr *GetReturned(const clang::FunctionDecl *rule);

const clang::Expr *GetMacroMemberBase(const clang::SourceManager &sm,
const clang::MemberExpr *member);

clang::QualType EnableIfSameType(const clang::Decl *rule);

std::optional<std::vector<clang::TemplateArgument>>
Expand Down
12 changes: 11 additions & 1 deletion cpp2rust/converter/rules/expr_matcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ ResolvedDecl getResolvedDecl(clang::ASTContext &ctx, const clang::Expr *expr,
} else if (auto construct = llvm::dyn_cast<clang::CXXConstructExpr>(expr)) {
return construct->getConstructor()->getCanonicalDecl();
} else if (auto member = llvm::dyn_cast<clang::MemberExpr>(expr)) {
auto &sm = ctx.getSourceManager();
if (RuleDecls::GetMacroMemberBase(sm, member)) {
return MacroUsage{clang::Lexer::getImmediateMacroName(
member->getMemberLoc(), sm, ctx.getLangOpts())
.str()};
}
return member->getMemberDecl()->getCanonicalDecl();
} else if (auto ref = llvm::dyn_cast<clang::DeclRefExpr>(expr)) {
return ref->getDecl()->getCanonicalDecl();
Expand Down Expand Up @@ -144,7 +150,11 @@ std::vector<clang::Expr *> getOperands(clang::ASTContext &ctx,
} else if (auto construct = llvm::dyn_cast<clang::CXXConstructExpr>(expr)) {
operands.assign(construct->arg_begin(), construct->arg_end());
} else if (auto member = llvm::dyn_cast<clang::MemberExpr>(expr)) {
auto base = member->getBase()->IgnoreParenImpCasts();
auto macro_base =
RuleDecls::GetMacroMemberBase(ctx.getSourceManager(), member);
auto base =
const_cast<clang::Expr *>(macro_base ? macro_base : member->getBase())
->IgnoreParenImpCasts();
if (auto arrow = llvm::dyn_cast<clang::CXXOperatorCallExpr>(base);
arrow && arrow->getOperator() == clang::OO_Arrow) {
base = arrow->getArg(0);
Expand Down
6 changes: 6 additions & 0 deletions cpp2rust/converter/rules/rule_keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ std::optional<ExprKey> getExprKey(clang::ASTContext &ctx,
return Unqualified{ref->getDeclName()};
}
if (auto member = llvm::dyn_cast<clang::MemberExpr>(expr)) {
auto &sm = ctx.getSourceManager();
if (RuleDecls::GetMacroMemberBase(sm, member)) {
auto macro = clang::Lexer::getImmediateMacroName(member->getMemberLoc(),
sm, ctx.getLangOpts());
return Unqualified{clang::DeclarationName(&ctx.Idents.get(macro))};
}
return getDeclKey(member->getMemberDecl());
}
if (auto ref = llvm::dyn_cast<clang::DeclRefExpr>(expr)) {
Expand Down
7 changes: 7 additions & 0 deletions cpp2rust/converter/rules/rules_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <vector>

#include "converter/converter_lib.h"
#include "converter/rules/decls.h"
#include "logging.h"

namespace cpp2rust::RulesLoader {
Expand Down Expand Up @@ -442,6 +443,12 @@ std::string ExprKey(clang::ASTContext &ctx, const clang::Expr *expr) {
return FunctionKey(construct->getConstructor());
}
if (auto member = llvm::dyn_cast<clang::MemberExpr>(expr)) {
if (RuleDecls::GetMacroMemberBase(ctx.getSourceManager(), member)) {
return clang::Lexer::getImmediateMacroName(member->getMemberLoc(),
ctx.getSourceManager(),
ctx.getLangOpts())
.str();
}
return DeclKey(member->getMemberDecl());
}
if (auto ref = llvm::dyn_cast<clang::DeclRefExpr>(expr)) {
Expand Down
5 changes: 5 additions & 0 deletions rules/ip/src.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ int f5(void) { return IPPROTO_MPTCP; }
#endif

int f6(void) { return TCP_NODELAY; }

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-stack-address"
uint8_t *f7(struct in6_addr a0) { return a0.s6_addr; }
#pragma clang diagnostic pop
4 changes: 4 additions & 0 deletions rules/ip/tgt_refcount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ fn t3() -> libcc2rs::SockaddrIn6 {
fn t4() -> libcc2rs::In6Addr {
Default::default()
}

fn f7(a0: Ptr<In6Addr>) -> Ptr<u8> {
In6Addr::s6_addr(a0)
}
4 changes: 4 additions & 0 deletions rules/ip/tgt_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@ unsafe fn f5() -> i32 {
unsafe fn f6() -> i32 {
libc::TCP_NODELAY
}

unsafe fn f7(a0: *mut ::libc::in6_addr) -> *mut [u8; 16] {
&raw mut (*a0).s6_addr
}
2 changes: 2 additions & 0 deletions rules/stat/src.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ int f1(const char *pathname, struct stat *statbuf) {
int f2(int fd, struct stat *statbuf) { return fstat(fd, statbuf); }

int f3(const char *pathname, mode_t mode) { return mkdir(pathname, mode); }

time_t f4(struct stat a0) { return a0.st_mtime; }
4 changes: 4 additions & 0 deletions rules/stat/tgt_refcount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ fn f3(a0: Ptr<i8>, a1: ::libc::mode_t) -> i32 {
}
}
}

fn f4(a0: Ptr<Stat>) -> Ptr<i64> {
field_ptr!(a0, st_mtime)
}
4 changes: 4 additions & 0 deletions rules/stat/tgt_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ unsafe fn f2(a0: i32, a1: *mut ::libc::stat) -> i32 {
unsafe fn f3(a0: *const libc::c_char, a1: ::libc::mode_t) -> i32 {
libc::mkdir(a0, a1 as ::libc::mode_t)
}

unsafe fn f4(a0: *mut ::libc::stat) -> *mut ::libc::time_t {
&raw mut (*a0).st_mtime
}
24 changes: 24 additions & 0 deletions tests/unit/inet_pton_ntop.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,31 @@
#include <assert.h>
#include <string.h>

static void test_s6_addr_access(void) {
const unsigned char loopback[16] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1};
struct in6_addr addr;
struct in6_addr *ap = &addr;
memcpy(addr.s6_addr, loopback, 16);
assert(memcmp(ap->s6_addr, loopback, 16) == 0);
addr.s6_addr[0] = 0x20;
ap->s6_addr[1] = 0x01;
assert(addr.s6_addr[0] == 0x20 && ap->s6_addr[1] == 0x01);
addr.s6_addr[15] += 4;
ap->s6_addr[15]++;
assert(addr.s6_addr[15] == 6);
unsigned char *bytes = addr.s6_addr;
bytes[2] = 7;
assert(ap->s6_addr[2] == 7);
unsigned char *fourth = &ap->s6_addr[3];
*fourth = 8;
assert(addr.s6_addr[3] == 8);
memcpy(ap->s6_addr, loopback, 16);
assert(memcmp(addr.s6_addr, loopback, 16) == 0);
}

int main(void) {
test_s6_addr_access();
unsigned char buf[16];
assert(inet_pton(AF_INET, "1.2.3.4", buf) == 1);
assert(buf[0] == 1 && buf[1] == 2 && buf[2] == 3 && buf[3] == 4);
Expand Down
Loading
Loading