Skip to content

Commit daba927

Browse files
committed
Add dummy definition for referenced never-defined structs
1 parent 2c67f24 commit daba927

9 files changed

Lines changed: 136 additions & 1 deletion

File tree

cpp2rust/converter/converter.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ std::unordered_set<std::string> Converter::record_decls_;
2323
std::unordered_set<std::string> Converter::decl_ids_;
2424
std::unordered_set<std::string> Converter::globals_;
2525
std::unordered_set<std::string> Converter::abstract_structs_;
26+
std::unordered_map<std::string, std::string> Converter::referenced_records_;
2627

2728
void Converter::ConvertUniquePtrDeref(clang::CXXOperatorCallExpr *expr) {
2829
bool is_star = expr->getOperator() == clang::OverloadedOperatorKind::OO_Star;
@@ -53,6 +54,19 @@ use std::rc::Rc;
5354
)");
5455
}
5556

57+
std::string Converter::EmitOpaqueRecordMarkers() {
58+
std::string out;
59+
for (const auto &[id, name] : referenced_records_) {
60+
if (record_decls_.contains(id)) {
61+
continue;
62+
}
63+
out += "#[repr(C)] pub struct ";
64+
out += name;
65+
out += " { _opaque: [u8; 0] }\n";
66+
}
67+
return out;
68+
}
69+
5670
bool Converter::VisitRecoveryExpr(clang::RecoveryExpr *expr) {
5771
llvm::errs() << "RecoveryExpr: ";
5872
expr->dump();
@@ -160,7 +174,11 @@ bool Converter::VisitRecordType(clang::RecordType *type) {
160174
}
161175
}
162176

163-
StrCat(GetRecordName(decl));
177+
auto name = GetRecordName(decl);
178+
StrCat(name);
179+
if (!ctx_.getSourceManager().isInSystemHeader(decl->getLocation())) {
180+
referenced_records_.try_emplace(GetID(decl), std::move(name));
181+
}
164182
Mapper::AddRuleForUserDefinedType(decl);
165183
return false;
166184
}

cpp2rust/converter/converter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
5151

5252
virtual void EmitFilePreamble();
5353

54+
// Returns Rust text emitting `pub struct N { _opaque: [u8; 0] }` for each
55+
// record name referenced by some TU but never defined by any.
56+
static std::string EmitOpaqueRecordMarkers();
57+
5458
virtual bool VisitBuiltinType(clang::BuiltinType *type);
5559

5660
virtual bool VisitRecordType(clang::RecordType *type);
@@ -646,6 +650,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
646650
static std::unordered_set<std::string> decl_ids_;
647651
static std::unordered_set<std::string> record_decls_;
648652
static std::unordered_set<std::string> abstract_structs_;
653+
static std::unordered_map<std::string, std::string> referenced_records_;
649654

650655
enum class ExprKind : uint8_t {
651656
Callee,

cpp2rust/cpp2rust_lib.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <filesystem>
1111

1212
#include "compat/platform_flags.h"
13+
#include "converter/converter.h"
1314
#include "frontend_action.h"
1415

1516
namespace cpp2rust {
@@ -29,6 +30,7 @@ std::string TranspileSrc(std::string_view cc_code, Model model,
2930
rules_dir),
3031
cc_code, tool_args, std::filesystem::path(filename).filename().string(),
3132
filename.ends_with(".c") ? CLANG_C_COMPILER : CLANG_CXX_COMPILER);
33+
rs_code += Converter::EmitOpaqueRecordMarkers();
3234
return rs_code;
3335
}
3436

@@ -68,6 +70,7 @@ std::string TranspileDir(std::string_view build_dir, Model model,
6870
std::string rs_code;
6971
FrontendActionFactory factory(rs_code, model, rules_dir);
7072
Tool.run(&factory);
73+
rs_code += Converter::EmitOpaqueRecordMarkers();
7174
return rs_code;
7275
}
7376
} // namespace cpp2rust
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
project(opaque_forward_decl LANGUAGES C)
3+
add_executable(app a.c b.c)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <assert.h>
2+
#include <stddef.h>
3+
4+
#include "header.h"
5+
6+
int main(void) {
7+
struct container c = {NULL, 42};
8+
touch(&c);
9+
assert(c.x == 42);
10+
assert(c.p == NULL);
11+
return 0;
12+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include "header.h"
2+
3+
void touch(struct container *c) {
4+
/* read the opaque pointer field without dereferencing the opaque type */
5+
(void)c->p;
6+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
3+
/* Forward declaration only; no full definition exists anywhere in the build. */
4+
struct opaque;
5+
6+
struct container {
7+
struct opaque *p;
8+
int x;
9+
};
10+
11+
void touch(struct container *c);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
#[derive(Default)]
10+
pub struct container {
11+
pub p: Value<Ptr<opaque>>,
12+
pub x: Value<i32>,
13+
}
14+
impl ByteRepr for container {}
15+
pub fn main() {
16+
std::process::exit(main_0());
17+
}
18+
fn main_0() -> i32 {
19+
let c: Value<container> = Rc::new(RefCell::new(container {
20+
p: Rc::new(RefCell::new(Ptr::<opaque>::null())),
21+
x: Rc::new(RefCell::new(42)),
22+
}));
23+
({
24+
let _c: Ptr<container> = (c.as_pointer());
25+
touch_0(_c)
26+
});
27+
assert!(((((*(*c.borrow()).x.borrow()) == 42) as i32) != 0));
28+
assert!(((((*(*c.borrow()).p.borrow()).is_null()) as i32) != 0));
29+
return 0;
30+
}
31+
pub fn touch_0(c: Ptr<container>) {
32+
let c: Value<Ptr<container>> = Rc::new(RefCell::new(c));
33+
(*(*(*c.borrow()).upgrade().deref()).p.borrow()).clone();
34+
}
35+
#[repr(C)]
36+
pub struct opaque {
37+
_opaque: [u8; 0],
38+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
#[repr(C)]
10+
#[derive(Copy, Clone, Default)]
11+
pub struct container {
12+
pub p: *mut opaque,
13+
pub x: i32,
14+
}
15+
pub fn main() {
16+
unsafe {
17+
std::process::exit(main_0() as i32);
18+
}
19+
}
20+
unsafe fn main_0() -> i32 {
21+
let mut c: container = container {
22+
p: std::ptr::null_mut(),
23+
x: 42,
24+
};
25+
(unsafe {
26+
let _c: *mut container = (&mut c as *mut container);
27+
touch_0(_c)
28+
});
29+
assert!(((((c.x) == (42)) as i32) != 0));
30+
assert!(((((c.p).is_null()) as i32) != 0));
31+
return 0;
32+
}
33+
pub unsafe fn touch_0(mut c: *mut container) {
34+
&((*c).p);
35+
}
36+
#[repr(C)]
37+
pub struct opaque {
38+
_opaque: [u8; 0],
39+
}

0 commit comments

Comments
 (0)