Skip to content

Commit 38d6547

Browse files
authored
transpile: Split off new pointers.rs module (#1495)
Working with pointer-related stuff, I found that related code was kinda scattered all over, making it difficult to find at times. This creates a new pointers.rs module, moves some existing functions there, and creates new functions to wrap some other bits of code. I've tried to not make too many semantic changes. In `convert_assignment_operator_with_rhs` there was a bit of dead code that I removed. Since `AssignAdd` and `AssignSubtract` are handled by the match arms, the `if` that checks for them below a second time wasn't doing anything (and it did the same thing anyway).
2 parents 6ea5545 + 95de6eb commit 38d6547

File tree

3 files changed

+473
-458
lines changed

3 files changed

+473
-458
lines changed

c2rust-transpile/src/translator/mod.rs

Lines changed: 5 additions & 336 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ mod literals;
4949
mod main_function;
5050
mod named_references;
5151
mod operators;
52+
mod pointers;
5253
mod simd;
5354
mod structs;
5455
mod variadic;
@@ -302,34 +303,6 @@ fn cast_int(val: Box<Expr>, name: &str, need_lit_suffix: bool) -> Box<Expr> {
302303
}
303304
}
304305

305-
/// Pointer offset that casts its argument to isize
306-
fn pointer_offset(
307-
ptr: Box<Expr>,
308-
offset: Box<Expr>,
309-
multiply_by: Option<Box<Expr>>,
310-
neg: bool,
311-
mut deref: bool,
312-
) -> Box<Expr> {
313-
let mut offset = cast_int(offset, "isize", false);
314-
315-
if let Some(mul) = multiply_by {
316-
let mul = cast_int(mul, "isize", false);
317-
offset = mk().binary_expr(BinOp::Mul(Default::default()), offset, mul);
318-
deref = false;
319-
}
320-
321-
if neg {
322-
offset = mk().unary_expr(UnOp::Neg(Default::default()), offset);
323-
}
324-
325-
let res = mk().method_call_expr(ptr, "offset", vec![offset]);
326-
if deref {
327-
mk().unary_expr(UnOp::Deref(Default::default()), res)
328-
} else {
329-
res
330-
}
331-
}
332-
333306
/// Given an expression with type Option<fn(...)->...>, unwrap
334307
/// the Option and return the function.
335308
fn unwrap_function_pointer(ptr: Box<Expr>) -> Box<Expr> {
@@ -3082,54 +3055,6 @@ impl<'c> Translation<'c> {
30823055
.convert(&self.ast_context, type_id)
30833056
}
30843057

3085-
fn convert_pointee_type(&self, type_id: CTypeId) -> TranslationResult<Box<Type>> {
3086-
self.import_type(type_id);
3087-
3088-
self.type_converter
3089-
.borrow_mut()
3090-
.convert_pointee(&self.ast_context, type_id)
3091-
}
3092-
3093-
/// Construct an expression for a NULL at any type, including forward declarations,
3094-
/// function pointers, and normal pointers.
3095-
fn null_ptr(&self, type_id: CTypeId, is_static: bool) -> TranslationResult<Box<Expr>> {
3096-
if self.ast_context.is_function_pointer(type_id) {
3097-
return Ok(mk().path_expr(vec!["None"]));
3098-
}
3099-
3100-
let pointer_qty = self
3101-
.ast_context
3102-
.get_pointee_qual_type(type_id)
3103-
.ok_or_else(|| TranslationError::generic("null_ptr requires a pointer"))?;
3104-
3105-
let func = if pointer_qty.qualifiers.is_const
3106-
// static variable initializers aren't able to use null_mut
3107-
// TODO: Rust 1.83: Allowed, so this can be removed.
3108-
|| is_static
3109-
{
3110-
"null"
3111-
} else {
3112-
"null_mut"
3113-
};
3114-
let pointee_ty = self.convert_pointee_type(pointer_qty.ctype)?;
3115-
let type_args = mk().angle_bracketed_args(vec![pointee_ty.clone()]);
3116-
let mut val = mk().call_expr(
3117-
mk().abs_path_expr(vec![
3118-
mk().path_segment("core"),
3119-
mk().path_segment("ptr"),
3120-
mk().path_segment_with_args(func, type_args),
3121-
]),
3122-
vec![],
3123-
);
3124-
3125-
// TODO: Rust 1.83: Remove.
3126-
if is_static && !pointer_qty.qualifiers.is_const {
3127-
val = mk().cast_expr(val, mk().mutbl().ptr_ty(pointee_ty));
3128-
}
3129-
3130-
Ok(val)
3131-
}
3132-
31333058
fn addr_lhs(
31343059
&self,
31353060
lhs: Box<Expr>,
@@ -3865,151 +3790,9 @@ impl<'c> Translation<'c> {
38653790
)
38663791
.map_err(|e| e.add_loc(self.ast_context.display_loc(src_loc))),
38673792

3868-
ArraySubscript(_, ref lhs, ref rhs, _) => {
3869-
let lhs_node = &self.ast_context.index(*lhs).kind;
3870-
let rhs_node = &self.ast_context.index(*rhs).kind;
3871-
3872-
let lhs_node_type = lhs_node
3873-
.get_type()
3874-
.ok_or_else(|| format_err!("lhs node bad type"))?;
3875-
let lhs_node_kind = &self.ast_context.resolve_type(lhs_node_type).kind;
3876-
let lhs_is_indexable = lhs_node_kind.is_pointer() || lhs_node_kind.is_vector();
3877-
3878-
// From here on in, the LHS is the pointer/array and the RHS the index
3879-
let (lhs, rhs, lhs_node) = if lhs_is_indexable {
3880-
(lhs, rhs, lhs_node)
3881-
} else {
3882-
(rhs, lhs, rhs_node)
3883-
};
3884-
3885-
let lhs_node_type = lhs_node
3886-
.get_type()
3887-
.ok_or_else(|| format_err!("lhs node bad type"))?;
3888-
if self
3889-
.ast_context
3890-
.resolve_type(lhs_node_type)
3891-
.kind
3892-
.is_vector()
3893-
{
3894-
return Err(TranslationError::new(
3895-
self.ast_context.display_loc(src_loc),
3896-
err_msg("Attempting to index a vector type")
3897-
.context(TranslationErrorKind::OldLLVMSimd),
3898-
));
3899-
}
3900-
3901-
let rhs = self.convert_expr(ctx.used(), *rhs, None)?;
3902-
rhs.and_then(|rhs| {
3903-
let simple_index_array = if ctx.needs_address() {
3904-
// We can't necessarily index into an array if we're using
3905-
// that element to compute an address.
3906-
None
3907-
} else {
3908-
match lhs_node {
3909-
&CExprKind::ImplicitCast(
3910-
_,
3911-
arr,
3912-
CastKind::ArrayToPointerDecay,
3913-
_,
3914-
_,
3915-
) => {
3916-
match self.ast_context[arr].kind {
3917-
CExprKind::Member(_, _, field_decl, _, _)
3918-
if self
3919-
.potential_flexible_array_members
3920-
.borrow()
3921-
.contains(&field_decl) =>
3922-
{
3923-
None
3924-
}
3925-
ref kind => {
3926-
let arr_type = kind
3927-
.get_type()
3928-
.ok_or_else(|| format_err!("bad arr type"))?;
3929-
match self.ast_context.resolve_type(arr_type).kind {
3930-
// These get translated to 0-element arrays, this avoids the bounds check
3931-
// that using an array subscript in Rust would cause
3932-
CTypeKind::IncompleteArray(_) => None,
3933-
_ => Some(arr),
3934-
}
3935-
}
3936-
}
3937-
}
3938-
_ => None,
3939-
}
3940-
};
3941-
3942-
if let Some(arr) = simple_index_array {
3943-
// If the LHS just underwent an implicit cast from array to pointer, bypass that
3944-
// to make an actual Rust indexing operation
3945-
3946-
let t = self.ast_context[arr]
3947-
.kind
3948-
.get_type()
3949-
.ok_or_else(|| format_err!("bad arr type"))?;
3950-
let var_elt_type_id = match self.ast_context.resolve_type(t).kind {
3951-
CTypeKind::ConstantArray(..) => None,
3952-
CTypeKind::IncompleteArray(..) => None,
3953-
CTypeKind::VariableArray(elt, _) => Some(elt),
3954-
ref other => panic!("Unexpected array type {:?}", other),
3955-
};
3956-
3957-
let lhs = self.convert_expr(ctx.used(), arr, None)?;
3958-
lhs.and_then(|lhs| {
3959-
// stmts.extend(lhs.stmts_mut());
3960-
// is_unsafe = is_unsafe || lhs.is_unsafe();
3961-
3962-
// Don't dereference the offset if we're still within the variable portion
3963-
if let Some(elt_type_id) = var_elt_type_id {
3964-
let mul = self.compute_size_of_expr(elt_type_id);
3965-
Ok(WithStmts::new_unsafe_val(pointer_offset(
3966-
lhs, rhs, mul, false, true,
3967-
)))
3968-
} else {
3969-
Ok(WithStmts::new_val(
3970-
mk().index_expr(lhs, cast_int(rhs, "usize", false)),
3971-
))
3972-
}
3973-
})
3974-
} else {
3975-
// LHS must be ref decayed for the offset method call's self param
3976-
let mut lhs = self.convert_expr(ctx.used().decay_ref(), *lhs, None)?;
3977-
lhs.set_unsafe(); // `pointer_offset` is unsafe.
3978-
lhs.result_map(|lhs| {
3979-
// stmts.extend(lhs.stmts_mut());
3980-
// is_unsafe = is_unsafe || lhs.is_unsafe();
3981-
3982-
let lhs_type_id = lhs_node
3983-
.get_type()
3984-
.ok_or_else(|| format_err!("bad lhs type"))?;
3985-
3986-
// Determine the type of element being indexed
3987-
let pointee_type_id =
3988-
match self.ast_context.resolve_type(lhs_type_id).kind {
3989-
CTypeKind::Pointer(pointee_id) => pointee_id,
3990-
_ => {
3991-
return Err(format_err!(
3992-
"Subscript applied to non-pointer: {:?}",
3993-
lhs
3994-
)
3995-
.into());
3996-
}
3997-
};
3998-
3999-
let mul = self.compute_size_of_expr(pointee_type_id.ctype);
4000-
let mut val = pointer_offset(lhs, rhs, mul, false, true);
4001-
// if the context wants a different type, add a cast
4002-
if let Some(expected_ty) = override_ty {
4003-
if expected_ty != pointee_type_id {
4004-
val =
4005-
mk().cast_expr(val, self.convert_type(expected_ty.ctype)?);
4006-
}
4007-
}
4008-
Ok(val)
4009-
})
4010-
}
4011-
})
4012-
}
3793+
ArraySubscript(_, lhs, rhs, _) => self
3794+
.convert_array_subscript(ctx, lhs, rhs, override_ty)
3795+
.map_err(|e| e.add_loc(self.ast_context.display_loc(src_loc))),
40133796

40143797
Call(call_expr_ty, func, ref args) => {
40153798
let fn_ty =
@@ -4739,21 +4522,7 @@ impl<'c> Translation<'c> {
47394522
}
47404523

47414524
CastKind::ArrayToPointerDecay => {
4742-
// Because va_list is sometimes defined as a single-element
4743-
// array in order for it to allocate memory as a local variable
4744-
// and to be a pointer as a function argument we would get
4745-
// spurious casts when trying to treat it like a VaList which
4746-
// has reference semantics.
4747-
if self.ast_context.is_va_list(target_cty.ctype) {
4748-
return Ok(val);
4749-
}
4750-
4751-
// Variable length arrays are already represented as pointers.
4752-
if let CTypeKind::VariableArray(..) = source_ty_kind {
4753-
return Ok(val);
4754-
}
4755-
4756-
self.convert_address_of(ctx, expr, source_cty, target_cty, val, true)
4525+
self.convert_array_to_pointer_decay(ctx, source_cty, target_cty, val, expr)
47574526
}
47584527

47594528
CastKind::NullToPointer => {
@@ -4913,106 +4682,6 @@ impl<'c> Translation<'c> {
49134682
val.map(|x| mk().cast_expr(x, target_ty))
49144683
}
49154684

4916-
pub fn convert_address_of(
4917-
&self,
4918-
ctx: ExprContext,
4919-
arg: Option<CExprId>,
4920-
arg_cty: CQualTypeId,
4921-
pointer_cty: CQualTypeId,
4922-
mut val: WithStmts<Box<Expr>>,
4923-
is_array_decay: bool,
4924-
) -> TranslationResult<WithStmts<Box<Expr>>> {
4925-
let arg_expr_kind = arg.map(|arg| {
4926-
let arg = self.ast_context.unwrap_predefined_ident(arg);
4927-
&self.ast_context.index(arg).kind
4928-
});
4929-
let pointee_cty = self
4930-
.ast_context
4931-
.get_pointee_qual_type(pointer_cty.ctype)
4932-
.ok_or_else(|| TranslationError::generic("Address-of should return a pointer"))?;
4933-
let arg_is_macro = arg.map_or(false, |arg| {
4934-
matches!(
4935-
self.convert_const_macro_expansion(ctx, arg, None),
4936-
Ok(Some(_))
4937-
)
4938-
});
4939-
4940-
let mut needs_cast = false;
4941-
let mut ref_cast_pointee_ty = None;
4942-
let mutbl = if pointee_cty.qualifiers.is_const {
4943-
Mutability::Immutable
4944-
} else if ctx.is_static {
4945-
// static variable initializers aren't able to use &mut, so we work around that
4946-
// by using & and an extra cast through & to *const to *mut
4947-
// TODO: Rust 1.83: Allowed, so this can be removed.
4948-
needs_cast = true;
4949-
Mutability::Immutable
4950-
} else {
4951-
Mutability::Mutable
4952-
};
4953-
4954-
// String literals are translated with a transmute, which produces a temporary.
4955-
// Taking the address of a temporary leaves a dangling pointer. So instead,
4956-
// cast the string literal directly so that its 'static lifetime is preserved.
4957-
if let (
4958-
Some(&CExprKind::Literal(literal_cty, CLiteral::String(ref bytes, element_size @ 1))),
4959-
false,
4960-
) = (arg_expr_kind, arg_is_macro)
4961-
{
4962-
let bytes_padded = self.string_literal_bytes(literal_cty.ctype, bytes, element_size);
4963-
let len = bytes_padded.len();
4964-
val = WithStmts::new_val(mk().lit_expr(bytes_padded));
4965-
4966-
if is_array_decay {
4967-
ref_cast_pointee_ty = Some(mk().ident_ty("u8"));
4968-
} else {
4969-
ref_cast_pointee_ty =
4970-
Some(mk().array_ty(mk().ident_ty("u8"), mk().lit_expr(len as u128)));
4971-
}
4972-
needs_cast = true;
4973-
} else {
4974-
let arg_cty_kind = &self.ast_context.resolve_type(arg_cty.ctype).kind;
4975-
4976-
if is_array_decay {
4977-
let method = match mutbl {
4978-
Mutability::Mutable => "as_mut_ptr",
4979-
Mutability::Immutable => "as_ptr",
4980-
};
4981-
val = val.map(|val| mk().method_call_expr(val, method, vec![]));
4982-
4983-
// If the target pointee type is different from the source element type,
4984-
// then we need to cast the ptr type as well.
4985-
if arg_cty_kind.element_ty().map_or(false, |arg_element_cty| {
4986-
arg_element_cty != pointee_cty.ctype
4987-
}) {
4988-
needs_cast = true;
4989-
}
4990-
} else {
4991-
val = val.map(|val| mk().set_mutbl(mutbl).addr_of_expr(val));
4992-
4993-
// Add an intermediate reference-to-pointer cast if the context needs
4994-
// reference-to-pointer decay, or if another cast follows.
4995-
if ctx.decay_ref.is_yes() || needs_cast {
4996-
ref_cast_pointee_ty = Some(self.convert_pointee_type(arg_cty.ctype)?);
4997-
}
4998-
}
4999-
}
5000-
5001-
// Perform an intermediate reference-to-pointer cast if needed.
5002-
// TODO: Rust 1.76: Use `ptr::from_ref`.
5003-
if let Some(pointee_ty) = ref_cast_pointee_ty {
5004-
val = val.map(|val| mk().cast_expr(val, mk().set_mutbl(mutbl).ptr_ty(pointee_ty)));
5005-
}
5006-
5007-
// Perform a final cast to the target type if needed.
5008-
if needs_cast {
5009-
let pointer_ty = self.convert_type(pointer_cty.ctype)?;
5010-
val = val.map(|val| mk().cast_expr(val, pointer_ty));
5011-
}
5012-
5013-
Ok(val)
5014-
}
5015-
50164685
pub fn implicit_default_expr(
50174686
&self,
50184687
ty_id: CTypeId,

0 commit comments

Comments
 (0)