Skip to content

Commit cbf4e0a

Browse files
authored
transpile: support CastKind::ArrayToPointerDecays in --translate-const-macros conservative (#1349)
* Fixes #1348. This is done by adding a ptr cast to the target pointer type if the element types aren't the same, where the element type is like the pointee type, but also includes array types that will decay to pointers. `fn CTypeKind::element_ty` is added for that. I also cleaned up some stuff in `fn convert_cast`, as the naming was pretty irregular, repetitive, and confusing.
2 parents 3f701aa + 4150cab commit cbf4e0a

File tree

5 files changed

+117
-96
lines changed

5 files changed

+117
-96
lines changed

c2rust-transpile/src/c_ast/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,6 @@ impl TypedAstContext {
649649
// TODO `f128` is not yet handled, as we should eventually
650650
// switch to the (currently unstable) `f128` primitive type (#1262).
651651
Binary(_, _, lhs, rhs, _, _) => is_const(lhs) && is_const(rhs),
652-
ImplicitCast(_, _, CastKind::ArrayToPointerDecay, _, _) => false, // TODO disabled for now as tests are broken
653652
// `as` casts are always `const`.
654653
ImplicitCast(_, expr, _, _, _) => is_const(expr),
655654
// `as` casts are always `const`.
@@ -2330,6 +2329,17 @@ impl CTypeKind {
23302329
};
23312330
Some(ty)
23322331
}
2332+
2333+
/// Return the element type of a pointer or array
2334+
pub fn element_ty(&self) -> Option<CTypeId> {
2335+
Some(match *self {
2336+
Self::Pointer(ty) => ty.ctype,
2337+
Self::ConstantArray(ty, _) => ty,
2338+
Self::IncompleteArray(ty) => ty,
2339+
Self::VariableArray(ty, _) => ty,
2340+
_ => return None,
2341+
})
2342+
}
23332343
}
23342344

23352345
#[cfg(test)]

c2rust-transpile/src/translator/mod.rs

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2934,10 +2934,10 @@ impl<'c> Translation<'c> {
29342934
return Ok(mk().path_expr(vec!["None"]));
29352935
}
29362936

2937-
let pointee = match self.ast_context.resolve_type(type_id).kind {
2938-
CTypeKind::Pointer(pointee) => pointee,
2939-
_ => return Err(TranslationError::generic("null_ptr requires a pointer")),
2940-
};
2937+
let pointee = self
2938+
.ast_context
2939+
.get_pointee_qual_type(type_id)
2940+
.ok_or(TranslationError::generic("null_ptr requires a pointer"))?;
29412941
let ty = self.convert_type(type_id)?;
29422942
let mut zero = mk().lit_expr(mk().int_unsuffixed_lit(0));
29432943
if is_static && !pointee.qualifiers.is_const {
@@ -4293,15 +4293,15 @@ impl<'c> Translation<'c> {
42934293
fn convert_cast(
42944294
&self,
42954295
ctx: ExprContext,
4296-
source_ty: CQualTypeId,
4297-
ty: CQualTypeId,
4296+
source_cty: CQualTypeId,
4297+
target_cty: CQualTypeId,
42984298
val: WithStmts<Box<Expr>>,
42994299
expr: Option<CExprId>,
43004300
kind: Option<CastKind>,
43014301
opt_field_id: Option<CFieldId>,
43024302
) -> TranslationResult<WithStmts<Box<Expr>>> {
4303-
let source_ty_kind = &self.ast_context.resolve_type(source_ty.ctype).kind;
4304-
let target_ty_kind = &self.ast_context.resolve_type(ty.ctype).kind;
4303+
let source_ty_kind = &self.ast_context.resolve_type(source_cty.ctype).kind;
4304+
let target_ty_kind = &self.ast_context.resolve_type(target_cty.ctype).kind;
43054305

43064306
if source_ty_kind == target_ty_kind {
43074307
return Ok(val);
@@ -4382,24 +4382,26 @@ impl<'c> Translation<'c> {
43824382
match kind {
43834383
CastKind::BitCast | CastKind::NoOp => {
43844384
val.and_then(|x| {
4385-
if self.ast_context.is_function_pointer(ty.ctype)
4386-
|| self.ast_context.is_function_pointer(source_ty.ctype)
4385+
if self.ast_context.is_function_pointer(target_cty.ctype)
4386+
|| self.ast_context.is_function_pointer(source_cty.ctype)
43874387
{
4388-
let source_ty = self.convert_type(source_ty.ctype)?;
4389-
let target_ty = self.convert_type(ty.ctype)?;
4388+
let source_ty = self.convert_type(source_cty.ctype)?;
4389+
let target_ty = self.convert_type(target_cty.ctype)?;
43904390
Ok(WithStmts::new_unsafe_val(transmute_expr(
43914391
source_ty, target_ty, x,
43924392
)))
43934393
} else {
43944394
// Normal case
4395-
let target_ty = self.convert_type(ty.ctype)?;
4395+
let target_ty = self.convert_type(target_cty.ctype)?;
43964396
Ok(WithStmts::new_val(mk().cast_expr(x, target_ty)))
43974397
}
43984398
})
43994399
}
44004400

4401-
CastKind::IntegralToPointer if self.ast_context.is_function_pointer(ty.ctype) => {
4402-
let target_ty = self.convert_type(ty.ctype)?;
4401+
CastKind::IntegralToPointer
4402+
if self.ast_context.is_function_pointer(target_cty.ctype) =>
4403+
{
4404+
let target_ty = self.convert_type(target_cty.ctype)?;
44034405
val.and_then(|x| {
44044406
let intptr_t = mk().path_ty(vec!["libc", "intptr_t"]);
44054407
let intptr = mk().cast_expr(x, intptr_t.clone());
@@ -4415,13 +4417,10 @@ impl<'c> Translation<'c> {
44154417
| CastKind::FloatingCast
44164418
| CastKind::FloatingToIntegral
44174419
| CastKind::IntegralToFloating => {
4418-
let target_ty = self.convert_type(ty.ctype)?;
4419-
let target_ty_ctype = &self.ast_context.resolve_type(ty.ctype).kind;
4420+
let target_ty = self.convert_type(target_cty.ctype)?;
4421+
let source_ty = self.convert_type(source_cty.ctype)?;
44204422

4421-
let source_ty_ctype_id = source_ty.ctype;
4422-
4423-
let source_ty = self.convert_type(source_ty_ctype_id)?;
4424-
if let CTypeKind::LongDouble = target_ty_ctype {
4423+
if let CTypeKind::LongDouble = target_ty_kind {
44254424
if ctx.is_const {
44264425
return Err(format_translation_err!(
44274426
None,
@@ -4433,21 +4432,28 @@ impl<'c> Translation<'c> {
44334432

44344433
let fn_path = mk().path_expr(vec!["f128", "f128", "new"]);
44354434
Ok(val.map(|val| mk().call_expr(fn_path, vec![val])))
4436-
} else if let CTypeKind::LongDouble = self.ast_context[source_ty_ctype_id].kind {
4437-
self.f128_cast_to(val, target_ty_ctype)
4438-
} else if let &CTypeKind::Enum(enum_decl_id) = target_ty_ctype {
4435+
} else if let CTypeKind::LongDouble = self.ast_context[source_cty.ctype].kind {
4436+
self.f128_cast_to(val, target_ty_kind)
4437+
} else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind {
44394438
// Casts targeting `enum` types...
44404439
let expr =
44414440
expr.ok_or_else(|| format_err!("Casts to enums require a C ExprId"))?;
4442-
Ok(self.enum_cast(ty.ctype, enum_decl_id, expr, val, source_ty, target_ty))
4443-
} else if target_ty_ctype.is_floating_type() && source_ty_kind.is_bool() {
4441+
Ok(self.enum_cast(
4442+
target_cty.ctype,
4443+
enum_decl_id,
4444+
expr,
4445+
val,
4446+
source_ty,
4447+
target_ty,
4448+
))
4449+
} else if target_ty_kind.is_floating_type() && source_ty_kind.is_bool() {
44444450
val.and_then(|x| {
44454451
Ok(WithStmts::new_val(mk().cast_expr(
44464452
mk().cast_expr(x, mk().path_ty(vec!["u8"])),
44474453
target_ty,
44484454
)))
44494455
})
4450-
} else if target_ty_ctype.is_pointer() && source_ty_kind.is_bool() {
4456+
} else if target_ty_kind.is_pointer() && source_ty_kind.is_bool() {
44514457
val.and_then(|x| {
44524458
Ok(WithStmts::new_val(mk().cast_expr(
44534459
mk().cast_expr(x, mk().path_ty(vec!["libc", "size_t"])),
@@ -4458,7 +4464,7 @@ impl<'c> Translation<'c> {
44584464
// Other numeric casts translate to Rust `as` casts,
44594465
// unless the cast is to a function pointer then use `transmute`.
44604466
val.and_then(|x| {
4461-
if self.ast_context.is_function_pointer(source_ty_ctype_id) {
4467+
if self.ast_context.is_function_pointer(source_cty.ctype) {
44624468
Ok(WithStmts::new_unsafe_val(transmute_expr(
44634469
source_ty, target_ty, x,
44644470
)))
@@ -4481,21 +4487,21 @@ impl<'c> Translation<'c> {
44814487
// and to be a pointer as a function argument we would get
44824488
// spurious casts when trying to treat it like a VaList which
44834489
// has reference semantics.
4484-
if self.ast_context.is_va_list(ty.ctype) {
4490+
if self.ast_context.is_va_list(target_cty.ctype) {
44854491
return Ok(val);
44864492
}
44874493

4488-
let pointee = match self.ast_context.resolve_type(ty.ctype).kind {
4489-
CTypeKind::Pointer(pointee) => pointee,
4490-
_ => panic!("Dereferencing a non-pointer"),
4491-
};
4494+
let pointee = self
4495+
.ast_context
4496+
.get_pointee_qual_type(target_cty.ctype)
4497+
.unwrap_or_else(|| panic!("dereferencing a non-pointer"));
44924498

44934499
let is_const = pointee.qualifiers.is_const;
44944500

44954501
let expr_kind = expr.map(|e| &self.ast_context.index(e).kind);
44964502
match expr_kind {
44974503
Some(&CExprKind::Literal(_, CLiteral::String(ref bytes, 1))) if is_const => {
4498-
let target_ty = self.convert_type(ty.ctype)?;
4504+
let target_ty = self.convert_type(target_cty.ctype)?;
44994505

45004506
let mut bytes = bytes.to_owned();
45014507
bytes.push(0);
@@ -4507,9 +4513,7 @@ impl<'c> Translation<'c> {
45074513
}
45084514
_ => {
45094515
// Variable length arrays are already represented as pointers.
4510-
if let CTypeKind::VariableArray(..) =
4511-
self.ast_context.resolve_type(source_ty.ctype).kind
4512-
{
4516+
if let CTypeKind::VariableArray(..) = source_ty_kind {
45134517
Ok(val)
45144518
} else {
45154519
let method = if is_const || ctx.is_static {
@@ -4520,6 +4524,19 @@ impl<'c> Translation<'c> {
45204524

45214525
let call = val.map(|x| mk().method_call_expr(x, method, vec![]));
45224526

4527+
// If the target pointee type is different from the source element type,
4528+
// then we need to cast the ptr type as well.
4529+
let call = match source_ty_kind.element_ty() {
4530+
None => call,
4531+
Some(source_element_ty) if source_element_ty == pointee.ctype => {
4532+
call
4533+
}
4534+
Some(_) => {
4535+
let target_ty = self.convert_type(target_cty.ctype)?;
4536+
call.map(|ptr| mk().cast_expr(ptr, target_ty))
4537+
}
4538+
};
4539+
45234540
// Static arrays can now use as_ptr. Can also cast that const ptr to a
45244541
// mutable pointer as we do here:
45254542
if ctx.is_static && !is_const {
@@ -4538,7 +4555,9 @@ impl<'c> Translation<'c> {
45384555

45394556
CastKind::NullToPointer => {
45404557
assert!(val.stmts().is_empty());
4541-
Ok(WithStmts::new_val(self.null_ptr(ty.ctype, ctx.is_static)?))
4558+
Ok(WithStmts::new_val(
4559+
self.null_ptr(target_cty.ctype, ctx.is_static)?,
4560+
))
45424561
}
45434562

45444563
CastKind::ToUnion => {
@@ -4567,7 +4586,7 @@ impl<'c> Translation<'c> {
45674586
if let Some(expr) = expr {
45684587
self.convert_condition(ctx, true, expr)
45694588
} else {
4570-
Ok(val.map(|e| self.match_bool(true, source_ty.ctype, e)))
4589+
Ok(val.map(|e| self.match_bool(true, source_cty.ctype, e)))
45714590
}
45724591
}
45734592

c2rust-transpile/tests/snapshots/[email protected]

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ pub unsafe extern "C" fn size_of_const() -> std::ffi::c_int {
3131
return SIZE as std::ffi::c_int;
3232
}
3333
pub const SIZE: usize = unsafe { ::core::mem::size_of::<[std::ffi::c_int; 10]>() };
34+
pub const POS: [std::ffi::c_char; 3] =
35+
unsafe { *::core::mem::transmute::<&[u8; 3], &[std::ffi::c_char; 3]>(b"\"]\0") };
3436
#[no_mangle]
3537
pub unsafe extern "C" fn memcpy_str_literal(mut out: *mut std::ffi::c_char) {
3638
memcpy(
3739
out as *mut std::ffi::c_void,
38-
b"\"]\0" as *const u8 as *const std::ffi::c_char as *const std::ffi::c_void,
40+
POS.as_ptr() as *const std::ffi::c_void,
3941
(::core::mem::size_of::<[std::ffi::c_char; 3]>() as size_t)
4042
.wrapping_div(::core::mem::size_of::<std::ffi::c_char>() as size_t)
4143
.wrapping_sub(1 as size_t)

c2rust-transpile/tests/snapshots/[email protected]

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ pub unsafe extern "C" fn size_of_const() -> std::ffi::c_int {
3232
return SIZE as std::ffi::c_int;
3333
}
3434
pub const SIZE: usize = unsafe { ::core::mem::size_of::<[std::ffi::c_int; 10]>() };
35+
pub const POS: [std::ffi::c_char; 3] =
36+
unsafe { *::core::mem::transmute::<&[u8; 3], &[std::ffi::c_char; 3]>(b"\"]\0") };
3537
#[no_mangle]
3638
pub unsafe extern "C" fn memcpy_str_literal(mut out: *mut std::ffi::c_char) {
3739
memcpy(
3840
out as *mut std::ffi::c_void,
39-
b"\"]\0" as *const u8 as *const std::ffi::c_char as *const std::ffi::c_void,
41+
POS.as_ptr() as *const std::ffi::c_void,
4042
(::core::mem::size_of::<[std::ffi::c_char; 3]>() as size_t)
4143
.wrapping_div(::core::mem::size_of::<std::ffi::c_char>() as size_t)
4244
.wrapping_sub(1 as size_t)

0 commit comments

Comments
 (0)