diff --git a/c2rust-transpile/src/convert_type.rs b/c2rust-transpile/src/convert_type.rs index 3a176d9b56..2c04237c45 100644 --- a/c2rust-transpile/src/convert_type.rs +++ b/c2rust-transpile/src/convert_type.rs @@ -21,6 +21,7 @@ pub struct TypeConverter { suffix_names: HashMap<(CDeclId, &'static str), String>, features: HashSet<&'static str>, emit_no_std: bool, + ctypes_prefix: String, } pub const RESERVED_NAMES: [&str; 103] = [ @@ -133,7 +134,7 @@ pub const RESERVED_NAMES: [&str; 103] = [ ]; impl TypeConverter { - pub fn new(emit_no_std: bool) -> TypeConverter { + pub fn new(emit_no_std: bool, ctypes_prefix: String) -> TypeConverter { TypeConverter { translate_valist: false, renamer: Renamer::new(&RESERVED_NAMES), @@ -141,6 +142,7 @@ impl TypeConverter { suffix_names: HashMap::new(), features: HashSet::new(), emit_no_std, + ctypes_prefix, } } @@ -275,7 +277,7 @@ impl TypeConverter { CTypeKind::Void => { Ok(mk() .set_mutbl(mutbl) - .ptr_ty(mk().path_ty(vec!["libc", "c_void"]))) + .ptr_ty(mk().path_ty(vec!["core", "ffi", "c_void"]))) } CTypeKind::VariableArray(mut elt, _len) => { @@ -301,6 +303,41 @@ impl TypeConverter { } } + /// Convert a primitive C type kind into the equivalent Rust type + pub fn convert_primitive_type_kind(&self, kind: &CTypeKind) -> Option> { + let primitive_type = |ty: &str| { + let path = self + .ctypes_prefix + .split("::") + .chain(std::iter::once(ty)) + .collect::>(); + mk().path_ty(mk().path(path)) + }; + + match kind { + CTypeKind::Void => Some(mk().tuple_ty(vec![] as Vec>)), + CTypeKind::Bool => Some(mk().path_ty(mk().path(vec!["bool"]))), + CTypeKind::Short => Some(primitive_type("c_short")), + CTypeKind::Int => Some(primitive_type("c_int")), + CTypeKind::Long => Some(primitive_type("c_long")), + CTypeKind::LongLong => Some(primitive_type("c_longlong")), + CTypeKind::UShort => Some(primitive_type("c_ushort")), + CTypeKind::UInt => Some(primitive_type("c_uint")), + CTypeKind::ULong => Some(primitive_type("c_ulong")), + CTypeKind::ULongLong => Some(primitive_type("c_ulonglong")), + CTypeKind::SChar => Some(primitive_type("c_schar")), + CTypeKind::UChar => Some(primitive_type("c_uchar")), + CTypeKind::Char => Some(primitive_type("c_char")), + CTypeKind::Float => Some(primitive_type("c_float")), + CTypeKind::Double => Some(primitive_type("c_double")), + CTypeKind::LongDouble => Some(mk().path_ty(mk().path(vec!["f128", "f128"]))), + CTypeKind::Int128 => Some(mk().path_ty(mk().path(vec!["i128"]))), + CTypeKind::UInt128 => Some(mk().path_ty(mk().path(vec!["u128"]))), + + _ => None + } + } + /// Convert a `C` type to a `Rust` one. For the moment, these are expected to have compatible /// memory layouts. pub fn convert( @@ -315,26 +352,12 @@ impl TypeConverter { return Ok(ty); } - match ctxt.index(ctype).kind { - CTypeKind::Void => Ok(mk().tuple_ty(vec![] as Vec>)), - CTypeKind::Bool => Ok(mk().path_ty(mk().path(vec!["bool"]))), - CTypeKind::Short => Ok(mk().path_ty(mk().path(vec!["libc", "c_short"]))), - CTypeKind::Int => Ok(mk().path_ty(mk().path(vec!["libc", "c_int"]))), - CTypeKind::Long => Ok(mk().path_ty(mk().path(vec!["libc", "c_long"]))), - CTypeKind::LongLong => Ok(mk().path_ty(mk().path(vec!["libc", "c_longlong"]))), - CTypeKind::UShort => Ok(mk().path_ty(mk().path(vec!["libc", "c_ushort"]))), - CTypeKind::UInt => Ok(mk().path_ty(mk().path(vec!["libc", "c_uint"]))), - CTypeKind::ULong => Ok(mk().path_ty(mk().path(vec!["libc", "c_ulong"]))), - CTypeKind::ULongLong => Ok(mk().path_ty(mk().path(vec!["libc", "c_ulonglong"]))), - CTypeKind::SChar => Ok(mk().path_ty(mk().path(vec!["libc", "c_schar"]))), - CTypeKind::UChar => Ok(mk().path_ty(mk().path(vec!["libc", "c_uchar"]))), - CTypeKind::Char => Ok(mk().path_ty(mk().path(vec!["libc", "c_char"]))), - CTypeKind::Double => Ok(mk().path_ty(mk().path(vec!["libc", "c_double"]))), - CTypeKind::LongDouble => Ok(mk().path_ty(mk().path(vec!["f128", "f128"]))), - CTypeKind::Float => Ok(mk().path_ty(mk().path(vec!["libc", "c_float"]))), - CTypeKind::Int128 => Ok(mk().path_ty(mk().path(vec!["i128"]))), - CTypeKind::UInt128 => Ok(mk().path_ty(mk().path(vec!["u128"]))), + let kind = &ctxt.index(ctype).kind; + if let Some(ty) = self.convert_primitive_type_kind(kind) { + return Ok(ty); + } + match *kind { CTypeKind::Pointer(qtype) => self.convert_pointer(ctxt, qtype), CTypeKind::Elaborated(ref ctype) => self.convert(ctxt, *ctype), diff --git a/c2rust-transpile/src/lib.rs b/c2rust-transpile/src/lib.rs index 1872b6f4be..2d85c4fa05 100644 --- a/c2rust-transpile/src/lib.rs +++ b/c2rust-transpile/src/lib.rs @@ -105,6 +105,7 @@ pub struct TranspilerConfig { pub reorganize_definitions: bool, pub enabled_warnings: HashSet, pub emit_no_std: bool, + pub ctypes_prefix: String, pub output_dir: Option, pub translate_const_macros: bool, pub translate_fn_macros: bool, diff --git a/c2rust-transpile/src/translator/builtins.rs b/c2rust-transpile/src/translator/builtins.rs index eb92595dca..583894f6fe 100644 --- a/c2rust-transpile/src/translator/builtins.rs +++ b/c2rust-transpile/src/translator/builtins.rs @@ -93,7 +93,7 @@ impl<'c> Translation<'c> { Ok(val.map(|v| { let val = mk().method_call_expr(v, "is_sign_negative", vec![] as Vec>); - mk().cast_expr(val, mk().path_ty(vec!["libc", "c_int"])) + mk().cast_expr(val, self.convert_primitive_type_kind(&CTypeKind::Int)) })) }, "__builtin_ffs" | "__builtin_ffsl" | "__builtin_ffsll" => { @@ -246,6 +246,8 @@ impl<'c> Translation<'c> { "__builtin_constant_p" => Ok(WithStmts::new_val(mk().lit_expr(mk().int_lit(0, "")))), "__builtin_object_size" => { + self.use_crate(ExternCrate::Libc); + // We can't convert this to Rust, but it should be safe to always return -1/0 // (depending on the value of `type`), so we emit the following: // `(if (type & 2) == 0 { -1isize } else { 0isize }) as libc::size_t` @@ -670,6 +672,8 @@ impl<'c> Translation<'c> { ctx: ExprContext, args: &[CExprId], ) -> Result>, TranslationError> { + self.use_crate(ExternCrate::Libc); + let name = &builtin_name[10..]; let mem = mk().path_expr(vec!["libc", name]); let args = self.convert_exprs(ctx.used(), args)?; diff --git a/c2rust-transpile/src/translator/main_function.rs b/c2rust-transpile/src/translator/main_function.rs index 3fc9aa13c6..0daf9c26c1 100644 --- a/c2rust-transpile/src/translator/main_function.rs +++ b/c2rust-transpile/src/translator/main_function.rs @@ -53,7 +53,7 @@ impl<'c> Translation<'c> { Some(mk().path_ty(vec![mk().path_segment_with_args( "Vec", mk().angle_bracketed_args(vec![ - mk().mutbl().ptr_ty(mk().path_ty(vec!["libc", "c_char"])), + mk().mutbl().ptr_ty(self.convert_primitive_type_kind(&CTypeKind::Char)), ]), )])), Some( @@ -125,7 +125,7 @@ impl<'c> Translation<'c> { Some(mk().path_ty(vec![mk().path_segment_with_args( "Vec", mk().angle_bracketed_args(vec![ - mk().mutbl().ptr_ty(mk().path_ty(vec!["libc", "c_char"])), + mk().mutbl().ptr_ty(self.convert_primitive_type_kind(&CTypeKind::Char)), ]), )])), Some( diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 38f7b41122..921562e217 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -520,7 +520,9 @@ pub fn translate( // `with_globals` sets up a thread-local variable required by the syntax crate. with_globals(Edition::Edition2018, || { - t.use_crate(ExternCrate::Libc); + if t.tcfg.ctypes_prefix == "libc" { + t.use_crate(ExternCrate::Libc); + } // Sort the top-level declarations by file and source location so that we // preserve the ordering of all declarations in each file. @@ -1033,11 +1035,6 @@ fn print_header(s: &mut pprust::State, t: &Translation, is_binary: bool) { } } -/// Convert a boolean expression to a c_int -fn bool_to_int(val: P) -> P { - mk().cast_expr(val, mk().path_ty(vec!["libc", "c_int"])) -} - /// Add a src_loc = "line:col" attribute to an item/foreign_item fn add_src_loc_attr(attrs: &mut Vec, src_loc: &Option) { if let Some(src_loc) = src_loc.as_ref() { @@ -1092,7 +1089,7 @@ impl<'c> Translation<'c> { main_file: &path::Path, ) -> Self { let comment_context = CommentContext::new(&mut ast_context); - let mut type_converter = TypeConverter::new(tcfg.emit_no_std); + let mut type_converter = TypeConverter::new(tcfg.emit_no_std, tcfg.ctypes_prefix.clone()); if tcfg.translate_valist { type_converter.translate_valist = true @@ -2786,6 +2783,21 @@ impl<'c> Translation<'c> { .convert(&self.ast_context, type_id) } + fn convert_primitive_type_kind(&self, kind: &CTypeKind) -> P { + if self.tcfg.ctypes_prefix == "libc" { + self.use_crate(ExternCrate::Libc); + } + self.type_converter + .borrow() + .convert_primitive_type_kind(kind) + .unwrap() + } + + /// Convert a boolean expression to a c_int + fn convert_bool_to_int(&self, val: P) -> P { + mk().cast_expr(val, self.convert_primitive_type_kind(&CTypeKind::Int)) + } + /// Construct an expression for a NULL at any type, including forward declarations, /// function pointers, and normal pointers. fn null_ptr(&self, type_id: CTypeId, is_static: bool) -> Result, TranslationError> { @@ -3118,7 +3130,7 @@ impl<'c> Translation<'c> { UnTypeOp::PreferredAlignOf => self.compute_align_of_type(arg_ty.ctype, true)?, }; - Ok(result.map(|x| mk().cast_expr(x, mk().path_ty(vec!["libc", "c_ulong"])))) + Ok(result.map(|x| mk().cast_expr(x, self.convert_primitive_type_kind(&CTypeKind::ULong)))) } CExprKind::ConstantExpr(_ty, child, value) => { @@ -4033,10 +4045,10 @@ impl<'c> Translation<'c> { } let target_ty = self.convert_type(ty.ctype)?; val.and_then(|x| { - let intptr_t = mk().path_ty(vec!["libc", "intptr_t"]); - let intptr = mk().cast_expr(x, intptr_t.clone()); + let usize_ty = mk().ident_ty("usize"); + let intptr = mk().cast_expr(x, usize_ty.clone()); Ok(WithStmts::new_unsafe_val( - transmute_expr(intptr_t, target_ty, intptr, self.tcfg.emit_no_std) + transmute_expr(usize_ty, target_ty, intptr, self.tcfg.emit_no_std) )) }) } diff --git a/c2rust-transpile/src/translator/operators.rs b/c2rust-transpile/src/translator/operators.rs index 4c840c3502..f9ff4cd671 100644 --- a/c2rust-transpile/src/translator/operators.rs +++ b/c2rust-transpile/src/translator/operators.rs @@ -68,7 +68,7 @@ impl<'c> Translation<'c> { let lhs = self.convert_condition(ctx, true, lhs)?; let rhs = self.convert_condition(ctx, true, rhs)?; lhs - .map(|x| bool_to_int(mk().binary_expr(BinOpKind::from(op), x, rhs.to_expr()))) + .map(|x| self.convert_bool_to_int(mk().binary_expr(BinOpKind::from(op), x, rhs.to_expr()))) .and_then(|out| { if ctx.is_unused() { Ok(WithStmts::new( @@ -655,7 +655,7 @@ impl<'c> Translation<'c> { mk().binary_expr(BinOpKind::Eq, lhs, rhs) }; - Ok(bool_to_int(expr)) + Ok(self.convert_bool_to_int(expr)) } c_ast::BinOp::NotEqual => { // Using is_some method for null comparison means we don't have to @@ -677,12 +677,12 @@ impl<'c> Translation<'c> { mk().binary_expr(BinOpKind::Ne, lhs, rhs) }; - Ok(bool_to_int(expr)) + Ok(self.convert_bool_to_int(expr)) } - c_ast::BinOp::Less => Ok(bool_to_int(mk().binary_expr(BinOpKind::Lt, lhs, rhs))), - c_ast::BinOp::Greater => Ok(bool_to_int(mk().binary_expr(BinOpKind::Gt, lhs, rhs))), - c_ast::BinOp::GreaterEqual => Ok(bool_to_int(mk().binary_expr(BinOpKind::Ge, lhs, rhs))), - c_ast::BinOp::LessEqual => Ok(bool_to_int(mk().binary_expr(BinOpKind::Le, lhs, rhs))), + c_ast::BinOp::Less => Ok(self.convert_bool_to_int(mk().binary_expr(BinOpKind::Lt, lhs, rhs))), + c_ast::BinOp::Greater => Ok(self.convert_bool_to_int(mk().binary_expr(BinOpKind::Gt, lhs, rhs))), + c_ast::BinOp::GreaterEqual => Ok(self.convert_bool_to_int(mk().binary_expr(BinOpKind::Ge, lhs, rhs))), + c_ast::BinOp::LessEqual => Ok(self.convert_bool_to_int(mk().binary_expr(BinOpKind::Le, lhs, rhs))), c_ast::BinOp::BitAnd => Ok(mk().binary_expr(BinOpKind::BitAnd, lhs, rhs)), c_ast::BinOp::BitOr => Ok(mk().binary_expr(BinOpKind::BitOr, lhs, rhs)), @@ -1031,7 +1031,7 @@ impl<'c> Translation<'c> { c_ast::UnOp::Not => { let val = self.convert_condition(ctx, false, arg)?; - Ok(val.map(|x| mk().cast_expr(x, mk().path_ty(vec!["libc", "c_int"])))) + Ok(val.map(|x| mk().cast_expr(x, self.convert_primitive_type_kind(&c_ast::CTypeKind::Int)))) } c_ast::UnOp::Extension => { let arg = self.convert_expr(ctx, arg)?; diff --git a/c2rust-transpile/src/translator/variadic.rs b/c2rust-transpile/src/translator/variadic.rs index 3cffd8f0a5..c788dd775a 100644 --- a/c2rust-transpile/src/translator/variadic.rs +++ b/c2rust-transpile/src/translator/variadic.rs @@ -147,7 +147,7 @@ impl<'c> Translation<'c> { .map_or(false, |ty| self.ast_context.is_forward_declared_type(ty.ctype)) { real_arg_ty = Some(arg_ty.clone()); - arg_ty = mk().mutbl().ptr_ty(mk().path_ty(vec!["libc", "c_void"])); + arg_ty = mk().mutbl().ptr_ty(mk().path_ty(vec!["core", "ffi", "c_void"])); } val.and_then(|val| { diff --git a/c2rust/src/bin/c2rust-transpile.rs b/c2rust/src/bin/c2rust-transpile.rs index 0bed965f6d..24bd4449e6 100644 --- a/c2rust/src/bin/c2rust-transpile.rs +++ b/c2rust/src/bin/c2rust-transpile.rs @@ -112,6 +112,10 @@ fn main() { }, replace_unsupported_decls: ReplaceMode::Extern, emit_no_std: matches.is_present("emit-no-std"), + ctypes_prefix: matches + .value_of("ctypes-prefix") + .map(String::from) + .unwrap(), enabled_warnings, log_level, }; diff --git a/c2rust/src/transpile.yaml b/c2rust/src/transpile.yaml index a716b9b0bd..89822e59c1 100644 --- a/c2rust/src/transpile.yaml +++ b/c2rust/src/transpile.yaml @@ -168,6 +168,17 @@ args: long: emit-no-std help: Emit code using core rather than std takes_value: false + requires: use-libc-types + - ctypes-prefix: + long: ctypes-prefix + help: Prefix to use for C types + takes_value: true + default_value: std::os::raw + # FIXME: clap has a bug parsing this which was fixed + # immediately after the release of 2.33.3; when 2.33.4 + # comes out, this will work + #default_value_if: + # - ["emit-no-std", null, "libc"] - disable-refactoring: long: disable-refactoring help: Disable running refactoring tool after translation diff --git a/tests/statics/src/test_sections.rs b/tests/statics/src/test_sections.rs index 49908fb735..706cf2fde0 100644 --- a/tests/statics/src/test_sections.rs +++ b/tests/statics/src/test_sections.rs @@ -43,14 +43,14 @@ pub fn test_sectioned_used_static() { let pos = lines .iter() - .position(|&x| x == "static mut rust_used_static4: libc::c_int = 1 as libc::c_int;") + .position(|&x| x == "static mut rust_used_static4: std::os::raw::c_int = 1 as std::os::raw::c_int;") .expect("Did not find expected static string in source"); // The ordering of these attributes is not stable between LLVM versions assert!((lines[pos-1] == "#[used]" && lines[pos-2] == "#[link_section = \"barz\"]") || (lines[pos-2] == "#[used]" && lines[pos-1] == "#[link_section = \"barz\"]")); // This static is pub, but we want to ensure it has attributes applied - assert!(src.contains("#[link_section = \"fb\"]\npub static mut rust_initialized_extern: libc::c_int = 1 as libc::c_int;")); - assert!(src.contains("#[no_mangle]\n #[link_name = \"no_attrs\"]\n static mut rust_aliased_static: libc::c_int;")) + assert!(src.contains("#[link_section = \"fb\"]\npub static mut rust_initialized_extern: std::os::raw::c_int =\n 1 as std::os::raw::c_int;")); + assert!(src.contains("#[no_mangle]\n #[link_name = \"no_attrs\"]\n static mut rust_aliased_static: std::os::raw::c_int;")) } }