Skip to content
Open
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
22 changes: 18 additions & 4 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@

namespace cpp2rust {
std::unordered_map<std::string, std::string> Converter::inner_structs_;
std::unordered_set<std::string> Converter::record_decls_;
std::unordered_set<std::string> Converter::decl_ids_;
std::unordered_set<std::string> Converter::globals_;
std::unordered_set<std::string> Converter::abstract_structs_;
Converter::RecordIndex Converter::record_decls_;

void Converter::ConvertUniquePtrDeref(clang::CXXOperatorCallExpr *expr) {
bool is_star = expr->getOperator() == clang::OverloadedOperatorKind::OO_Star;
Expand Down Expand Up @@ -53,6 +53,16 @@ use std::rc::Rc;
)");
}

std::string Converter::EmitOpaqueRecords() {
std::string out;
record_decls_.ForEachUndefined([&](const std::string &name) {
out += "pub struct ";
out += name;
out += ";\n";
});
return out;
}

bool Converter::VisitRecoveryExpr(clang::RecoveryExpr *expr) {
llvm::errs() << "RecoveryExpr: ";
expr->dump();
Expand Down Expand Up @@ -160,7 +170,11 @@ bool Converter::VisitRecordType(clang::RecordType *type) {
}
}

StrCat(GetRecordName(decl));
auto name = GetRecordName(decl);
StrCat(name);
if (!ctx_.getSourceManager().isInSystemHeader(decl->getLocation())) {
record_decls_.MarkReferenced(std::move(name));
}
Mapper::AddRuleForUserDefinedType(decl);
return false;
}
Expand Down Expand Up @@ -617,7 +631,7 @@ bool Converter::VisitRecordDecl(clang::RecordDecl *decl) {
return false;
}

if (!record_decls_.insert(GetID(decl)).second) {
if (!record_decls_.MarkDefined(GetRecordName(decl))) {
return false;
}

Expand Down Expand Up @@ -734,7 +748,7 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) {
}
}

if (!record_decls_.insert(GetID(decl)).second) {
if (!record_decls_.MarkDefined(GetRecordName(decl))) {
return false;
}

Expand Down
33 changes: 32 additions & 1 deletion cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

virtual void EmitFilePreamble();

static std::string EmitOpaqueRecords();

virtual bool VisitBuiltinType(clang::BuiltinType *type);

virtual bool VisitRecordType(clang::RecordType *type);
Expand Down Expand Up @@ -644,9 +646,38 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
~ScopedMapIterDecl() { c.map_iter_decls_.erase(decl); }
};
static std::unordered_set<std::string> decl_ids_;
static std::unordered_set<std::string> record_decls_;
static std::unordered_set<std::string> abstract_structs_;

class RecordIndex {
public:
void MarkReferenced(std::string name) {
entries_.try_emplace(std::move(name), false);
}
// Returns false if `name` is already defined; otherwise marks it and
// returns true.
bool MarkDefined(const std::string &name) {
bool &defined = entries_[name];
if (defined) {
return false;
}
defined = true;
return true;
}
template <typename F> void ForEachUndefined(F &&f) const {
for (const auto &[name, defined] : entries_) {
if (!defined) {
f(name);
}
}
}

private:
// record name -> true if a definition has been emitted, false if only
// referenced.
std::unordered_map<std::string, bool> entries_;
};
static RecordIndex record_decls_;

enum class ExprKind : uint8_t {
Callee,
LValue,
Expand Down
3 changes: 3 additions & 0 deletions cpp2rust/cpp2rust_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <filesystem>

#include "compat/platform_flags.h"
#include "converter/converter.h"
#include "frontend_action.h"

namespace cpp2rust {
Expand All @@ -29,6 +30,7 @@ std::string TranspileSrc(std::string_view cc_code, Model model,
rules_dir),
cc_code, tool_args, std::filesystem::path(filename).filename().string(),
filename.ends_with(".c") ? CLANG_C_COMPILER : CLANG_CXX_COMPILER);
rs_code += Converter::EmitOpaqueRecords();
return rs_code;
}

Expand Down Expand Up @@ -68,6 +70,7 @@ std::string TranspileDir(std::string_view build_dir, Model model,
std::string rs_code;
FrontendActionFactory factory(rs_code, model, rules_dir);
Tool.run(&factory);
rs_code += Converter::EmitOpaqueRecords();
return rs_code;
}
} // namespace cpp2rust
3 changes: 3 additions & 0 deletions tests/multi-file/opaque_forward_decl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.16)
project(opaque_forward_decl LANGUAGES C)
add_executable(app a.c b.c)
12 changes: 12 additions & 0 deletions tests/multi-file/opaque_forward_decl/a.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <assert.h>
#include <stddef.h>

#include "header.h"

int main(void) {
struct container c = {NULL, 42};
touch(&c);
assert(c.x == 42);
assert(c.p == NULL);
return 0;
}
3 changes: 3 additions & 0 deletions tests/multi-file/opaque_forward_decl/b.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "header.h"

void touch(struct container *c) { (void)c->p; }
10 changes: 10 additions & 0 deletions tests/multi-file/opaque_forward_decl/header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

struct opaque;

struct container {
struct opaque *p;
int x;
};

void touch(struct container *c);
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
extern crate libcc2rs;
use libcc2rs::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::{Read, Seek, Write};
use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
#[derive(Default)]
pub struct container {
pub p: Value<Ptr<opaque>>,
pub x: Value<i32>,
}
impl ByteRepr for container {}
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let c: Value<container> = Rc::new(RefCell::new(container {
p: Rc::new(RefCell::new(Ptr::<opaque>::null())),
x: Rc::new(RefCell::new(42)),
}));
({
let _c: Ptr<container> = (c.as_pointer());
touch_0(_c)
});
assert!(((((*(*c.borrow()).x.borrow()) == 42) as i32) != 0));
assert!(((((*(*c.borrow()).p.borrow()).is_null()) as i32) != 0));
return 0;
}
pub fn touch_0(c: Ptr<container>) {
let c: Value<Ptr<container>> = Rc::new(RefCell::new(c));
(*(*(*c.borrow()).upgrade().deref()).p.borrow()).clone();
}
pub struct opaque;
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
extern crate libc;
use libc::*;
extern crate libcc2rs;
use libcc2rs::*;
use std::collections::BTreeMap;
use std::io::{Read, Seek, Write};
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
use std::rc::Rc;
#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct container {
pub p: *mut opaque,
pub x: i32,
}
pub fn main() {
unsafe {
std::process::exit(main_0() as i32);
}
}
unsafe fn main_0() -> i32 {
let mut c: container = container {
p: std::ptr::null_mut(),
x: 42,
};
(unsafe {
let _c: *mut container = (&mut c as *mut container);
touch_0(_c)
});
assert!(((((c.x) == (42)) as i32) != 0));
assert!(((((c.p).is_null()) as i32) != 0));
return 0;
}
pub unsafe fn touch_0(mut c: *mut container) {
&((*c).p);
}
pub struct opaque;
14 changes: 14 additions & 0 deletions tests/unit/opaque_forward_decl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <stddef.h>

struct opaque;

struct container {
struct opaque *p;
int x;
};

int main(void) {
struct container c = {NULL, 42};
(void)c.p;
return c.x - 42;
}
21 changes: 21 additions & 0 deletions tests/unit/opaque_then_defined.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <assert.h>

struct node;

struct list {
struct node *head;
int size;
};

struct node {
int value;
struct node *next;
};

int main(void) {
struct node n = {42, 0};
struct list l = {&n, 1};
assert(l.head->value == 42);
assert(l.size == 1);
return 0;
}
26 changes: 26 additions & 0 deletions tests/unit/out/refcount/opaque_forward_decl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
extern crate libcc2rs;
use libcc2rs::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::{Read, Seek, Write};
use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
#[derive(Default)]
pub struct container {
pub p: Value<Ptr<opaque>>,
pub x: Value<i32>,
}
impl ByteRepr for container {}
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let c: Value<container> = Rc::new(RefCell::new(container {
p: Rc::new(RefCell::new(Ptr::<opaque>::null())),
x: Rc::new(RefCell::new(42)),
}));
(*(*c.borrow()).p.borrow()).clone();
return ((*(*c.borrow()).x.borrow()) - 42);
}
pub struct opaque;
42 changes: 42 additions & 0 deletions tests/unit/out/refcount/opaque_then_defined.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
extern crate libcc2rs;
use libcc2rs::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::{Read, Seek, Write};
use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
#[derive(Default)]
pub struct list {
pub head: Value<Ptr<node>>,
pub size: Value<i32>,
}
impl ByteRepr for list {}
#[derive(Default)]
pub struct node {
pub value: Value<i32>,
pub next: Value<Ptr<node>>,
}
impl ByteRepr for node {}
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let n: Value<node> = Rc::new(RefCell::new(node {
value: Rc::new(RefCell::new(42)),
next: Rc::new(RefCell::new(Ptr::<node>::null())),
}));
let l: Value<list> = Rc::new(RefCell::new(list {
head: Rc::new(RefCell::new((n.as_pointer()))),
size: Rc::new(RefCell::new(1)),
}));
assert!(
((((*(*(*(*l.borrow()).head.borrow()).upgrade().deref())
.value
.borrow())
== 42) as i32)
!= 0)
);
assert!(((((*(*l.borrow()).size.borrow()) == 1) as i32) != 0));
return 0;
}
28 changes: 28 additions & 0 deletions tests/unit/out/unsafe/opaque_forward_decl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
extern crate libc;
use libc::*;
extern crate libcc2rs;
use libcc2rs::*;
use std::collections::BTreeMap;
use std::io::{Read, Seek, Write};
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
use std::rc::Rc;
#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct container {
pub p: *mut opaque,
pub x: i32,
}
pub fn main() {
unsafe {
std::process::exit(main_0() as i32);
}
}
unsafe fn main_0() -> i32 {
let mut c: container = container {
p: std::ptr::null_mut(),
x: 42,
};
&(c.p);
return ((c.x) - (42));
}
pub struct opaque;
Loading
Loading