Skip to content

Switch to core::ffi::c_* for C types instead of libc::c_* #297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 44 additions & 21 deletions c2rust-transpile/src/convert_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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] = [
Expand Down Expand Up @@ -133,14 +134,15 @@ 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),
fields: HashMap::new(),
suffix_names: HashMap::new(),
features: HashSet::new(),
emit_no_std,
ctypes_prefix,
}
}

Expand Down Expand Up @@ -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) => {
Expand All @@ -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<P<Ty>> {
let primitive_type = |ty: &str| {
let path = self
.ctypes_prefix
.split("::")
.chain(std::iter::once(ty))
.collect::<Vec<_>>();
mk().path_ty(mk().path(path))
};

match kind {
CTypeKind::Void => Some(mk().tuple_ty(vec![] as Vec<P<Ty>>)),
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(
Expand All @@ -315,26 +352,12 @@ impl TypeConverter {
return Ok(ty);
}

match ctxt.index(ctype).kind {
CTypeKind::Void => Ok(mk().tuple_ty(vec![] as Vec<P<Ty>>)),
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),
Expand Down
1 change: 1 addition & 0 deletions c2rust-transpile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ pub struct TranspilerConfig {
pub reorganize_definitions: bool,
pub enabled_warnings: HashSet<Diagnostic>,
pub emit_no_std: bool,
pub ctypes_prefix: String,
pub output_dir: Option<PathBuf>,
pub translate_const_macros: bool,
pub translate_fn_macros: bool,
Expand Down
6 changes: 5 additions & 1 deletion c2rust-transpile/src/translator/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<P<Expr>>);

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" => {
Expand Down Expand Up @@ -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`
Expand Down Expand Up @@ -670,6 +672,8 @@ impl<'c> Translation<'c> {
ctx: ExprContext,
args: &[CExprId],
) -> Result<WithStmts<P<Expr>>, 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)?;
Expand Down
4 changes: 2 additions & 2 deletions c2rust-transpile/src/translator/main_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down
34 changes: 23 additions & 11 deletions c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<Expr>) -> P<Expr> {
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<ast::Attribute>, src_loc: &Option<SrcLoc>) {
if let Some(src_loc) = src_loc.as_ref() {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2786,6 +2783,21 @@ impl<'c> Translation<'c> {
.convert(&self.ast_context, type_id)
}

fn convert_primitive_type_kind(&self, kind: &CTypeKind) -> P<Ty> {
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<Expr>) -> P<Expr> {
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<P<Expr>, TranslationError> {
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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)
))
})
}
Expand Down
16 changes: 8 additions & 8 deletions c2rust-transpile/src/translator/operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand All @@ -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)),
Expand Down Expand Up @@ -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)?;
Expand Down
2 changes: 1 addition & 1 deletion c2rust-transpile/src/translator/variadic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down
4 changes: 4 additions & 0 deletions c2rust/src/bin/c2rust-transpile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down
11 changes: 11 additions & 0 deletions c2rust/src/transpile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions tests/statics/src/test_sections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;"))
}
}