From d57941b639209b57914ac018e9f74c1bf8152a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gouveia?= Date: Mon, 1 Jun 2026 15:24:54 +0000 Subject: [PATCH 1/2] Make Rust type rules standalone functions --- rule-preprocessor/src/syntactic.rs | 60 +++++++++++++--------------- rules/array/tgt_unsafe.rs | 6 +-- rules/brotli/tgt_unsafe.rs | 24 ++++++++--- rules/carray/tgt_refcount.rs | 9 +++-- rules/carray/tgt_unsafe.rs | 9 +++-- rules/deque/tgt_unsafe.rs | 10 ++--- rules/fstream/tgt_unsafe.rs | 15 ++++--- rules/initializer_list/tgt_unsafe.rs | 6 +-- rules/iostream/tgt_refcount.rs | 9 +++-- rules/iostream/tgt_unsafe.rs | 14 +++++-- rules/map/tgt_refcount.rs | 18 +++++---- rules/map/tgt_unsafe.rs | 16 ++++---- rules/pair/tgt_refcount.rs | 12 ++---- rules/pair/tgt_unsafe.rs | 10 +---- rules/select/tgt_unsafe.rs | 4 +- rules/stdio/tgt_refcount.rs | 5 +-- rules/stdio/tgt_unsafe.rs | 5 +-- rules/string/tgt_refcount.rs | 4 +- rules/string/tgt_unsafe.rs | 9 +++-- rules/unique_ptr/tgt_refcount.rs | 13 +++--- rules/unique_ptr/tgt_unsafe.rs | 10 ++--- rules/vector/tgt_refcount.rs | 14 ++++--- rules/vector/tgt_unsafe.rs | 19 ++++++--- 23 files changed, 163 insertions(+), 138 deletions(-) diff --git a/rule-preprocessor/src/syntactic.rs b/rule-preprocessor/src/syntactic.rs index 191dac3c..6c74c6a6 100644 --- a/rule-preprocessor/src/syntactic.rs +++ b/rule-preprocessor/src/syntactic.rs @@ -124,10 +124,11 @@ impl SyntacticAnalysis { let Some(name) = fn_item.name() else { continue }; let fn_name = name.text().to_string(); - if fn_name == "types" { - for (name, ir) in TypeIrBuilder::new(&fn_item).build() { - file_ir.insert(name, RuleIr::Type(ir)); - } + if fn_name.starts_with('t') { + file_ir.insert( + fn_name.clone(), + RuleIr::Type(TypeIrBuilder::new(&fn_item).build()), + ); } else if fn_name.starts_with('f') { if !cfg_matches_host(&fn_item) { continue; @@ -531,35 +532,30 @@ impl<'a> TypeIrBuilder<'a> { Self { fn_item } } - fn build(&self) -> Vec<(String, TypeIr)> { - let Some(body) = self.fn_item.body() else { - return Vec::new(); - }; - let mut results = Vec::new(); - for stmt in body.syntax().descendants().filter_map(ast::LetStmt::cast) { - let Some(pat) = stmt.pat() else { continue }; - let pat_text = pat.syntax().text().to_string(); - if !pat_text.starts_with('t') { - continue; - } - let Some(ty) = stmt.ty() else { continue }; - let Some(init) = stmt.initializer() else { - continue; - }; + fn build(&self) -> TypeIr { + let ty = self + .fn_item + .ret_type() + .and_then(|rt| rt.ty()) + .expect("type rule must declare a return type"); + let (is_refcount_pointer, is_unsafe_pointer) = pointer_flags(&ty); - let (is_refcount_pointer, is_unsafe_pointer) = pointer_flags(&ty); - results.push(( - pat_text, - TypeIr { - init: init.syntax().text().to_string(), - type_info: TypeInfo { - ty: ty.syntax().text().to_string(), - is_refcount_pointer, - is_unsafe_pointer, - }, - }, - )); + let body = self.fn_item.body().expect("type rule must have a body"); + let init = body + .syntax() + .descendants() + .find_map(ast::ReturnExpr::cast) + .and_then(|ret| ret.expr()) + .or_else(|| body.stmt_list().and_then(|sl| sl.tail_expr())) + .expect("type rule must yield an initializer"); + + TypeIr { + init: init.syntax().text().to_string(), + type_info: TypeInfo { + ty: ty.syntax().text().to_string(), + is_refcount_pointer, + is_unsafe_pointer, + }, } - results } } diff --git a/rules/array/tgt_unsafe.rs b/rules/array/tgt_unsafe.rs index dafcc2cd..ba80ebe1 100644 --- a/rules/array/tgt_unsafe.rs +++ b/rules/array/tgt_unsafe.rs @@ -3,10 +3,8 @@ use libcc2rs::*; -struct T1; - -fn types() { - let t1: Vec = Default::default(); +fn t1() -> Vec { + Default::default() } unsafe fn f1(a0: Vec) -> *const T1 { diff --git a/rules/brotli/tgt_unsafe.rs b/rules/brotli/tgt_unsafe.rs index dddd3372..add87b72 100644 --- a/rules/brotli/tgt_unsafe.rs +++ b/rules/brotli/tgt_unsafe.rs @@ -1,12 +1,24 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -fn types() { - let t1: ::brotli_sys::BrotliDecoderResult = ::brotli_sys::BROTLI_DECODER_RESULT_ERROR; - let t2: ::brotli_sys::BrotliEncoderMode = ::brotli_sys::BROTLI_MODE_GENERIC; - let t3: *mut ::brotli_sys::BrotliDecoderState = std::ptr::null_mut(); - let t4: *const ::brotli_sys::BrotliDecoderState = std::ptr::null(); - let t5: ::brotli_sys::BrotliDecoderErrorCode = ::brotli_sys::BROTLI_DECODER_NO_ERROR; +fn t1() -> ::brotli_sys::BrotliDecoderResult { + ::brotli_sys::BROTLI_DECODER_RESULT_ERROR +} + +fn t2() -> ::brotli_sys::BrotliEncoderMode { + ::brotli_sys::BROTLI_MODE_GENERIC +} + +fn t3() -> *mut ::brotli_sys::BrotliDecoderState { + std::ptr::null_mut() +} + +fn t4() -> *const ::brotli_sys::BrotliDecoderState { + std::ptr::null() +} + +fn t5() -> ::brotli_sys::BrotliDecoderErrorCode { + ::brotli_sys::BROTLI_DECODER_NO_ERROR } unsafe fn f1() -> ::brotli_sys::BrotliEncoderMode { diff --git a/rules/carray/tgt_refcount.rs b/rules/carray/tgt_refcount.rs index 67f78e2b..327770fa 100644 --- a/rules/carray/tgt_refcount.rs +++ b/rules/carray/tgt_refcount.rs @@ -3,9 +3,10 @@ use libcc2rs::*; -struct T1; +fn t1() -> Box<[Value>]> { + Box::new([Default::default()]) +} -fn types() { - let t1: Box<[Value>]> = Box::new([Default::default()]); - let t2: Box<[Value>]>>]> = Box::new([Default::default()]); +fn t2() -> Box<[Value>]>>]> { + Box::new([Default::default()]) } diff --git a/rules/carray/tgt_unsafe.rs b/rules/carray/tgt_unsafe.rs index 44e778d4..08aebe35 100644 --- a/rules/carray/tgt_unsafe.rs +++ b/rules/carray/tgt_unsafe.rs @@ -1,7 +1,10 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -fn types() { - let t1: libcc2rs::IgnoreRule = libcc2rs::IgnoreRule; - let t2: libcc2rs::IgnoreRule = libcc2rs::IgnoreRule; +fn t1() -> libcc2rs::IgnoreRule { + libcc2rs::IgnoreRule +} + +fn t2() -> libcc2rs::IgnoreRule { + libcc2rs::IgnoreRule } diff --git a/rules/deque/tgt_unsafe.rs b/rules/deque/tgt_unsafe.rs index 60b59e09..8382d48f 100644 --- a/rules/deque/tgt_unsafe.rs +++ b/rules/deque/tgt_unsafe.rs @@ -3,12 +3,10 @@ use libcc2rs::*; -struct T1; - -fn types() { - // TODO: it should be VecDeque, but we don't have the neccessary infrastructure in Ptr<> to - // make this work. - let t1: Vec = Default::default(); +// TODO: it should be VecDeque, but we don't have the neccessary infrastructure in Ptr<> to +// make this work. +fn t1() -> Vec { + Default::default() } unsafe fn f1(a0: &mut Vec) -> *const T1 { diff --git a/rules/fstream/tgt_unsafe.rs b/rules/fstream/tgt_unsafe.rs index cc12d437..ce16e030 100644 --- a/rules/fstream/tgt_unsafe.rs +++ b/rules/fstream/tgt_unsafe.rs @@ -1,11 +1,16 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -fn types() -> Result<(), Box> { - let t1: ::std::fs::File = ::std::fs::File::open("")?; - let t2: ::std::fs::File = ::std::fs::File::open("")?; - let t3: ::std::fs::File = ::std::fs::File::open("")?; - Ok(()) +fn t1() -> ::std::fs::File { + ::std::fs::File::open("").unwrap() +} + +fn t2() -> ::std::fs::File { + ::std::fs::File::open("").unwrap() +} + +fn t3() -> ::std::fs::File { + ::std::fs::File::open("").unwrap() } unsafe fn f1(a0: *const u8) -> ::std::fs::File { diff --git a/rules/initializer_list/tgt_unsafe.rs b/rules/initializer_list/tgt_unsafe.rs index b4d2dd13..ba8a9acc 100644 --- a/rules/initializer_list/tgt_unsafe.rs +++ b/rules/initializer_list/tgt_unsafe.rs @@ -3,10 +3,8 @@ use libcc2rs::*; -struct T1; - -fn types() { - let t1: Vec = Default::default(); +fn t1() -> Vec { + Default::default() } unsafe fn f1(a0: Vec) -> u64 { diff --git a/rules/iostream/tgt_refcount.rs b/rules/iostream/tgt_refcount.rs index 1468c87a..ff39d46a 100644 --- a/rules/iostream/tgt_refcount.rs +++ b/rules/iostream/tgt_refcount.rs @@ -5,9 +5,12 @@ use libcc2rs::*; use std::os::fd::AsFd; // TODO: t2 and t3 should be translated to Ptr -fn types() { - let t2: Ptr = Ptr::null(); - let t3: Ptr = Ptr::null(); +fn t2() -> Ptr { + Ptr::null() +} + +fn t3() -> Ptr { + Ptr::null() } fn f1() -> ::std::fs::File { diff --git a/rules/iostream/tgt_unsafe.rs b/rules/iostream/tgt_unsafe.rs index 15c39a29..b0c5d2b9 100644 --- a/rules/iostream/tgt_unsafe.rs +++ b/rules/iostream/tgt_unsafe.rs @@ -4,11 +4,17 @@ use libcc2rs::*; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +fn t1() -> std::fs::File { + std::fs::File::open("").unwrap() +} + // TODO: t2 and t3 should be translated to *mut dyn Traits -unsafe fn types() { - let t1: std::fs::File = std::fs::File::open("").unwrap(); - let t2: *mut std::fs::File = libcc2rs::cout_unsafe(); - let t3: *mut std::fs::File = libcc2rs::cout_unsafe(); +unsafe fn t2() -> *mut std::fs::File { + libcc2rs::cout_unsafe() +} + +unsafe fn t3() -> *mut std::fs::File { + libcc2rs::cout_unsafe() } unsafe fn f1() -> ::std::fs::File { diff --git a/rules/map/tgt_refcount.rs b/rules/map/tgt_refcount.rs index ad950c5c..2a6b7361 100644 --- a/rules/map/tgt_refcount.rs +++ b/rules/map/tgt_refcount.rs @@ -6,14 +6,16 @@ use std::cell::RefCell; use std::collections::BTreeMap; use std::rc::Rc; -#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] -struct T1; -struct T2; - -fn types() { - let t1: BTreeMap> = BTreeMap::new(); - let t2: RefcountMapIter = RefcountMapIter::null(); - let t3: RefcountMapIter = RefcountMapIter::null(); +fn t1() -> BTreeMap> { + BTreeMap::new() +} + +fn t2() -> RefcountMapIter { + RefcountMapIter::null() +} + +fn t3() -> RefcountMapIter { + RefcountMapIter::null() } fn f1( diff --git a/rules/map/tgt_unsafe.rs b/rules/map/tgt_unsafe.rs index 6fd8733a..c96ec26d 100644 --- a/rules/map/tgt_unsafe.rs +++ b/rules/map/tgt_unsafe.rs @@ -4,14 +4,16 @@ use libcc2rs::{MapIterator, UnsafeMapIterator}; use std::collections::BTreeMap; -#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] -struct T1; -struct T2; +fn t1() -> BTreeMap> { + BTreeMap::new() +} + +fn t2() -> UnsafeMapIterator { + UnsafeMapIterator::null() +} -fn types() { - let t1: BTreeMap> = BTreeMap::new(); - let t2: UnsafeMapIterator = UnsafeMapIterator::null(); - let t3: UnsafeMapIterator = UnsafeMapIterator::null(); +fn t3() -> UnsafeMapIterator { + UnsafeMapIterator::null() } unsafe fn f1(a0: &mut BTreeMap>, a1: T1) -> &mut T2 { diff --git a/rules/pair/tgt_refcount.rs b/rules/pair/tgt_refcount.rs index 3578346b..d8a49175 100644 --- a/rules/pair/tgt_refcount.rs +++ b/rules/pair/tgt_refcount.rs @@ -5,17 +5,11 @@ use libcc2rs::*; use std::cell::RefCell; use std::rc::Rc; -#[derive(Default)] -struct T1; - -#[derive(Default)] -struct T2; - -fn types() { - let t1: (Value, Value) = ( +fn t1() -> (Value, Value) { + ( Rc::new(RefCell::new(T1::default())), Rc::new(RefCell::new(T2::default())), - ); + ) } fn f1(a0: (Value, Value)) -> Value { diff --git a/rules/pair/tgt_unsafe.rs b/rules/pair/tgt_unsafe.rs index cae891fa..c00a09c9 100644 --- a/rules/pair/tgt_unsafe.rs +++ b/rules/pair/tgt_unsafe.rs @@ -1,14 +1,8 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -#[derive(Default)] -struct T1; - -#[derive(Default)] -struct T2; - -fn types() { - let t1: (T1, T2) = <(T1, T2)>::default(); +fn t1() -> (T1, T2) { + <(T1, T2)>::default() } unsafe fn f1(a0: (T1, T2)) -> T2 { diff --git a/rules/select/tgt_unsafe.rs b/rules/select/tgt_unsafe.rs index 9588a09d..2b6feaf2 100644 --- a/rules/select/tgt_unsafe.rs +++ b/rules/select/tgt_unsafe.rs @@ -1,8 +1,8 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -unsafe fn types() { - let t1: ::libc::fd_set = std::mem::zeroed::<::libc::fd_set>(); +unsafe fn t1() -> ::libc::fd_set { + std::mem::zeroed::<::libc::fd_set>() } unsafe fn f1( diff --git a/rules/stdio/tgt_refcount.rs b/rules/stdio/tgt_refcount.rs index 1acc3e53..b78f49cb 100644 --- a/rules/stdio/tgt_refcount.rs +++ b/rules/stdio/tgt_refcount.rs @@ -5,9 +5,8 @@ use libcc2rs::*; use std::io::prelude::*; use std::os::fd::AsFd; -fn types() -> Result<(), Box> { - let t1: Ptr<::std::fs::File> = Ptr::null(); - Ok(()) +fn t1() -> Ptr<::std::fs::File> { + Ptr::null() } fn f1(a0: Ptr, a1: Ptr) -> Ptr<::std::fs::File> { diff --git a/rules/stdio/tgt_unsafe.rs b/rules/stdio/tgt_unsafe.rs index ce96445f..91216fef 100644 --- a/rules/stdio/tgt_unsafe.rs +++ b/rules/stdio/tgt_unsafe.rs @@ -1,9 +1,8 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -fn types() -> Result<(), Box> { - let t1: *mut ::libc::FILE = std::ptr::null_mut(); - Ok(()) +fn t1() -> *mut ::libc::FILE { + std::ptr::null_mut() } unsafe fn f1(a0: *const u8, a1: *const u8) -> *mut ::libc::FILE { diff --git a/rules/string/tgt_refcount.rs b/rules/string/tgt_refcount.rs index b455d179..9faa100f 100644 --- a/rules/string/tgt_refcount.rs +++ b/rules/string/tgt_refcount.rs @@ -5,8 +5,8 @@ use libcc2rs::*; use std::cell::RefCell; use std::rc::Rc; -fn types() { - let t2: Ptr = Ptr::null(); +fn t2() -> Ptr { + Ptr::null() } fn f1(a0: Vec, a1: usize, a2: usize) -> Vec { diff --git a/rules/string/tgt_unsafe.rs b/rules/string/tgt_unsafe.rs index 3e3376a2..064ff08e 100644 --- a/rules/string/tgt_unsafe.rs +++ b/rules/string/tgt_unsafe.rs @@ -1,9 +1,12 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -fn types() { - let t1: Vec = Vec::new(); - let t2: *mut u8 = ::std::ptr::null_mut(); +fn t1() -> Vec { + Vec::new() +} + +fn t2() -> *mut u8 { + ::std::ptr::null_mut() } unsafe fn f1(a0: Vec, a1: usize, a2: usize) -> Vec { diff --git a/rules/unique_ptr/tgt_refcount.rs b/rules/unique_ptr/tgt_refcount.rs index f8d05a11..f0062cef 100644 --- a/rules/unique_ptr/tgt_refcount.rs +++ b/rules/unique_ptr/tgt_refcount.rs @@ -5,11 +5,12 @@ use libcc2rs::*; use std::cell::RefCell; use std::rc::Rc; -struct T1; +fn t1() -> Option> { + None +} -fn types() { - let t1: Option> = None; - let t2: Option>> = None; +fn t2() -> Option>> { + None } fn f1(a0: usize) -> Option>> { @@ -51,10 +52,10 @@ fn f9(a0: &mut Option>>) { *a0 = None } -fn f10() -> Option> { +fn f10() -> Option> { None } -fn f11() -> Option>> { +fn f11() -> Option>> { None } diff --git a/rules/unique_ptr/tgt_unsafe.rs b/rules/unique_ptr/tgt_unsafe.rs index 091166a0..ca144a86 100644 --- a/rules/unique_ptr/tgt_unsafe.rs +++ b/rules/unique_ptr/tgt_unsafe.rs @@ -1,12 +1,12 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -#[derive(Default)] -struct T1; +fn t1() -> Option> { + None +} -fn types() { - let t1: Option> = None; - let t2: Option> = None; +fn t2() -> Option> { + None } unsafe fn f1(a0: usize) -> Option> { diff --git a/rules/vector/tgt_refcount.rs b/rules/vector/tgt_refcount.rs index 8563aafd..aa3f43e3 100644 --- a/rules/vector/tgt_refcount.rs +++ b/rules/vector/tgt_refcount.rs @@ -5,12 +5,16 @@ use libcc2rs::*; use std::cell::RefCell; use std::rc::Rc; -struct T1; +fn t2() -> Ptr { + Ptr::null() +} + +fn t3() -> Vec>> { + Vec::new() +} -fn types() { - let t2: Ptr = Ptr::null(); - let t3: Vec>> = Vec::new(); - let t4: Ptr = Ptr::null(); +fn t4() -> Ptr { + Ptr::null() } fn f1(a0: Ptr>, a1: Ptr) -> Ptr { diff --git a/rules/vector/tgt_unsafe.rs b/rules/vector/tgt_unsafe.rs index 43e3161a..58436271 100644 --- a/rules/vector/tgt_unsafe.rs +++ b/rules/vector/tgt_unsafe.rs @@ -3,13 +3,20 @@ use libcc2rs::*; -struct T1; +fn t1() -> Vec { + Default::default() +} + +fn t2() -> *mut T1 { + Default::default() +} + +fn t3() -> Vec> { + Vec::new() +} -fn types() { - let t1: Vec = Default::default(); - let t2: *mut T1 = Default::default(); - let t3: Vec> = Vec::new(); - let t4: *const T1 = Default::default(); +fn t4() -> *const T1 { + Default::default() } unsafe fn f1(a0: &mut Vec, a1: *const T1) -> *const T1 { From 1a223c7b86ef144670cc2278ecc31150b39a6aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gouveia?= Date: Tue, 2 Jun 2026 16:22:54 +0100 Subject: [PATCH 2/2] Address reviews --- rule-preprocessor/src/syntactic.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/rule-preprocessor/src/syntactic.rs b/rule-preprocessor/src/syntactic.rs index 6c74c6a6..3e448636 100644 --- a/rule-preprocessor/src/syntactic.rs +++ b/rule-preprocessor/src/syntactic.rs @@ -537,17 +537,22 @@ impl<'a> TypeIrBuilder<'a> { .fn_item .ret_type() .and_then(|rt| rt.ty()) - .expect("type rule must declare a return type"); + .expect("Type rules must declare a return type"); let (is_refcount_pointer, is_unsafe_pointer) = pointer_flags(&ty); - let body = self.fn_item.body().expect("type rule must have a body"); - let init = body - .syntax() - .descendants() - .find_map(ast::ReturnExpr::cast) - .and_then(|ret| ret.expr()) - .or_else(|| body.stmt_list().and_then(|sl| sl.tail_expr())) - .expect("type rule must yield an initializer"); + let stmts = self + .fn_item + .body() + .and_then(|bd| bd.stmt_list()) + .expect("Types rule must have a body"); + assert!( + stmts.statements().count() == 0, + "Type rules mustn't contain anything in the body besides the tail expression" + ); + + let init = stmts + .tail_expr() + .expect("Type rules must yield an initializer"); TypeIr { init: init.syntax().text().to_string(),