Skip to content

Commit 1ca5371

Browse files
committed
transpile: handle fiddly cases around function casts
1 parent cf9c20f commit 1ca5371

File tree

3 files changed

+113
-3
lines changed

3 files changed

+113
-3
lines changed

c2rust-transpile/src/c_ast/conversion.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,30 @@ impl ConversionContext {
480480
self.visit_node(untyped_context, node_id, new_id, expected_ty)
481481
}
482482

483+
// Function declarations' types look through typedefs, but we want to use the types with
484+
// typedefs intact in some cases during translation. To ensure that these types exist in the
485+
// `TypedAstContext`, iterate over all function decls, compute their adjusted type using
486+
// argument types from arg declarations, and then ensure the existence of both this type and
487+
// the type of pointers to it.
488+
for (_decl_id, located_kind) in self.typed_context.c_decls.iter() {
489+
if let kind @ CDeclKind::Function { .. } = &located_kind.kind {
490+
let new_kind = self.typed_context.fn_decl_ty_with_declared_args(kind);
491+
if self.typed_context.type_for_kind(&new_kind).is_none() {
492+
// Create and insert fn type
493+
let new_id = CTypeId(self.id_mapper.fresh_id());
494+
self.typed_context
495+
.c_types
496+
.insert(new_id, not_located(new_kind));
497+
// Create and insert fn ptr type
498+
let ptr_kind = CTypeKind::Pointer(CQualTypeId::new(new_id));
499+
let ptr_id = CTypeId(self.id_mapper.fresh_id());
500+
self.typed_context
501+
.c_types
502+
.insert(ptr_id, not_located(ptr_kind));
503+
}
504+
}
505+
}
506+
483507
// Invert the macro invocations to get a list of macro expansion expressions
484508
for (expr_id, macro_ids) in &self.typed_context.macro_invocations {
485509
for mac_id in macro_ids {

c2rust-transpile/src/c_ast/mod.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,44 @@ impl TypedAstContext {
519519
return Some(param_tys);
520520
}
521521

522+
/// Return the most precise possible CTypeKind for the given function declaration.
523+
/// Specifically, ensures that arguments' types are not resolved to underlying types if they were
524+
/// declared as typedefs, but returned as those typedefs.
525+
///
526+
/// The passed CDeclId must refer to a function declaration.
527+
pub fn fn_decl_ty_with_declared_args(&self, func_decl: &CDeclKind) -> CTypeKind {
528+
if let CDeclKind::Function {
529+
typ, parameters, ..
530+
} = func_decl
531+
{
532+
let typ = self.resolve_type_id(*typ);
533+
let decl_arg_tys = self.tys_of_params(parameters).unwrap();
534+
let typ_kind = &self[typ].kind;
535+
if let &CTypeKind::Function(ret, ref _arg_tys, a, b, c) = typ_kind {
536+
return CTypeKind::Function(ret, decl_arg_tys, a, b, c);
537+
}
538+
panic!("expected {typ:?} to be CTypeKind::Function, but it was {typ_kind:?}")
539+
}
540+
panic!("expected a CDeclKind::Function, but passed {func_decl:?}")
541+
}
542+
543+
/// Return the most id of the most precise possible type for the function referenced by the
544+
/// given expression.
545+
pub fn function_declref_ty_with_declared_args(
546+
&self,
547+
func_expr: CExprId,
548+
) -> Option<CQualTypeId> {
549+
if let Some(func_decl @ CDeclKind::Function { .. }) = self.function_declref_decl(func_expr)
550+
{
551+
let kind_with_declared_args = self.fn_decl_ty_with_declared_args(func_decl);
552+
let specific_typ = self
553+
.type_for_kind(&kind_with_declared_args)
554+
.expect(&format!("no type for kind {kind_with_declared_args:?}"));
555+
return Some(CQualTypeId::new(specific_typ));
556+
}
557+
None
558+
}
559+
522560
/// Pessimistically try to check if an expression has side effects. If it does, or we can't tell
523561
/// that it doesn't, return `false`.
524562
pub fn is_expr_pure(&self, expr: CExprId) -> bool {

c2rust-transpile/src/translator/mod.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3408,7 +3408,20 @@ impl<'c> Translation<'c> {
34083408
val = transmute_expr(actual_ty, ty, val);
34093409
set_unsafe = true;
34103410
} else {
3411-
val = mk().cast_expr(val, ty);
3411+
let decl_kind = &self.ast_context[decl_id].kind;
3412+
let kind_with_declared_args =
3413+
self.ast_context.fn_decl_ty_with_declared_args(decl_kind);
3414+
3415+
if let Some(ty) = self
3416+
.ast_context
3417+
.type_for_kind(&kind_with_declared_args)
3418+
.map(CQualTypeId::new)
3419+
{
3420+
let ty = self.convert_type(ty.ctype)?;
3421+
val = mk().cast_expr(val, ty);
3422+
} else {
3423+
val = mk().cast_expr(val, ty);
3424+
}
34123425
}
34133426
}
34143427
}
@@ -3514,17 +3527,46 @@ impl<'c> Translation<'c> {
35143527
_ => {}
35153528
}
35163529

3517-
let source_ty = self.ast_context[expr]
3530+
let mut source_ty = self.ast_context[expr]
35183531
.kind
35193532
.get_qual_type()
35203533
.ok_or_else(|| format_err!("bad source type"))?;
35213534

35223535
let val = if is_explicit {
3536+
// If we're casting a function, look for its declared ty to use as a more
3537+
// precise source type. The AST node's type will not preserve typedef arg types
3538+
// but the function's declaration will.
3539+
if let Some(func_decl) = self.ast_context.function_declref_decl(expr) {
3540+
let kind_with_declared_args =
3541+
self.ast_context.fn_decl_ty_with_declared_args(func_decl);
3542+
let func_ty = self
3543+
.ast_context
3544+
.type_for_kind(&kind_with_declared_args)
3545+
.expect(&format!("no type for kind {kind_with_declared_args:?}"));
3546+
let func_ptr_ty = self
3547+
.ast_context
3548+
.type_for_kind(&CTypeKind::Pointer(CQualTypeId::new(func_ty)))
3549+
.expect(&format!("no type for kind {kind_with_declared_args:?}"));
3550+
3551+
source_ty = CQualTypeId::new(func_ptr_ty);
3552+
}
3553+
35233554
let stmts = self.compute_variable_array_sizes(ctx, ty.ctype)?;
35243555
let mut val = self.convert_expr(ctx, expr, None)?;
35253556
val.prepend_stmts(stmts);
35263557
val
35273558
} else {
3559+
// Cast the return types of functions whose return types are synthetic.
3560+
if let Some(func_decl) = self.ast_context.function_declref_decl(expr) {
3561+
let kind_with_declared_args =
3562+
self.ast_context.fn_decl_ty_with_declared_args(func_decl);
3563+
let func_ty = self
3564+
.ast_context
3565+
.type_for_kind(&kind_with_declared_args)
3566+
.expect(&format!("no type for kind {kind_with_declared_args:?}"));
3567+
source_ty = CQualTypeId::new(func_ty);
3568+
}
3569+
35283570
// In general, if we are casting the result of an expression, then the inner
35293571
// expression should be translated to whatever type it normally would.
35303572
// But for literals, if we don't absolutely have to cast, we would rather the
@@ -3537,7 +3579,13 @@ impl<'c> Translation<'c> {
35373579
return self.convert_expr(ctx, expr, override_ty);
35383580
}
35393581
}
3540-
self.convert_expr(ctx, expr, None)?
3582+
if kind == CastKind::LValueToRValue
3583+
&& Some(source_ty.ctype) != override_ty.map(|x| x.ctype)
3584+
{
3585+
self.convert_expr(ctx, expr, override_ty)?
3586+
} else {
3587+
self.convert_expr(ctx, expr, None)?
3588+
}
35413589
};
35423590
// Shuffle Vector "function" builtins will add a cast to the output of the
35433591
// builtin call which is unnecessary for translation purposes

0 commit comments

Comments
 (0)