Skip to content

Commit 18e0f14

Browse files
authored
Add rules for more IP constants (#142)
IPPROTO_MPTCP is only defined on Linux. Before #144 the target_os attribute was used in the IR to define symbols that are platform specific in order to keep the IR uniform. But since the IR is not indexed in git anymore, the IR now can be different based on the platform. As such, I deleted the target_os from the IR. I also took this opportunity to replace the previous manual parsing of function attributes in rust with a proper parser, i.e. the cfg-expr crate. In the future I plan to use more attributes, other than target_os, for which I will need proper parsing of the function attributes. For example we also need target_arch, not only target_os.
1 parent ea12f2d commit 18e0f14

9 files changed

Lines changed: 57 additions & 54 deletions

File tree

cpp2rust/converter/translation_rule.cpp

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

137-
bool TargetOSMatchesHost(llvm::StringRef target_os) {
138-
#if defined(__linux__)
139-
return target_os == "linux";
140-
#elif defined(__APPLE__)
141-
return target_os == "macos";
142-
#else
143-
return false;
144-
#endif
145-
}
146-
147137
void LoadTgtFromIR(ExprRules &exprs, TypeRules &types,
148138
const std::filesystem::path &json_path) {
149139
auto buf = llvm::MemoryBuffer::getFile(json_path.string());
@@ -167,11 +157,6 @@ void LoadTgtFromIR(ExprRules &exprs, TypeRules &types,
167157
if (!obj)
168158
continue;
169159

170-
if (auto target_os = obj->getString("target_os");
171-
target_os && !TargetOSMatchesHost(*target_os)) {
172-
continue;
173-
}
174-
175160
auto name = entry_name.str();
176161
if (name[0] == 'f') {
177162
exprs[std::move(name)] = ParseExprRuleJSON(*obj);

rule-preprocessor/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2024"
66
[dependencies]
77
libcc2rs = { path = "../libcc2rs" }
88
rules = { path = "../rules" }
9+
cfg-expr = "0.20"
910
ra_ap_syntax = "0.0.266"
1011
serde = { version = "1", features = ["derive"] }
1112
serde_json = "1"
12-
syn = "2"

rule-preprocessor/src/ir.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ pub struct FnIr {
5757
pub params: Option<BTreeMap<String, TypeInfo>>,
5858
#[serde(skip_serializing_if = "Option::is_none")]
5959
pub return_type: Option<TypeInfo>,
60-
#[serde(skip_serializing_if = "Option::is_none")]
61-
pub target_os: Option<String>,
6260
}
6361

6462
impl FnIr {

rule-preprocessor/src/syntactic.rs

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Copyright (c) 2022-present INESC-ID.
22
// Distributed under the MIT license that can be found in the LICENSE file.
33

4-
use ra_ap_syntax::ast::{HasGenericParams, HasName, HasTypeBounds};
4+
use cfg_expr::Expression;
5+
use cfg_expr::expr::{Predicate, TargetPredicate};
6+
use ra_ap_syntax::ast::{HasAttrs, HasGenericParams, HasName, HasTypeBounds};
57
use ra_ap_syntax::{AstNode, SyntaxKind, ast, match_ast};
68
use std::collections::{BTreeMap, HashMap};
79
use std::path::{Path, PathBuf};
@@ -38,6 +40,31 @@ fn pointer_flags(ty: &ast::Type) -> (bool, bool) {
3840
flags
3941
}
4042

43+
fn cfg_matches_host(fn_item: &ast::Fn) -> bool {
44+
for attr in fn_item.attrs() {
45+
let Some(meta) = attr.meta() else { continue };
46+
let Some(path) = meta.path() else { continue };
47+
if path.syntax().text() != "cfg" {
48+
continue;
49+
}
50+
let meta_text = meta.syntax().text().to_string();
51+
let expr = Expression::parse(&meta_text)
52+
.unwrap_or_else(|e| panic!("failed to parse `{meta_text}`: {e}"));
53+
let matches = expr.eval(|pred| match pred {
54+
Predicate::Target(TargetPredicate::Os(os)) => match os.as_str() {
55+
"linux" => cfg!(target_os = "linux"),
56+
"macos" => cfg!(target_os = "macos"),
57+
other => panic!("unsupported target_os in cfg: {other}"),
58+
},
59+
_ => panic!("unsupported cfg predicate in `{meta_text}`"),
60+
});
61+
if !matches {
62+
return false;
63+
}
64+
}
65+
true
66+
}
67+
4168
pub struct SyntacticAnalysis;
4269

4370
impl SyntacticAnalysis {
@@ -49,12 +76,6 @@ impl SyntacticAnalysis {
4976
let source = std::fs::read_to_string(rule_file).unwrap();
5077
let file_ir = Self::parse_rule_file(&source, rule_file);
5178

52-
assert!(
53-
!file_ir.is_empty(),
54-
"Rule file {} produced no IR",
55-
rule_file.display()
56-
);
57-
5879
let canonical = rule_file
5980
.canonicalize()
6081
.unwrap_or_else(|_| rule_file.clone())
@@ -103,6 +124,9 @@ impl SyntacticAnalysis {
103124
file_ir.insert(name, RuleIr::Type(ir));
104125
}
105126
} else if fn_name.starts_with('f') {
127+
if !cfg_matches_host(&fn_item) {
128+
continue;
129+
}
106130
file_ir.insert(
107131
fn_name.clone(),
108132
RuleIr::Fn(FnIrBuilder::new(&fn_item).build(path)),
@@ -253,31 +277,6 @@ impl<'a> FnIrBuilder<'a> {
253277
Self { fn_item }
254278
}
255279

256-
fn get_target_os(&self) -> Option<String> {
257-
use ast::HasAttrs;
258-
for attr in self.fn_item.attrs() {
259-
let meta_text = attr.meta()?.syntax().text().to_string();
260-
let syn::Meta::List(list) = syn::parse_str(&meta_text).ok()? else {
261-
continue;
262-
};
263-
if !list.path.is_ident("cfg") {
264-
continue;
265-
}
266-
let mut found = None;
267-
let _ = list.parse_nested_meta(|nested| {
268-
if nested.path.is_ident("target_os") {
269-
let lit: syn::LitStr = nested.value()?.parse()?;
270-
found = Some(lit.value());
271-
}
272-
Ok(())
273-
});
274-
if found.is_some() {
275-
return found;
276-
}
277-
}
278-
None
279-
}
280-
281280
fn params(&self) -> Vec<ParamInfo> {
282281
let mut params = Vec::new();
283282
let Some(param_list) = self.fn_item.param_list() else {
@@ -512,7 +511,6 @@ impl<'a> FnIrBuilder<'a> {
512511
},
513512
multi_statement,
514513
body,
515-
target_os: self.get_target_os(),
516514
};
517515
ir.validate(&format!("{}:{}", path.display(), fn_name));
518516
ir

rules/ip/src.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,13 @@ int f2() {
1111
int f3() {
1212
return IPPROTO_IP;
1313
}
14+
15+
int f4() {
16+
return IPPROTO_IPV6;
17+
}
18+
19+
#if defined(__linux__)
20+
int f5() {
21+
return IPPROTO_MPTCP;
22+
}
23+
#endif

rules/ip/tgt_unsafe.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,12 @@ unsafe fn f2() -> i32 {
99
unsafe fn f3() -> i32 {
1010
libc::IPPROTO_IP
1111
}
12+
13+
unsafe fn f4() -> i32 {
14+
libc::IPPROTO_IPV6
15+
}
16+
17+
#[cfg(target_os = "linux")]
18+
unsafe fn f5() -> i32 {
19+
libc::IPPROTO_MPTCP
20+
}

tests/unit/ipproto_macros.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ int main() {
44
int tcp = IPPROTO_TCP;
55
int udp = IPPROTO_UDP;
66
int ip = IPPROTO_IP;
7-
return tcp + udp + ip;
7+
int ip6 = IPPROTO_IPV6;
8+
return tcp + udp + ip + ip6;
89
}

tests/unit/out/refcount/ipproto_macros.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ fn main_0() -> i32 {
1313
let tcp: Value<i32> = Rc::new(RefCell::new(libc::IPPROTO_TCP));
1414
let udp: Value<i32> = Rc::new(RefCell::new(libc::IPPROTO_UDP));
1515
let ip: Value<i32> = Rc::new(RefCell::new(libc::IPPROTO_IP));
16-
return (((*tcp.borrow()) + (*udp.borrow())) + (*ip.borrow()));
16+
let ip6: Value<i32> = Rc::new(RefCell::new(libc::IPPROTO_IPV6));
17+
return ((((*tcp.borrow()) + (*udp.borrow())) + (*ip.borrow())) + (*ip6.borrow()));
1718
}

tests/unit/out/unsafe/ipproto_macros.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ unsafe fn main_0() -> i32 {
1515
let mut tcp: i32 = libc::IPPROTO_TCP;
1616
let mut udp: i32 = libc::IPPROTO_UDP;
1717
let mut ip: i32 = libc::IPPROTO_IP;
18-
return (((tcp) + (udp)) + (ip));
18+
let mut ip6: i32 = libc::IPPROTO_IPV6;
19+
return ((((tcp) + (udp)) + (ip)) + (ip6));
1920
}

0 commit comments

Comments
 (0)