diff --git a/c2rust-ast-builder/src/builder.rs b/c2rust-ast-builder/src/builder.rs index 489194ebb0..80fe27608d 100644 --- a/c2rust-ast-builder/src/builder.rs +++ b/c2rust-ast-builder/src/builder.rs @@ -664,6 +664,17 @@ impl Builder { ))) } + /// A convenience function for calling multiple methods in a chain. + pub fn method_chain_expr( + self, + expr: Box, + calls: Vec<(PathSegment, Vec>)>, + ) -> Box { + calls.into_iter().fold(expr, |expr, (seg, args)| { + mk().method_call_expr(expr, seg, args) + }) + } + pub fn tuple_expr(self, exprs: Vec>) -> Box { Box::new(Expr::Tuple(ExprTuple { attrs: self.attrs, @@ -2088,17 +2099,11 @@ impl Builder { self, capture: CaptureBy, mov: Movability, - decl: FnDecl, + inputs: Vec, + output: ReturnType, body: Box, ) -> Box { - let (_name, inputs, _variadic, output) = decl; - let inputs = inputs - .into_iter() - .map(|e| match e { - FnArg::Receiver(_s) => panic!("found 'self' in closure arguments"), - FnArg::Typed(PatType { pat, .. }) => *pat, - }) - .collect(); + let inputs = inputs.into_iter().collect(); let capture = match capture { CaptureBy::Ref => None, CaptureBy::Value => Some(Default::default()), diff --git a/c2rust-ast-builder/src/lib.rs b/c2rust-ast-builder/src/lib.rs index d8a1376103..361b520488 100644 --- a/c2rust-ast-builder/src/lib.rs +++ b/c2rust-ast-builder/src/lib.rs @@ -1,2 +1,2 @@ mod builder; -pub use crate::builder::{mk, properties, Builder, Make}; +pub use crate::builder::{mk, properties, Builder, CaptureBy, Make}; diff --git a/c2rust-transpile/src/translator/main_function.rs b/c2rust-transpile/src/translator/main_function.rs index 20c6300f3e..5a47236fbc 100644 --- a/c2rust-transpile/src/translator/main_function.rs +++ b/c2rust-transpile/src/translator/main_function.rs @@ -4,6 +4,7 @@ //! Rust. use super::*; +use c2rust_ast_builder::CaptureBy; use failure::format_err; use proc_macro2::{TokenStream, TokenTree}; @@ -53,45 +54,97 @@ impl<'c> Translation<'c> { if n >= 2 { // `argv` and `argc` - stmts.push(mk().local_stmt(Box::new(mk().local( - mk().mutbl().ident_pat("args"), - Some(mk().path_ty(vec![mk().path_segment_with_args( + stmts.push(mk().local_stmt(Box::new({ + // ty = Vec> + let ty = mk().path_ty(vec![mk().path_segment_with_args( "Vec", - mk().angle_bracketed_args(vec![ - mk().mutbl().ptr_ty(mk().abs_path_ty(vec!["core", "ffi", "c_char"])), - ]), - )])), - Some(mk().call_expr(mk().path_expr(vec!["Vec", "new"]), vec![])), - )))); - stmts.push(mk().semi_stmt(mk().for_expr( - mk().ident_pat("arg"), - mk().call_expr(args_fn, vec![]), - mk().block(vec![mk().semi_stmt(mk().method_call_expr( - mk().path_expr(vec!["args"]), - "push", - vec![mk().method_call_expr( - mk().method_call_expr( - mk().call_expr( - // TODO(kkysen) change `"std"` to `"alloc"` after `#![feature(alloc_c_string)]` is stabilized in `1.63.0` - mk().abs_path_expr(vec!["std", "ffi", "CString", "new"]), - vec![mk().path_expr(vec!["arg"])], - ), - "expect", - vec![mk().lit_expr("Failed to convert argument into CString.")], - ), - "into_raw", + mk().angle_bracketed_args(vec![mk().path_ty(vec![mk() + .path_segment_with_args( + "Vec", + mk().angle_bracketed_args(vec![mk().ident_ty("u8")]), + )])]), + )]); + // map_arg = |arg| { + // (::std::ffi::CString::new(arg)) + // .expect("Failed to convert argument into CString.") + // .into_bytes_with_nul() + // } + let cstring_call = mk().call_expr( + // TODO(kkysen) change `"std"` to `"alloc"` after `#![feature(alloc_c_string)]` is stabilized in `1.63.0` + mk().abs_path_expr(vec!["std", "ffi", "CString", "new"]), + vec![mk().path_expr(vec!["arg"])], + ); + let expect_arg = mk().lit_expr("Failed to convert argument into CString."); + let map_arg = mk().closure_expr( + CaptureBy::Ref, + Movability::Movable, + vec![mk().ident_pat("arg")], + ReturnType::Default, + mk().method_chain_expr( + cstring_call, + vec![ + (mk().path_segment("expect"), vec![expect_arg]), + (mk().path_segment("into_bytes_with_nul"), vec![]), + ], + ), + ); + // init = args_fn + // .map(map_arg) + // .collect(); + let init = mk().method_chain_expr( + mk().call_expr(args_fn, vec![]), + vec![ + (mk().path_segment("map"), vec![map_arg]), + (mk().path_segment("collect"), vec![]), + ], + ); + mk().local(mk().mutbl().ident_pat("args_strings"), Some(ty), Some(init)) + }))); + + stmts.push(mk().local_stmt(Box::new({ + // ty = Vec<*mut ::core::ffi::c_char> + let ty = mk().path_ty(vec![mk().path_segment_with_args( + "Vec", + mk().angle_bracketed_args(vec![mk() + .mutbl() + .ptr_ty(mk().abs_path_ty(vec!["core", "ffi", "c_char"]))]), + )]); + // map_arg = |arg| arg.as_mut_ptr() as *mut ::core::ffi::c_char + let map_arg = mk().closure_expr( + CaptureBy::Ref, + Movability::Movable, + vec![mk().ident_pat("arg")], + ReturnType::Default, + mk().cast_expr( + mk().method_call_expr(mk().ident_expr("arg"), "as_mut_ptr", vec![]), + mk().mutbl() + .ptr_ty(mk().abs_path_ty(vec!["core", "ffi", "c_char"])), + ), + ); + // chain_arg = ::core::iter::once(::core::ptr::null_mut()) + let chain_arg = mk().call_expr( + mk().abs_path_expr(vec!["core", "iter", "once"]), + vec![mk().call_expr( + mk().abs_path_expr(vec!["core", "ptr", "null_mut"]), vec![], )], - ))]), - None::, - ))); - stmts.push(mk().semi_stmt(mk().method_call_expr( - mk().path_expr(vec!["args"]), - "push", - vec![ - mk().call_expr(mk().abs_path_expr(vec!["core", "ptr", "null_mut"]), vec![]), - ], - ))); + ); + // init = args_strings + // .iter_mut() + // .map(map_arg) + // .chain(chain_arg) + // .collect() + let init = mk().method_chain_expr( + mk().ident_expr("args_strings"), + vec![ + (mk().path_segment("iter_mut"), vec![]), + (mk().path_segment("map"), vec![map_arg]), + (mk().path_segment("chain"), vec![chain_arg]), + (mk().path_segment("collect"), vec![]), + ], + ); + mk().local(mk().mutbl().ident_pat("args_ptrs"), Some(ty), Some(init)) + }))); let argc_ty: Box = match self.ast_context.index(parameters[0]).kind { CDeclKind::Variable { ref typ, .. } => self.convert_type(typ.ctype), @@ -105,8 +158,7 @@ impl<'c> Translation<'c> { "Cannot find type of 'argv' argument in main function", )), }?; - - let args = mk().ident_expr("args"); + let args = mk().ident_expr("args_ptrs"); let argc = mk().binary_expr( BinOp::Sub(Default::default()), mk().method_call_expr(args.clone(), "len", no_args.clone()), diff --git a/c2rust-transpile/tests/snapshots/main.c b/c2rust-transpile/tests/snapshots/main.c new file mode 100644 index 0000000000..d3038e072e --- /dev/null +++ b/c2rust-transpile/tests/snapshots/main.c @@ -0,0 +1,3 @@ +int main(int argc, char **argv, char **envp) { + return 0; +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@main.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@main.c.snap new file mode 100644 index 0000000000..528de96c9c --- /dev/null +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@main.c.snap @@ -0,0 +1,51 @@ +--- +source: c2rust-transpile/tests/snapshots.rs +expression: cat tests/snapshots/main.rs +input_file: c2rust-transpile/tests/snapshots/main.c +--- +#![allow( + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_assignments, + unused_mut +)] +unsafe fn main_0( + mut argc: ::core::ffi::c_int, + mut argv: *mut *mut ::core::ffi::c_char, + mut envp: *mut *mut ::core::ffi::c_char, +) -> ::core::ffi::c_int { + return 0 as ::core::ffi::c_int; +} +pub fn main() { + let mut args_strings: Vec> = ::std::env::args() + .map(|arg| { + ::std::ffi::CString::new(arg) + .expect("Failed to convert argument into CString.") + .into_bytes_with_nul() + }) + .collect(); + let mut args_ptrs: Vec<*mut ::core::ffi::c_char> = args_strings + .iter_mut() + .map(|arg| arg.as_mut_ptr() as *mut ::core::ffi::c_char) + .chain(::core::iter::once(::core::ptr::null_mut())) + .collect(); + let mut vars: Vec<*mut ::core::ffi::c_char> = Vec::new(); + for (var_name, var_value) in ::std::env::vars() { + let var: String = format!("{}={}", var_name, var_value); + vars.push( + ::std::ffi::CString::new(var) + .expect("Failed to convert environment variable into CString.") + .into_raw(), + ); + } + vars.push(::core::ptr::null_mut()); + unsafe { + ::std::process::exit(main_0( + (args_ptrs.len() - 1) as ::core::ffi::c_int, + args_ptrs.as_mut_ptr() as *mut *mut ::core::ffi::c_char, + vars.as_mut_ptr() as *mut *mut ::core::ffi::c_char, + ) as i32) + } +}