diff --git a/cpp2rust/converter/translation_rule.cpp b/cpp2rust/converter/translation_rule.cpp index fa05ab7..3f24e59 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); diff --git a/rule-preprocessor/Cargo.toml b/rule-preprocessor/Cargo.toml index 497c57a..6247ab3 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 8929bcb..4697724 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 3b3d657..855ffc0 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,12 +76,6 @@ 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() - ); - let canonical = rule_file .canonicalize() .unwrap_or_else(|_| rule_file.clone()) @@ -103,6 +124,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 +277,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 +511,6 @@ impl<'a> FnIrBuilder<'a> { }, multi_statement, body, - target_os: self.get_target_os(), }; ir.validate(&format!("{}:{}", path.display(), fn_name)); ir diff --git a/rules/ip/src.cpp b/rules/ip/src.cpp index 200abfc..1fabb8b 100644 --- a/rules/ip/src.cpp +++ b/rules/ip/src.cpp @@ -11,3 +11,13 @@ int f2() { int f3() { return IPPROTO_IP; } + +int f4() { + return IPPROTO_IPV6; +} + +#if defined(__linux__) +int f5() { + return IPPROTO_MPTCP; +} +#endif diff --git a/rules/ip/tgt_unsafe.rs b/rules/ip/tgt_unsafe.rs index 7325fc0..ff300a2 100644 --- a/rules/ip/tgt_unsafe.rs +++ b/rules/ip/tgt_unsafe.rs @@ -9,3 +9,12 @@ unsafe fn f2() -> i32 { unsafe fn f3() -> i32 { libc::IPPROTO_IP } + +unsafe fn f4() -> i32 { + libc::IPPROTO_IPV6 +} + +#[cfg(target_os = "linux")] +unsafe fn f5() -> i32 { + libc::IPPROTO_MPTCP +} diff --git a/tests/unit/ipproto_macros.cpp b/tests/unit/ipproto_macros.cpp index 3951505..7aafbac 100644 --- a/tests/unit/ipproto_macros.cpp +++ b/tests/unit/ipproto_macros.cpp @@ -4,5 +4,6 @@ int main() { int tcp = IPPROTO_TCP; int udp = IPPROTO_UDP; int ip = IPPROTO_IP; - return tcp + udp + ip; + int ip6 = IPPROTO_IPV6; + return tcp + udp + ip + ip6; } diff --git a/tests/unit/out/refcount/ipproto_macros.rs b/tests/unit/out/refcount/ipproto_macros.rs index f901727..545dd95 100644 --- a/tests/unit/out/refcount/ipproto_macros.rs +++ b/tests/unit/out/refcount/ipproto_macros.rs @@ -13,5 +13,6 @@ 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)); + 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 4ff8e7f..41e33f2 100644 --- a/tests/unit/out/unsafe/ipproto_macros.rs +++ b/tests/unit/out/unsafe/ipproto_macros.rs @@ -15,5 +15,6 @@ 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; + return ((((tcp) + (udp)) + (ip)) + (ip6)); }