From 9cec5b60571b8e7e8f12dc424fdae79ca6270504 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 22 May 2026 14:24:17 +0100 Subject: [PATCH 1/8] Add IPPROTO IPV6 and MPTCP --- rules/ip/src.cpp | 8 ++++++++ rules/ip/tgt_unsafe.rs | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/rules/ip/src.cpp b/rules/ip/src.cpp index 200abfc0..c66ba9fe 100644 --- a/rules/ip/src.cpp +++ b/rules/ip/src.cpp @@ -11,3 +11,11 @@ int f2() { int f3() { return IPPROTO_IP; } + +int f4() { + return IPPROTO_IPV6; +} + +int f5() { + return IPPROTO_MPTCP; +} diff --git a/rules/ip/tgt_unsafe.rs b/rules/ip/tgt_unsafe.rs index 7325fc09..766ed978 100644 --- a/rules/ip/tgt_unsafe.rs +++ b/rules/ip/tgt_unsafe.rs @@ -9,3 +9,11 @@ unsafe fn f2() -> i32 { unsafe fn f3() -> i32 { libc::IPPROTO_IP } + +unsafe fn f4() -> i32 { + libc::IPPROTO_IPV6 +} + +unsafe fn f5() -> i32 { + libc::IPPROTO_MPTCP +} From dac3b1adc1d31c34809efa422b0e06844eab7c84 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 22 May 2026 14:25:18 +0100 Subject: [PATCH 2/8] Update tests --- tests/unit/ipproto_macros.cpp | 4 +++- tests/unit/out/refcount/ipproto_macros.rs | 5 ++++- tests/unit/out/unsafe/ipproto_macros.rs | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/unit/ipproto_macros.cpp b/tests/unit/ipproto_macros.cpp index 39515059..8b049636 100644 --- a/tests/unit/ipproto_macros.cpp +++ b/tests/unit/ipproto_macros.cpp @@ -4,5 +4,7 @@ int main() { int tcp = IPPROTO_TCP; int udp = IPPROTO_UDP; int ip = IPPROTO_IP; - return tcp + udp + ip; + int ip6 = IPPROTO_IPV6; + int mptcp = IPPROTO_MPTCP; + return tcp + udp + ip + ip6 + mptcp; } diff --git a/tests/unit/out/refcount/ipproto_macros.rs b/tests/unit/out/refcount/ipproto_macros.rs index f9017278..f5da640d 100644 --- a/tests/unit/out/refcount/ipproto_macros.rs +++ b/tests/unit/out/refcount/ipproto_macros.rs @@ -13,5 +13,8 @@ fn main_0() -> i32 { let tcp: Value = Rc::new(RefCell::new(libc::IPPROTO_TCP)); let udp: Value = Rc::new(RefCell::new(libc::IPPROTO_UDP)); let ip: Value = Rc::new(RefCell::new(libc::IPPROTO_IP)); - return (((*tcp.borrow()) + (*udp.borrow())) + (*ip.borrow())); + let ip6: Value = Rc::new(RefCell::new(libc::IPPROTO_IPV6)); + let mptcp: Value = Rc::new(RefCell::new(libc::IPPROTO_MPTCP)); + return (((((*tcp.borrow()) + (*udp.borrow())) + (*ip.borrow())) + (*ip6.borrow())) + + (*mptcp.borrow())); } diff --git a/tests/unit/out/unsafe/ipproto_macros.rs b/tests/unit/out/unsafe/ipproto_macros.rs index 4ff8e7f7..3f9d4753 100644 --- a/tests/unit/out/unsafe/ipproto_macros.rs +++ b/tests/unit/out/unsafe/ipproto_macros.rs @@ -15,5 +15,7 @@ unsafe fn main_0() -> i32 { let mut tcp: i32 = libc::IPPROTO_TCP; let mut udp: i32 = libc::IPPROTO_UDP; let mut ip: i32 = libc::IPPROTO_IP; - return (((tcp) + (udp)) + (ip)); + let mut ip6: i32 = libc::IPPROTO_IPV6; + let mut mptcp: i32 = libc::IPPROTO_MPTCP; + return (((((tcp) + (udp)) + (ip)) + (ip6)) + (mptcp)); } From 647095b3f4067c059bae9c41999758b6ab20ddae Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 22 May 2026 14:40:29 +0100 Subject: [PATCH 3/8] Guard IPPROT_MPTCP on Linux only --- rules/ip/src.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rules/ip/src.cpp b/rules/ip/src.cpp index c66ba9fe..1fabb8b2 100644 --- a/rules/ip/src.cpp +++ b/rules/ip/src.cpp @@ -16,6 +16,8 @@ int f4() { return IPPROTO_IPV6; } +#if defined(__linux__) int f5() { return IPPROTO_MPTCP; } +#endif From f3cd74102f5b20ed4c66756d1f68526e65df0fe1 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 23 May 2026 14:10:17 +0100 Subject: [PATCH 4/8] Drop the target_os check --- cpp2rust/converter/translation_rule.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/cpp2rust/converter/translation_rule.cpp b/cpp2rust/converter/translation_rule.cpp index fa05ab7c..3f24e59a 100644 --- a/cpp2rust/converter/translation_rule.cpp +++ b/cpp2rust/converter/translation_rule.cpp @@ -134,16 +134,6 @@ TypeRule ParseTypeRuleJSON(const llvm::json::Object &obj) { return rule; } -bool TargetOSMatchesHost(llvm::StringRef target_os) { -#if defined(__linux__) - return target_os == "linux"; -#elif defined(__APPLE__) - return target_os == "macos"; -#else - return false; -#endif -} - void LoadTgtFromIR(ExprRules &exprs, TypeRules &types, const std::filesystem::path &json_path) { auto buf = llvm::MemoryBuffer::getFile(json_path.string()); @@ -167,11 +157,6 @@ void LoadTgtFromIR(ExprRules &exprs, TypeRules &types, if (!obj) continue; - if (auto target_os = obj->getString("target_os"); - target_os && !TargetOSMatchesHost(*target_os)) { - continue; - } - auto name = entry_name.str(); if (name[0] == 'f') { exprs[std::move(name)] = ParseExprRuleJSON(*obj); From 2694632d2031bce7909463709bbec4075eecf2de Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 23 May 2026 14:10:37 +0100 Subject: [PATCH 5/8] Add target_os=linux on IPPROTO_MPTCP --- rules/ip/tgt_unsafe.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rules/ip/tgt_unsafe.rs b/rules/ip/tgt_unsafe.rs index 766ed978..ff300a25 100644 --- a/rules/ip/tgt_unsafe.rs +++ b/rules/ip/tgt_unsafe.rs @@ -14,6 +14,7 @@ unsafe fn f4() -> i32 { libc::IPPROTO_IPV6 } +#[cfg(target_os = "linux")] unsafe fn f5() -> i32 { libc::IPPROTO_MPTCP } From 8d92dde34a611222b893e2902fc54ef6e444f03b Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 23 May 2026 14:11:31 +0100 Subject: [PATCH 6/8] Drop functions where target_os != current os --- rule-preprocessor/Cargo.toml | 2 +- rule-preprocessor/src/ir.rs | 2 - rule-preprocessor/src/syntactic.rs | 66 +++++++++++++++--------------- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/rule-preprocessor/Cargo.toml b/rule-preprocessor/Cargo.toml index 497c57ac..6247ab3b 100644 --- a/rule-preprocessor/Cargo.toml +++ b/rule-preprocessor/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] libcc2rs = { path = "../libcc2rs" } rules = { path = "../rules" } +cfg-expr = "0.20" ra_ap_syntax = "0.0.266" serde = { version = "1", features = ["derive"] } serde_json = "1" -syn = "2" diff --git a/rule-preprocessor/src/ir.rs b/rule-preprocessor/src/ir.rs index 8929bcb8..4697724d 100644 --- a/rule-preprocessor/src/ir.rs +++ b/rule-preprocessor/src/ir.rs @@ -57,8 +57,6 @@ pub struct FnIr { pub params: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub return_type: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub target_os: Option, } impl FnIr { diff --git a/rule-preprocessor/src/syntactic.rs b/rule-preprocessor/src/syntactic.rs index 3b3d6578..61a3de13 100644 --- a/rule-preprocessor/src/syntactic.rs +++ b/rule-preprocessor/src/syntactic.rs @@ -1,7 +1,9 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -use ra_ap_syntax::ast::{HasGenericParams, HasName, HasTypeBounds}; +use cfg_expr::Expression; +use cfg_expr::expr::{Predicate, TargetPredicate}; +use ra_ap_syntax::ast::{HasAttrs, HasGenericParams, HasName, HasTypeBounds}; use ra_ap_syntax::{AstNode, SyntaxKind, ast, match_ast}; use std::collections::{BTreeMap, HashMap}; use std::path::{Path, PathBuf}; @@ -38,6 +40,31 @@ fn pointer_flags(ty: &ast::Type) -> (bool, bool) { flags } +fn cfg_matches_host(fn_item: &ast::Fn) -> bool { + for attr in fn_item.attrs() { + let Some(meta) = attr.meta() else { continue }; + let Some(path) = meta.path() else { continue }; + if path.syntax().text() != "cfg" { + continue; + } + let meta_text = meta.syntax().text().to_string(); + let expr = Expression::parse(&meta_text) + .unwrap_or_else(|e| panic!("failed to parse `{meta_text}`: {e}")); + let matches = expr.eval(|pred| match pred { + Predicate::Target(TargetPredicate::Os(os)) => match os.as_str() { + "linux" => cfg!(target_os = "linux"), + "macos" => cfg!(target_os = "macos"), + other => panic!("unsupported target_os in cfg: {other}"), + }, + _ => panic!("unsupported cfg predicate in `{meta_text}`"), + }); + if !matches { + return false; + } + } + true +} + pub struct SyntacticAnalysis; impl SyntacticAnalysis { @@ -49,11 +76,9 @@ impl SyntacticAnalysis { let source = std::fs::read_to_string(rule_file).unwrap(); let file_ir = Self::parse_rule_file(&source, rule_file); - assert!( - !file_ir.is_empty(), - "Rule file {} produced no IR", - rule_file.display() - ); + if file_ir.is_empty() { + continue; + } let canonical = rule_file .canonicalize() @@ -103,6 +128,9 @@ impl SyntacticAnalysis { file_ir.insert(name, RuleIr::Type(ir)); } } else if fn_name.starts_with('f') { + if !cfg_matches_host(&fn_item) { + continue; + } file_ir.insert( fn_name.clone(), RuleIr::Fn(FnIrBuilder::new(&fn_item).build(path)), @@ -253,31 +281,6 @@ impl<'a> FnIrBuilder<'a> { Self { fn_item } } - fn get_target_os(&self) -> Option { - use ast::HasAttrs; - for attr in self.fn_item.attrs() { - let meta_text = attr.meta()?.syntax().text().to_string(); - let syn::Meta::List(list) = syn::parse_str(&meta_text).ok()? else { - continue; - }; - if !list.path.is_ident("cfg") { - continue; - } - let mut found = None; - let _ = list.parse_nested_meta(|nested| { - if nested.path.is_ident("target_os") { - let lit: syn::LitStr = nested.value()?.parse()?; - found = Some(lit.value()); - } - Ok(()) - }); - if found.is_some() { - return found; - } - } - None - } - fn params(&self) -> Vec { let mut params = Vec::new(); let Some(param_list) = self.fn_item.param_list() else { @@ -512,7 +515,6 @@ impl<'a> FnIrBuilder<'a> { }, multi_statement, body, - target_os: self.get_target_os(), }; ir.validate(&format!("{}:{}", path.display(), fn_name)); ir From 7cc5e58ef6fb36d31d173a831f95270fec022193 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 23 May 2026 14:18:26 +0100 Subject: [PATCH 7/8] Delete unportable macro --- tests/unit/ipproto_macros.cpp | 3 +-- tests/unit/out/refcount/ipproto_macros.rs | 4 +--- tests/unit/out/unsafe/ipproto_macros.rs | 3 +-- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/unit/ipproto_macros.cpp b/tests/unit/ipproto_macros.cpp index 8b049636..7aafbac6 100644 --- a/tests/unit/ipproto_macros.cpp +++ b/tests/unit/ipproto_macros.cpp @@ -5,6 +5,5 @@ int main() { int udp = IPPROTO_UDP; int ip = IPPROTO_IP; int ip6 = IPPROTO_IPV6; - int mptcp = IPPROTO_MPTCP; - return tcp + udp + ip + ip6 + mptcp; + return tcp + udp + ip + ip6; } diff --git a/tests/unit/out/refcount/ipproto_macros.rs b/tests/unit/out/refcount/ipproto_macros.rs index f5da640d..545dd95c 100644 --- a/tests/unit/out/refcount/ipproto_macros.rs +++ b/tests/unit/out/refcount/ipproto_macros.rs @@ -14,7 +14,5 @@ fn main_0() -> i32 { let udp: Value = Rc::new(RefCell::new(libc::IPPROTO_UDP)); let ip: Value = Rc::new(RefCell::new(libc::IPPROTO_IP)); let ip6: Value = Rc::new(RefCell::new(libc::IPPROTO_IPV6)); - let mptcp: Value = Rc::new(RefCell::new(libc::IPPROTO_MPTCP)); - return (((((*tcp.borrow()) + (*udp.borrow())) + (*ip.borrow())) + (*ip6.borrow())) - + (*mptcp.borrow())); + return ((((*tcp.borrow()) + (*udp.borrow())) + (*ip.borrow())) + (*ip6.borrow())); } diff --git a/tests/unit/out/unsafe/ipproto_macros.rs b/tests/unit/out/unsafe/ipproto_macros.rs index 3f9d4753..41e33f22 100644 --- a/tests/unit/out/unsafe/ipproto_macros.rs +++ b/tests/unit/out/unsafe/ipproto_macros.rs @@ -16,6 +16,5 @@ unsafe fn main_0() -> i32 { let mut udp: i32 = libc::IPPROTO_UDP; let mut ip: i32 = libc::IPPROTO_IP; let mut ip6: i32 = libc::IPPROTO_IPV6; - let mut mptcp: i32 = libc::IPPROTO_MPTCP; - return (((((tcp) + (udp)) + (ip)) + (ip6)) + (mptcp)); + return ((((tcp) + (udp)) + (ip)) + (ip6)); } From ec8bfee5b0eafb4bcf0b5f61de7edf2cfac49c49 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 23 May 2026 14:18:39 +0100 Subject: [PATCH 8/8] Create the file even if it's empty --- rule-preprocessor/src/syntactic.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rule-preprocessor/src/syntactic.rs b/rule-preprocessor/src/syntactic.rs index 61a3de13..855ffc05 100644 --- a/rule-preprocessor/src/syntactic.rs +++ b/rule-preprocessor/src/syntactic.rs @@ -76,10 +76,6 @@ impl SyntacticAnalysis { let source = std::fs::read_to_string(rule_file).unwrap(); let file_ir = Self::parse_rule_file(&source, rule_file); - if file_ir.is_empty() { - continue; - } - let canonical = rule_file .canonicalize() .unwrap_or_else(|_| rule_file.clone())