Skip to content
Draft
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
21 changes: 19 additions & 2 deletions c2rust-ast-builder/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use syn::{__private::ToTokens, punctuated::Punctuated, *};

pub mod properties {
use proc_macro2::Span;
use syn::{StaticMutability, Token};
use syn::{PointerMutability, StaticMutability, Token};

pub trait ToToken {
type Token;
Expand All @@ -34,6 +34,13 @@ pub mod properties {
}

impl Mutability {
pub fn to_pointer_mutability(&self, span: Span) -> PointerMutability {
match self {
Mutability::Mutable => PointerMutability::Mut(Token![mut](span)),
Mutability::Immutable => PointerMutability::Const(Token![const](span)),
}
}

pub fn to_static_mutability(&self, span: Span) -> StaticMutability {
match self {
Mutability::Mutable => StaticMutability::Mut(Token![mut](span)),
Expand Down Expand Up @@ -826,7 +833,7 @@ impl Builder {
self.path_expr(vec![name])
}

pub fn addr_of_expr(self, e: Box<Expr>) -> Box<Expr> {
pub fn borrow_expr(self, e: Box<Expr>) -> Box<Expr> {
Box::new(parenthesize_if_necessary(Expr::Reference(ExprReference {
attrs: self.attrs,
and_token: Token![&](self.span),
Expand All @@ -835,6 +842,16 @@ impl Builder {
})))
}

pub fn raw_borrow_expr(self, e: Box<Expr>) -> Box<Expr> {
Box::new(parenthesize_if_necessary(Expr::RawAddr(ExprRawAddr {
attrs: self.attrs,
and_token: Token![&](self.span),
raw: Token![raw](self.span),
mutability: self.mutbl.to_pointer_mutability(self.span),
expr: e,
})))
}

pub fn mac_expr(self, mac: Macro) -> Box<Expr> {
Box::new(Expr::Macro(ExprMacro {
attrs: self.attrs,
Expand Down
49 changes: 27 additions & 22 deletions c2rust-transpile/src/convert_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,44 +268,49 @@ impl TypeConverter {
Ok(mk().unsafe_().extern_("C").barefn_ty(fn_ty))
}

/// Converts the qualified type of a pointer.
pub fn convert_pointer(
&mut self,
ctxt: &TypedAstContext,
qtype: CQualTypeId,
) -> TranslationResult<Box<Type>> {
let mutbl = if qtype.qualifiers.is_const {
Mutability::Immutable
let pointee_ty = self.convert_pointee(ctxt, qtype.ctype)?;

if let CTypeKind::Function(..) = ctxt.resolve_type(qtype.ctype).kind {
// Function pointers are translated to Option applied to the function type
// in order to support NULL function pointers natively
let param = mk().angle_bracketed_args(vec![pointee_ty]);
Ok(mk().path_ty(vec![mk().path_segment_with_args("Option", param)]))
} else {
Mutability::Mutable
};
let mutbl = if qtype.qualifiers.is_const {
Mutability::Immutable
} else {
Mutability::Mutable
};

match ctxt.resolve_type(qtype.ctype).kind {
Ok(mk().set_mutbl(mutbl).ptr_ty(pointee_ty))
}
}

/// Converts the pointee type of a pointer.
pub fn convert_pointee(
&mut self,
ctxt: &TypedAstContext,
ctype: CTypeId,
) -> TranslationResult<Box<Type>> {
match ctxt.resolve_type(ctype).kind {
// While void converts to () in function returns, it converts to c_void
// in the case of pointers.
CTypeKind::Void => Ok(mk()
.set_mutbl(mutbl)
.ptr_ty(mk().abs_path_ty(vec!["core", "ffi", "c_void"]))),
CTypeKind::Void => Ok(mk().abs_path_ty(vec!["core", "ffi", "c_void"])),

CTypeKind::VariableArray(mut elt, _len) => {
while let CTypeKind::VariableArray(elt_, _) = ctxt.resolve_type(elt).kind {
elt = elt_
}
let child_ty = self.convert(ctxt, elt)?;
Ok(mk().set_mutbl(mutbl).ptr_ty(child_ty))
}

// Function pointers are translated to Option applied to the function type
// in order to support NULL function pointers natively
CTypeKind::Function(..) => {
let fn_ty = self.convert(ctxt, qtype.ctype)?;
let param = mk().angle_bracketed_args(vec![fn_ty]);
Ok(mk().path_ty(vec![mk().path_segment_with_args("Option", param)]))
self.convert(ctxt, elt)
}

_ => {
let child_ty = self.convert(ctxt, qtype.ctype)?;
Ok(mk().set_mutbl(mutbl).ptr_ty(child_ty))
}
_ => self.convert(ctxt, ctype),
}
}

Expand Down
1 change: 1 addition & 0 deletions c2rust-transpile/src/rust_ast/set_span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ impl SetSpan for Expr {
RangeLimits::Closed(mut r) => r.spans[0] = s,
RangeLimits::HalfOpen(mut r) => r.spans[0] = s,
},
Expr::RawAddr(e) => e.and_token.span = s,
Expr::Reference(e) => e.and_token.span = s,
Expr::Return(e) => e.return_token.span = s,
Expr::Try(e) => e.question_token.span = s,
Expand Down
6 changes: 3 additions & 3 deletions c2rust-transpile/src/translator/assembly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ impl<'c> Translation<'c> {
// c2rust-ast-exporter added it (there's no gcc equivalent);
// in this case, we need to do what clang does and pass in
// the operand by-address instead of by-value
out_expr = mk().mutbl().addr_of_expr(out_expr);
out_expr = mk().mutbl().borrow_expr(out_expr);
}

if let Some(_tied_operand) = tied_operands.get(&(output_idx, true)) {
Expand All @@ -900,7 +900,7 @@ impl<'c> Translation<'c> {
let output_local = mk().local(
mk().ident_pat(&output_name),
None,
Some(mk().mutbl().addr_of_expr(out_expr)),
Some(mk().mutbl().borrow_expr(out_expr)),
);
stmts.push(mk().local_stmt(Box::new(output_local)));

Expand All @@ -924,7 +924,7 @@ impl<'c> Translation<'c> {
let mut in_expr = in_expr.into_value();

if operand.mem_only {
in_expr = mk().addr_of_expr(in_expr);
in_expr = mk().borrow_expr(in_expr);
}
if let Some(tied_operand) = tied_operands.get(&(input_idx, false)) {
self.use_crate(ExternCrate::C2RustAsmCasts);
Expand Down
47 changes: 29 additions & 18 deletions c2rust-transpile/src/translator/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,31 +151,42 @@ impl<'c> Translation<'c> {
Ok(WithStmts::new_val(val))
}

CLiteral::String(ref val, width) => {
let mut val = val.to_owned();
let num_elems = match self.ast_context.resolve_type(ty.ctype).kind {
CTypeKind::ConstantArray(_elem_ty, num_elems) => num_elems,
ref kind => {
panic!("String literal with unknown size: {val:?}, kind = {kind:?}")
}
};

// Match the literal size to the expected size padding with zeros as needed
let size = num_elems * (width as usize);
val.resize(size, 0);
CLiteral::String(ref bytes, element_size) => {
let bytes_padded = self.string_literal_bytes(ty.ctype, bytes, element_size);

// std::mem::transmute::<[u8; size], ctype>(*b"xxxx")
let u8_ty = mk().path_ty(vec!["u8"]);
let width_lit = mk().lit_expr(mk().int_unsuffixed_lit(val.len() as u128));
Ok(WithStmts::new_unsafe_val(transmute_expr(
mk().array_ty(u8_ty, width_lit),
let array_ty = mk().array_ty(
mk().ident_ty("u8"),
mk().lit_expr(bytes_padded.len() as u128),
);
let val = transmute_expr(
array_ty,
self.convert_type(ty.ctype)?,
mk().unary_expr(UnOp::Deref(Default::default()), mk().lit_expr(val)),
)))
mk().unary_expr(UnOp::Deref(Default::default()), mk().lit_expr(bytes_padded)),
);
Ok(WithStmts::new_unsafe_val(val))
}
}
}

/// Returns the bytes of a string literal, including any additional zero bytes to pad the
/// literal to the expected size.
pub fn string_literal_bytes(&self, ctype: CTypeId, bytes: &[u8], element_size: u8) -> Vec<u8> {
let num_elems = match self.ast_context.resolve_type(ctype).kind {
CTypeKind::ConstantArray(_, num_elems) => num_elems,
ref kind => {
panic!("String literal with unknown size: {bytes:?}, kind = {kind:?}")
}
};

let size = num_elems * (element_size as usize);
let mut bytes_padded = Vec::with_capacity(size);
bytes_padded.extend(bytes);
bytes_padded.resize(size, 0);

bytes_padded
}

/// Convert an initialization list into an expression. These initialization lists can be
/// used as array literals, struct literals, and union literals in code.
pub fn convert_init_list(
Expand Down
Loading
Loading