Skip to content

Commit 777d9f7

Browse files
committed
transpile: let can_propagate_cast handle casting EnumConstant to its own enum
1 parent f302c0f commit 777d9f7

4 files changed

Lines changed: 52 additions & 40 deletions

File tree

c2rust-transpile/src/c_ast/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,14 @@ impl TypedAstContext {
751751
Decayed(ty) => ty,
752752
TypeOf(ty) => ty,
753753
Paren(ty) => ty,
754+
755+
// As an exception, resolve typedefs in `prenamed_decls`, because they do not
756+
// get translated as type aliases in the final code.
757+
Typedef(decl) if self.prenamed_decls.contains_key(&decl) => match self[decl].kind {
758+
CDeclKind::Typedef { typ: ty, .. } => ty.ctype,
759+
_ => panic!("Typedef decl did not point to a typedef"),
760+
},
761+
754762
_ => return typ,
755763
};
756764
self.resolve_type_id_no_typedef(ty)

c2rust-transpile/src/translator/enums.rs

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use syn::Expr;
55
use crate::c_ast::CUnOp;
66
use crate::{
77
diagnostics::TranslationResult,
8-
translator::{signed_int_expr, ConvertedDecl, ExprContext, Translation},
8+
translator::{signed_int_expr, ConvertedDecl, Translation},
99
with_stmts::WithStmts,
1010
CDeclKind, CEnumConstantId, CEnumId, CExprId, CExprKind, CLiteral, CQualTypeId, CTypeId,
1111
CTypeKind, ConstIntExpr,
@@ -75,37 +75,14 @@ impl<'c> Translation<'c> {
7575
}
7676

7777
/// Translate a cast where the target type is an `enum` type.
78-
///
79-
/// When translating variable references to `EnumConstant`s, we always insert casts to the
80-
/// expected type. In C, `EnumConstant`s have some integral type, _not_ the enum type. However,
81-
/// if we then immediately have a cast to convert this variable back into an enum type, we would
82-
/// like to produce Rust with _no_ casts. This function handles this simplification.
8378
pub fn convert_cast_to_enum(
8479
&self,
85-
ctx: ExprContext,
8680
enum_type_id: CTypeId,
87-
enum_id: CEnumId,
8881
expr: Option<CExprId>,
8982
val: Box<Expr>,
9083
) -> TranslationResult<Box<Expr>> {
9184
if let Some(expr) = expr {
9285
match self.ast_context[expr].kind {
93-
// This is the case of finding a variable which is an `EnumConstant` of the same
94-
// enum we are casting to. Here, we can just remove the extraneous cast instead of
95-
// generating a new one.
96-
CExprKind::DeclRef(_, enum_constant_id, _)
97-
if self.is_variant_of_enum(enum_id, enum_constant_id) =>
98-
{
99-
// `enum`s shouldn't need portable `override_ty`s.
100-
let expr_is_macro = self.expr_is_expanded_macro(ctx, expr, None);
101-
102-
// If this DeclRef expanded to a const macro, we actually need to insert a cast,
103-
// because the translation of a const macro skips implicit casts in its context.
104-
if !expr_is_macro {
105-
return Ok(self.enum_constant_expr(enum_constant_id));
106-
}
107-
}
108-
10986
CExprKind::Literal(_, CLiteral::Integer(i, _)) => {
11087
return Ok(self.enum_for_i64(enum_type_id, i as i64));
11188
}
@@ -173,13 +150,17 @@ impl<'c> Translation<'c> {
173150
mk().ident_expr(name)
174151
}
175152

176-
fn is_variant_of_enum(&self, enum_id: CEnumId, enum_constant_id: CEnumConstantId) -> bool {
177-
let variants = match self.ast_context[enum_id].kind {
178-
CDeclKind::Enum { ref variants, .. } => variants,
179-
_ => panic!("{:?} does not point to an `enum` declaration", enum_id),
153+
pub fn enum_constant_matches_type(
154+
&self,
155+
type_id: CTypeId,
156+
enum_constant_id: CEnumConstantId,
157+
) -> bool {
158+
let type_enum_id = match self.ast_context.resolve_type_no_typedef(type_id).kind {
159+
CTypeKind::Enum(enum_id) => enum_id,
160+
_ => return false,
180161
};
181-
182-
variants.contains(&enum_constant_id)
162+
let constant_enum_id = self.ast_context.parents[&enum_constant_id];
163+
type_enum_id == constant_enum_id
183164
}
184165

185166
fn enum_integral_type(&self, enum_id: CEnumId) -> CQualTypeId {

c2rust-transpile/src/translator/mod.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,7 +3104,13 @@ impl<'c> Translation<'c> {
31043104
// If the variable is actually an `EnumConstant`, we need to add a cast to the
31053105
// expected integral type.
31063106
if let &CDeclKind::EnumConstant { .. } = decl {
3107-
val = self.convert_cast_from_enum(qual_ty.ctype, val)?;
3107+
if !self
3108+
.enum_constant_matches_type(override_ty.unwrap_or(qual_ty).ctype, decl_id)
3109+
{
3110+
val = self.convert_cast_from_enum(qual_ty.ctype, val)?;
3111+
}
3112+
3113+
return Ok(WithStmts::new_val(val));
31083114
}
31093115

31103116
// If we are referring to a function and need its address, we
@@ -3246,7 +3252,7 @@ impl<'c> Translation<'c> {
32463252
// But for some expression types, if we don't absolutely have to cast,
32473253
// we would rather the expression is translated according to the type we're
32483254
// expecting, and then we can skip the cast entirely.
3249-
if self.can_propagate_cast(expr, target_ty, is_explicit) {
3255+
if self.can_propagate_cast(ctx, expr, target_ty, is_explicit) {
32503256
return self.convert_expr(ctx, expr, Some(target_ty));
32513257
}
32523258

@@ -3517,6 +3523,7 @@ impl<'c> Translation<'c> {
35173523

35183524
fn can_propagate_cast(
35193525
&self,
3526+
ctx: ExprContext,
35203527
expr_id: CExprId,
35213528
target_type_id: CQualTypeId,
35223529
is_explicit: bool,
@@ -3527,6 +3534,26 @@ impl<'c> Translation<'c> {
35273534
}
35283535

35293536
let expr_kind = &self.ast_context[expr_id].kind;
3537+
3538+
if let &CExprKind::DeclRef(_, decl_id, _) = expr_kind {
3539+
if let CDeclKind::EnumConstant { .. } = self.ast_context[decl_id].kind {
3540+
// In C, `EnumConstant`s have some integral type, _not_ the enum type.
3541+
// However, if we then immediately have a cast to convert this variable back into
3542+
// the enum type, we would like to produce Rust with _no_ casts.
3543+
if self.enum_constant_matches_type(target_type_id.ctype, decl_id) {
3544+
// `enum`s shouldn't need portable `override_ty`s.
3545+
let expr_is_macro = self.expr_is_expanded_macro(ctx, expr_id, None);
3546+
3547+
// If this DeclRef expanded to a const macro, we actually need to insert
3548+
// a cast, because the translation of a const macro skips implicit casts
3549+
// in its context.
3550+
if !expr_is_macro {
3551+
return true;
3552+
}
3553+
}
3554+
}
3555+
}
3556+
35303557
let mut literal_expr_kind = expr_kind;
35313558
let mut is_negated = false;
35323559

@@ -3753,11 +3780,9 @@ impl<'c> Translation<'c> {
37533780
self.ast_context[source_cty.ctype].kind
37543781
{
37553782
self.f128_cast_to(val, target_ty_kind)
3756-
} else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind {
3783+
} else if let &CTypeKind::Enum(_) = target_ty_kind {
37573784
// Casts targeting `enum` types...
3758-
val.result_map(|val| {
3759-
self.convert_cast_to_enum(ctx, target_cty.ctype, enum_decl_id, expr, val)
3760-
})
3785+
val.result_map(|val| self.convert_cast_to_enum(target_cty.ctype, expr, val))
37613786
} else if target_ty_kind.is_floating_type() && source_ty_kind.is_bool() {
37623787
Ok(val.map(|val| {
37633788
mk().cast_expr(mk().cast_expr(val, mk().path_ty(vec!["u8"])), target_ty)

c2rust-transpile/src/translator/pointers.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -533,10 +533,8 @@ impl<'c> Translation<'c> {
533533
source_ty, target_ty, val,
534534
)))
535535
})
536-
} else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind {
537-
val.result_map(|val| {
538-
self.convert_cast_to_enum(ctx, target_cty, enum_decl_id, expr, val)
539-
})
536+
} else if let &CTypeKind::Enum(_) = target_ty_kind {
537+
val.result_map(|val| self.convert_cast_to_enum(target_cty, expr, val))
540538
} else {
541539
Ok(val.map(|val| mk().cast_expr(val, target_ty)))
542540
}

0 commit comments

Comments
 (0)