Skip to content

Commit 7e9a423

Browse files
authored
Add rules for socket_type enum values (#86)
This adds support for translating socket_types values: SOCK_STREAM, SOCK_DGRAM, SOCK_CLOEXEC (Linux specific), SOCK_NONBLOCK (Linux specific). The rules for CLOEXEC and NONBLOCK are only visible on Linux using the new IR field called `target_os`. On the C++ side, the rules are guarded with a macro: ```cpp #ifdef __linux__ int f4() { return SOCK_CLOEXEC; } int f5() { return SOCK_NONBLOCK; } #endif ``` On the Rust side, they are guarded using the target_os attribute: ```rs #[cfg(target_os = "linux")] unsafe fn f4() -> i32 { libc::SOCK_CLOEXEC } #[cfg(target_os = "linux")] unsafe fn f5() -> i32 { libc::SOCK_NONBLOCK } ``` `rule-preprocessor` parses the attributes of a function and adds `target_os = linux` in the IR. `translation_rule.cpp` skips the rule if the current OS is not the same as the OS declared by `target_os`.
1 parent f0faa2f commit 7e9a423

10 files changed

Lines changed: 165 additions & 1 deletion

File tree

cpp2rust/converter/translation_rule.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ TypeRule ParseTypeRuleJSON(const llvm::json::Object &obj) {
130130
return rule;
131131
}
132132

133+
bool TargetOSMatchesHost(llvm::StringRef target_os) {
134+
#if defined(__linux__)
135+
return target_os == "linux";
136+
#elif defined(__APPLE__)
137+
return target_os == "macos";
138+
#else
139+
return false;
140+
#endif
141+
}
142+
133143
void LoadTgtFromIR(ExprRules &exprs, TypeRules &types,
134144
const std::filesystem::path &json_path) {
135145
auto buf = llvm::MemoryBuffer::getFile(json_path.string());
@@ -153,6 +163,11 @@ void LoadTgtFromIR(ExprRules &exprs, TypeRules &types,
153163
if (!obj)
154164
continue;
155165

166+
if (auto target_os = obj->getString("target_os");
167+
target_os && !TargetOSMatchesHost(*target_os)) {
168+
continue;
169+
}
170+
156171
auto name = entry_name.str();
157172
if (name[0] == 'f') {
158173
exprs[std::move(name)] = ParseExprRuleJSON(*obj);

rule-preprocessor/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ rules = { path = "../rules" }
99
ra_ap_syntax = "0.0.266"
1010
serde = { version = "1", features = ["derive"] }
1111
serde_json = "1"
12+
syn = "2"

rule-preprocessor/src/ir.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ pub struct TypeInfo {
4848

4949
#[derive(Debug, Clone, Serialize, Deserialize)]
5050
pub struct FnIr {
51-
// Fields ordered alphabetically to match the old serde_json::Map output
5251
pub body: Vec<BodyFragment>,
5352
#[serde(skip_serializing_if = "Option::is_none")]
5453
pub generics: Option<BTreeMap<String, Vec<String>>>,
@@ -58,6 +57,8 @@ pub struct FnIr {
5857
pub params: Option<BTreeMap<String, TypeInfo>>,
5958
#[serde(skip_serializing_if = "Option::is_none")]
6059
pub return_type: Option<TypeInfo>,
60+
#[serde(skip_serializing_if = "Option::is_none")]
61+
pub target_os: Option<String>,
6162
}
6263

6364
impl FnIr {

rule-preprocessor/src/syntactic.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,31 @@ impl<'a> FnIrBuilder<'a> {
258258
Self { fn_item }
259259
}
260260

261+
fn get_target_os(&self) -> Option<String> {
262+
use ast::HasAttrs;
263+
for attr in self.fn_item.attrs() {
264+
let meta_text = attr.meta()?.syntax().text().to_string();
265+
let syn::Meta::List(list) = syn::parse_str(&meta_text).ok()? else {
266+
continue;
267+
};
268+
if !list.path.is_ident("cfg") {
269+
continue;
270+
}
271+
let mut found = None;
272+
let _ = list.parse_nested_meta(|nested| {
273+
if nested.path.is_ident("target_os") {
274+
let lit: syn::LitStr = nested.value()?.parse()?;
275+
found = Some(lit.value());
276+
}
277+
Ok(())
278+
});
279+
if found.is_some() {
280+
return found;
281+
}
282+
}
283+
None
284+
}
285+
261286
fn params(&self) -> Vec<ParamInfo> {
262287
let mut params = Vec::new();
263288
let Some(param_list) = self.fn_item.param_list() else {
@@ -499,6 +524,7 @@ impl<'a> FnIrBuilder<'a> {
499524
},
500525
multi_statement,
501526
body,
527+
target_os: self.get_target_os(),
502528
};
503529
ir.validate(&format!("{}:{}", path.display(), fn_name));
504530
ir

rules/socket/ir_unsafe.json

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,47 @@
88
"return_type": {
99
"type": "i32"
1010
}
11+
},
12+
"f2": {
13+
"body": [
14+
{
15+
"text": "libc::SOCK_STREAM"
16+
}
17+
],
18+
"return_type": {
19+
"type": "i32"
20+
}
21+
},
22+
"f3": {
23+
"body": [
24+
{
25+
"text": "libc::SOCK_DGRAM"
26+
}
27+
],
28+
"return_type": {
29+
"type": "i32"
30+
}
31+
},
32+
"f4": {
33+
"body": [
34+
{
35+
"text": "libc::SOCK_CLOEXEC"
36+
}
37+
],
38+
"return_type": {
39+
"type": "i32"
40+
},
41+
"target_os": "linux"
42+
},
43+
"f5": {
44+
"body": [
45+
{
46+
"text": "libc::SOCK_NONBLOCK"
47+
}
48+
],
49+
"return_type": {
50+
"type": "i32"
51+
},
52+
"target_os": "linux"
1153
}
1254
}

rules/socket/src.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,21 @@
44
int f1() {
55
return MSG_NOSIGNAL;
66
}
7+
8+
int f2() {
9+
return SOCK_STREAM;
10+
}
11+
12+
int f3() {
13+
return SOCK_DGRAM;
14+
}
15+
16+
#ifdef __linux__
17+
int f4() {
18+
return SOCK_CLOEXEC;
19+
}
20+
21+
int f5() {
22+
return SOCK_NONBLOCK;
23+
}
24+
#endif

rules/socket/tgt_unsafe.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
11
unsafe fn f1() -> i32 {
22
libc::MSG_NOSIGNAL
33
}
4+
5+
unsafe fn f2() -> i32 {
6+
libc::SOCK_STREAM
7+
}
8+
9+
unsafe fn f3() -> i32 {
10+
libc::SOCK_DGRAM
11+
}
12+
13+
#[cfg(target_os = "linux")]
14+
unsafe fn f4() -> i32 {
15+
libc::SOCK_CLOEXEC
16+
}
17+
18+
#[cfg(target_os = "linux")]
19+
unsafe fn f5() -> i32 {
20+
libc::SOCK_NONBLOCK
21+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
pub fn main() {
10+
std::process::exit(main_0());
11+
}
12+
fn main_0() -> i32 {
13+
assert!((((libc::SOCK_STREAM == 1) as i32) != 0));
14+
assert!((((libc::SOCK_DGRAM == 2) as i32) != 0));
15+
return 0;
16+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
pub fn main() {
10+
unsafe {
11+
std::process::exit(main_0() as i32);
12+
}
13+
}
14+
unsafe fn main_0() -> i32 {
15+
assert!(((((libc::SOCK_STREAM) == (1)) as i32) != 0));
16+
assert!(((((libc::SOCK_DGRAM) == (2)) as i32) != 0));
17+
return 0;
18+
}

tests/unit/socket_type_constants.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <assert.h>
2+
#include <sys/socket.h>
3+
#include <sys/types.h>
4+
5+
int main() {
6+
assert(SOCK_STREAM == 1);
7+
assert(SOCK_DGRAM == 2);
8+
return 0;
9+
}

0 commit comments

Comments
 (0)