From 855bf10c3df329b57d51a453b6dbd2bc9fbf9d4d Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 26 Apr 2026 12:27:43 +0200 Subject: [PATCH 1/8] transpile: Split off `convert_decl_ref` --- c2rust-transpile/src/translator/mod.rs | 267 +++++++++++++------------ 1 file changed, 138 insertions(+), 129 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 2661fc1ef5..482a4cbab5 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3070,135 +3070,9 @@ impl<'c> Translation<'c> { } } - DeclRef(qual_ty, decl_id, lrvalue) => { - let decl = &self - .ast_context - .get_decl(&decl_id) - .ok_or_else(|| format_err!("Missing declref {:?}", decl_id))? - .kind; - if ctx.expanding_macro.is_some() { - // TODO Determining which declarations have been declared within the scope of the const macro expr - // vs. which are out-of-scope of the const macro is non-trivial, - // so for now, we don't allow const macros referencing any declarations. - return Err(format_translation_err!( - self.ast_context.display_loc(src_loc), - "Cannot yet refer to declarations in a const expr", - )); - - #[allow(unreachable_code)] // TODO temporary (see above). - if let CDeclKind::Variable { - has_static_duration: true, - .. - } = decl - { - return Err(format_translation_err!( - self.ast_context.display_loc(src_loc), - "Cannot refer to static duration variable in a const expression", - )); - } - } - - let varname = decl.get_name().expect("expected variable name").to_owned(); - let rustname = self - .renamer - .borrow_mut() - .get(&decl_id) - .ok_or_else(|| format_err!("name not declared: '{}'", varname))?; - - // Import the referenced global decl into our submodule - if self.tcfg.reorganize_definitions { - self.add_import(decl_id, &rustname); - // match decl { - // CDeclKind::Variable { is_defn: false, .. } => {} - // _ => self.add_import(decl_id, &rustname), - // } - } - - let mut val = mk().path_expr(vec![rustname]); - let mut set_unsafe = false; - - match decl { - CDeclKind::EnumConstant { .. } => { - // If the variable is actually an `EnumConstant`, we need to add a cast to - // the expected integral type. - val = self.convert_cast_from_enum(qual_ty.ctype, val)?; - } - - CDeclKind::Function { parameters, .. } => { - // If we are referring to a function and need its address, we - // need to cast it to fn() to ensure that it has a real address. - if ctx.needs_address() { - let ty = self.convert_type(qual_ty.ctype)?; - let actual_ty = self - .type_converter - .borrow_mut() - .knr_function_type_with_parameters( - &self.ast_context, - qual_ty.ctype, - parameters, - )?; - if let Some(actual_ty) = actual_ty { - if actual_ty != ty { - // If we're casting a concrete function to - // a K&R function pointer type, use transmute - self.import_type(qual_ty.ctype); - - val = transmute_expr(actual_ty, ty, val); - set_unsafe = true; - } - } else { - let decl_kind = &self.ast_context[decl_id].kind; - let kind_with_declared_args = - self.ast_context.fn_decl_ty_with_declared_args(decl_kind); - - if let Some(ty) = self - .ast_context - .type_for_kind(&kind_with_declared_args) - .map(CQualTypeId::new) - { - let ty = self.convert_type(ty.ctype)?; - val = mk().cast_expr(val, ty); - } else { - val = mk().cast_expr(val, ty); - } - } - } - } - - CDeclKind::Variable { - has_static_duration, - has_thread_duration, - .. - } => { - // Accessing a static variable is unsafe. - // In the current nightly, this applies also to taking a raw pointer, - // but this requirement was removed in later versions of the - // `raw_ref_op` feature. - if (*has_static_duration || *has_thread_duration) - && (self.tcfg.edition < Edition2024 || !ctx.needs_address()) - { - set_unsafe = true; - } - } - - _ => {} - } - - if let CTypeKind::VariableArray(..) = - self.ast_context.resolve_type(qual_ty.ctype).kind - { - val = mk().method_call_expr(val, "as_mut_ptr", vec![]); - } - - // if the context wants a different type, add a cast - if let Some(expected_ty) = override_ty { - if lrvalue.is_rvalue() && expected_ty != qual_ty { - val = mk().cast_expr(val, self.convert_type(expected_ty.ctype)?); - } - } - - Ok(WithStmts::new_val(val).merge_unsafe(set_unsafe)) - } + DeclRef(qual_ty, decl_id, lrvalue) => self + .convert_decl_ref(ctx, override_ty, qual_ty, decl_id, lrvalue) + .map_err(|e| e.add_loc(self.ast_context.display_loc(src_loc))), OffsetOf(ty, ref kind) => match kind { OffsetOfKind::Constant(val) => Ok(WithStmts::new_val(self.mk_int_lit( @@ -3526,6 +3400,141 @@ impl<'c> Translation<'c> { } } + fn convert_decl_ref( + &self, + ctx: ExprContext, + override_ty: Option, + qual_ty: CQualTypeId, + decl_id: CDeclId, + lrvalue: LRValue, + ) -> TranslationResult>> { + let decl = &self + .ast_context + .get_decl(&decl_id) + .ok_or_else(|| format_err!("Missing declref {:?}", decl_id))? + .kind; + if ctx.expanding_macro.is_some() { + // TODO Determining which declarations have been declared within the scope of the const macro expr + // vs. which are out-of-scope of the const macro is non-trivial, + // so for now, we don't allow const macros referencing any declarations. + return Err(format_translation_err!( + None, + "Cannot yet refer to declarations in a const expr", + )); + + #[allow(unreachable_code)] // TODO temporary (see above). + if let CDeclKind::Variable { + has_static_duration: true, + .. + } = decl + { + return Err(format_translation_err!( + None, + "Cannot refer to static duration variable in a const expression", + )); + } + } + + let varname = decl.get_name().expect("expected variable name").to_owned(); + let rustname = self + .renamer + .borrow_mut() + .get(&decl_id) + .ok_or_else(|| format_err!("name not declared: '{}'", varname))?; + + // Import the referenced global decl into our submodule + if self.tcfg.reorganize_definitions { + self.add_import(decl_id, &rustname); + // match decl { + // CDeclKind::Variable { is_defn: false, .. } => {} + // _ => self.add_import(decl_id, &rustname), + // } + } + + let mut val = mk().path_expr(vec![rustname]); + let mut set_unsafe = false; + + match decl { + CDeclKind::EnumConstant { .. } => { + // If the variable is actually an `EnumConstant`, we need to add a cast to + // the expected integral type. + val = self.convert_cast_from_enum(qual_ty.ctype, val)?; + } + + CDeclKind::Function { parameters, .. } => { + // If we are referring to a function and need its address, we + // need to cast it to fn() to ensure that it has a real address. + if ctx.needs_address() { + let ty = self.convert_type(qual_ty.ctype)?; + let actual_ty = self + .type_converter + .borrow_mut() + .knr_function_type_with_parameters( + &self.ast_context, + qual_ty.ctype, + parameters, + )?; + if let Some(actual_ty) = actual_ty { + if actual_ty != ty { + // If we're casting a concrete function to + // a K&R function pointer type, use transmute + self.import_type(qual_ty.ctype); + + val = transmute_expr(actual_ty, ty, val); + set_unsafe = true; + } + } else { + let decl_kind = &self.ast_context[decl_id].kind; + let kind_with_declared_args = + self.ast_context.fn_decl_ty_with_declared_args(decl_kind); + + if let Some(ty) = self + .ast_context + .type_for_kind(&kind_with_declared_args) + .map(CQualTypeId::new) + { + let ty = self.convert_type(ty.ctype)?; + val = mk().cast_expr(val, ty); + } else { + val = mk().cast_expr(val, ty); + } + } + } + } + + CDeclKind::Variable { + has_static_duration, + has_thread_duration, + .. + } => { + // Accessing a static variable is unsafe. + // In the current nightly, this applies also to taking a raw pointer, + // but this requirement was removed in later versions of the + // `raw_ref_op` feature. + if (*has_static_duration || *has_thread_duration) + && (self.tcfg.edition < Edition2024 || !ctx.needs_address()) + { + set_unsafe = true; + } + } + + _ => {} + } + + if let CTypeKind::VariableArray(..) = self.ast_context.resolve_type(qual_ty.ctype).kind { + val = mk().method_call_expr(val, "as_mut_ptr", vec![]); + } + + // if the context wants a different type, add a cast + if let Some(expected_ty) = override_ty { + if lrvalue.is_rvalue() && expected_ty != qual_ty { + val = mk().cast_expr(val, self.convert_type(expected_ty.ctype)?); + } + } + + Ok(WithStmts::new_val(val).merge_unsafe(set_unsafe)) + } + pub fn convert_constant(&self, constant: ConstIntExpr) -> TranslationResult> { let expr = match constant { ConstIntExpr::U(n) => mk().lit_expr(mk().int_unsuffixed_lit(n as u128)), From 9e20cd4962e0b545b01e398ffe0be415dee065c2 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 25 Apr 2026 21:35:42 +0200 Subject: [PATCH 2/8] transpile: Modify enum/pointer cast methods to take `CQualTypeId` and return `WithStmts` --- c2rust-transpile/src/translator/enums.rs | 33 +++++++++------ c2rust-transpile/src/translator/mod.rs | 23 ++++------- c2rust-transpile/src/translator/pointers.rs | 46 +++++++++++---------- 3 files changed, 53 insertions(+), 49 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index 88a9045b13..a4438b459d 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -66,12 +66,14 @@ impl<'c> Translation<'c> { /// Translate a cast where the source type, but not the target type, is an `enum` type. pub fn convert_cast_from_enum( &self, - target_cty: CTypeId, - val: Box, - ) -> TranslationResult> { + target_cty: CQualTypeId, + mut val: Box, + ) -> TranslationResult>> { // Convert it to the expected integral type. - let ty = self.convert_type(target_cty)?; - Ok(mk().cast_expr(val, ty)) + let ty = self.convert_type(target_cty.ctype)?; + val = mk().cast_expr(val, ty); + + Ok(WithStmts::new_val(val)) } /// Translate a cast where the target type is an `enum` type. @@ -83,11 +85,11 @@ impl<'c> Translation<'c> { pub fn convert_cast_to_enum( &self, ctx: ExprContext, - enum_type_id: CTypeId, + enum_type_id: CQualTypeId, enum_id: CEnumId, expr: Option, - val: Box, - ) -> TranslationResult> { + mut val: Box, + ) -> TranslationResult>> { if let Some(expr) = expr { match self.ast_context.index_unwrap_parens(expr).kind { // This is the case of finding a variable which is an `EnumConstant` of the same @@ -102,19 +104,22 @@ impl<'c> Translation<'c> { // If this DeclRef expanded to a const macro, we actually need to insert a cast, // because the translation of a const macro skips implicit casts in its context. if !expr_is_macro { - return Ok(self.enum_constant_expr(enum_constant_id)); + val = self.enum_constant_expr(enum_constant_id); + return Ok(WithStmts::new_val(val)); } } CExprKind::Literal(_, CLiteral::Integer(i, _)) => { - return Ok(self.enum_for_i64(enum_type_id, i as i64)); + val = self.enum_for_i64(enum_type_id.ctype, i as i64); + return Ok(WithStmts::new_val(val)); } CExprKind::Unary(_, CUnOp::Negate, subexpr_id, _) => { if let &CExprKind::Literal(_, CLiteral::Integer(i, _)) = &self.ast_context.index_unwrap_parens(subexpr_id).kind { - return Ok(self.enum_for_i64(enum_type_id, -(i as i64))); + val = self.enum_for_i64(enum_type_id.ctype, -(i as i64)); + return Ok(WithStmts::new_val(val)); } } @@ -122,8 +127,10 @@ impl<'c> Translation<'c> { } } - let target_ty = self.convert_type(enum_type_id)?; - Ok(mk().cast_expr(val, target_ty)) + let target_ty = self.convert_type(enum_type_id.ctype)?; + val = mk().cast_expr(val, target_ty); + + Ok(WithStmts::new_val(val)) } /// Given an integer value this attempts to either generate the corresponding enum diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 482a4cbab5..a2ba1d5efe 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3458,7 +3458,7 @@ impl<'c> Translation<'c> { CDeclKind::EnumConstant { .. } => { // If the variable is actually an `EnumConstant`, we need to add a cast to // the expected integral type. - val = self.convert_cast_from_enum(qual_ty.ctype, val)?; + return self.convert_cast_from_enum(qual_ty, val); } CDeclKind::Function { parameters, .. } => { @@ -3693,20 +3693,16 @@ impl<'c> Translation<'c> { match kind { CastKind::BitCast | CastKind::NoOp => { - self.convert_pointer_to_pointer_cast(source_cty.ctype, target_cty.ctype, val) + self.convert_pointer_to_pointer_cast(source_cty, target_cty, val) } CastKind::IntegralToPointer => { - self.convert_integral_to_pointer_cast(ctx, source_cty.ctype, target_cty.ctype, val) + self.convert_integral_to_pointer_cast(ctx, source_cty, target_cty, val) } - CastKind::PointerToIntegral => self.convert_pointer_to_integral_cast( - ctx, - source_cty.ctype, - target_cty.ctype, - val, - expr, - ), + CastKind::PointerToIntegral => { + self.convert_pointer_to_integral_cast(ctx, source_cty, target_cty, val, expr) + } CastKind::IntegralCast | CastKind::FloatingCast @@ -3741,16 +3737,15 @@ impl<'c> Translation<'c> { { self.f128_cast_to(val, target_ty_kind) } else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind { - // Casts targeting `enum` types... - val.try_map(|val| { - self.convert_cast_to_enum(ctx, target_cty.ctype, enum_decl_id, expr, val) + val.and_then_try(|val| { + self.convert_cast_to_enum(ctx, target_cty, enum_decl_id, expr, val) }) } else if target_ty_kind.is_floating_type() && source_ty_kind.is_bool() { Ok(val.map(|val| { mk().cast_expr(mk().cast_expr(val, mk().path_ty(vec!["u8"])), target_ty) })) } else if let &CTypeKind::Enum(..) = source_ty_kind { - val.try_map(|val| self.convert_cast_from_enum(target_cty.ctype, val)) + val.and_then_try(|val| self.convert_cast_from_enum(target_cty, val)) } else { Ok(val.map(|val| mk().cast_expr(val, target_ty))) } diff --git a/c2rust-transpile/src/translator/pointers.rs b/c2rust-transpile/src/translator/pointers.rs index 5428ce9e6b..9b5cdd6cfb 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -426,35 +426,35 @@ impl<'c> Translation<'c> { pub fn convert_pointer_to_pointer_cast( &self, - source_cty: CTypeId, - target_cty: CTypeId, + source_cty: CQualTypeId, + target_cty: CQualTypeId, val: WithStmts>, ) -> TranslationResult>> { - if self.ast_context.is_function_pointer(target_cty) - || self.ast_context.is_function_pointer(source_cty) + if self.ast_context.is_function_pointer(target_cty.ctype) + || self.ast_context.is_function_pointer(source_cty.ctype) { let source_ty = self .type_converter .borrow_mut() - .convert(&self.ast_context, source_cty)?; + .convert(&self.ast_context, source_cty.ctype)?; let target_ty = self .type_converter .borrow_mut() - .convert(&self.ast_context, target_cty)?; + .convert(&self.ast_context, target_cty.ctype)?; if source_ty == target_ty { return Ok(val); } - self.import_type(source_cty); - self.import_type(target_cty); + self.import_type(source_cty.ctype); + self.import_type(target_cty.ctype); Ok(val.and_then(|val| { WithStmts::new_val(transmute_expr(source_ty, target_ty, val)).set_unsafe() })) } else { // Normal case - let target_ty = self.convert_type(target_cty)?; + let target_ty = self.convert_type(target_cty.ctype)?; Ok(val.map(|val| mk().cast_expr(val, target_ty))) } } @@ -462,14 +462,14 @@ impl<'c> Translation<'c> { pub fn convert_integral_to_pointer_cast( &self, ctx: ExprContext, - source_cty: CTypeId, - target_cty: CTypeId, + source_cty: CQualTypeId, + target_cty: CQualTypeId, val: WithStmts>, ) -> TranslationResult>> { - let source_ty_kind = &self.ast_context.resolve_type(source_cty).kind; - let target_ty = self.convert_type(target_cty)?; + let source_ty_kind = &self.ast_context.resolve_type(source_cty.ctype).kind; + let target_ty = self.convert_type(target_cty.ctype)?; - if self.ast_context.is_function_pointer(target_cty) { + if self.ast_context.is_function_pointer(target_cty.ctype) { if ctx.is_const { return Err(format_translation_err!( None, @@ -493,7 +493,7 @@ impl<'c> Translation<'c> { mk().cast_expr(val, target_ty) })) } else if let &CTypeKind::Enum(..) = source_ty_kind { - val.try_map(|val| self.convert_cast_from_enum(target_cty, val)) + val.and_then_try(|val| self.convert_cast_from_enum(target_cty, val)) } else { Ok(val.map(|val| mk().cast_expr(val, target_ty))) } @@ -502,8 +502,8 @@ impl<'c> Translation<'c> { pub fn convert_pointer_to_integral_cast( &self, ctx: ExprContext, - source_cty: CTypeId, - target_cty: CTypeId, + source_cty: CQualTypeId, + target_cty: CQualTypeId, val: WithStmts>, expr: Option, ) -> TranslationResult>> { @@ -514,16 +514,18 @@ impl<'c> Translation<'c> { )); } - let target_ty = self.convert_type(target_cty)?; - let source_ty = self.convert_type(source_cty)?; - let target_ty_kind = &self.ast_context.resolve_type(target_cty).kind; + let target_ty = self.convert_type(target_cty.ctype)?; + let source_ty = self.convert_type(source_cty.ctype)?; + let target_ty_kind = &self.ast_context.resolve_type(target_cty.ctype).kind; - if self.ast_context.is_function_pointer(source_cty) { + if self.ast_context.is_function_pointer(source_cty.ctype) { Ok(val.and_then(|val| { WithStmts::new_val(transmute_expr(source_ty, target_ty, val)).set_unsafe() })) } else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind { - val.try_map(|val| self.convert_cast_to_enum(ctx, target_cty, enum_decl_id, expr, val)) + val.and_then_try(|val| { + self.convert_cast_to_enum(ctx, target_cty, enum_decl_id, expr, val) + }) } else { Ok(val.map(|val| mk().cast_expr(val, target_ty))) } From 2c21205148940707784f349c71b1e67198383d74 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 19:20:40 +0200 Subject: [PATCH 3/8] transpile: Add `convert_enum_constant_decl_ref` --- c2rust-transpile/src/translator/enums.rs | 12 ++++++++++++ c2rust-transpile/src/translator/mod.rs | 10 ++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index a4438b459d..3bbb95ebe9 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -63,6 +63,18 @@ impl<'c> Translation<'c> { WithStmts::new_val(self.enum_for_i64(type_id, 0)) } + /// Translates a `DeclRef` for an `EnumConstant`. + pub fn convert_enum_constant_decl_ref( + &self, + enum_constant_id: CEnumConstantId, + target_type_id: CQualTypeId, + ) -> TranslationResult>> { + let val = self.enum_constant_expr(enum_constant_id); + + // Add a cast to the expected integral type. + self.convert_cast_from_enum(target_type_id, val) + } + /// Translate a cast where the source type, but not the target type, is an `enum` type. pub fn convert_cast_from_enum( &self, diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index a2ba1d5efe..c38aa381fb 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3435,6 +3435,10 @@ impl<'c> Translation<'c> { } } + if let CDeclKind::EnumConstant { .. } = decl { + return self.convert_enum_constant_decl_ref(decl_id, qual_ty); + } + let varname = decl.get_name().expect("expected variable name").to_owned(); let rustname = self .renamer @@ -3455,12 +3459,6 @@ impl<'c> Translation<'c> { let mut set_unsafe = false; match decl { - CDeclKind::EnumConstant { .. } => { - // If the variable is actually an `EnumConstant`, we need to add a cast to - // the expected integral type. - return self.convert_cast_from_enum(qual_ty, val); - } - CDeclKind::Function { parameters, .. } => { // If we are referring to a function and need its address, we // need to cast it to fn() to ensure that it has a real address. From 8386804b2cf66a992bf3a9d7e936d2b27b0e924d Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 18:11:57 +0200 Subject: [PATCH 4/8] transpile: Add `enum_constructor_expr`, replace params accordingly --- c2rust-transpile/src/translator/enums.rs | 37 +++++++++++---------- c2rust-transpile/src/translator/mod.rs | 8 ++--- c2rust-transpile/src/translator/pointers.rs | 6 ++-- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index 3bbb95ebe9..6a4f0848af 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -7,8 +7,8 @@ use crate::{ diagnostics::TranslationResult, translator::{signed_int_expr, ConvertedDecl, ExprContext, Translation}, with_stmts::WithStmts, - CDeclKind, CEnumConstantId, CEnumId, CExprId, CExprKind, CLiteral, CQualTypeId, CTypeId, - CTypeKind, ConstIntExpr, + CDeclKind, CEnumConstantId, CEnumId, CExprId, CExprKind, CLiteral, CQualTypeId, CTypeKind, + ConstIntExpr, }; impl<'c> Translation<'c> { @@ -59,8 +59,8 @@ impl<'c> Translation<'c> { )) } - pub fn convert_enum_zero_initializer(&self, type_id: CTypeId) -> WithStmts> { - WithStmts::new_val(self.enum_for_i64(type_id, 0)) + pub fn convert_enum_zero_initializer(&self, enum_id: CEnumId) -> WithStmts> { + WithStmts::new_val(self.enum_for_i64(enum_id, 0)) } /// Translates a `DeclRef` for an `EnumConstant`. @@ -97,7 +97,6 @@ impl<'c> Translation<'c> { pub fn convert_cast_to_enum( &self, ctx: ExprContext, - enum_type_id: CQualTypeId, enum_id: CEnumId, expr: Option, mut val: Box, @@ -122,7 +121,7 @@ impl<'c> Translation<'c> { } CExprKind::Literal(_, CLiteral::Integer(i, _)) => { - val = self.enum_for_i64(enum_type_id.ctype, i as i64); + val = self.enum_for_i64(enum_id, i as i64); return Ok(WithStmts::new_val(val)); } @@ -130,7 +129,7 @@ impl<'c> Translation<'c> { if let &CExprKind::Literal(_, CLiteral::Integer(i, _)) = &self.ast_context.index_unwrap_parens(subexpr_id).kind { - val = self.enum_for_i64(enum_type_id.ctype, -(i as i64)); + val = self.enum_for_i64(enum_id, -(i as i64)); return Ok(WithStmts::new_val(val)); } } @@ -139,20 +138,14 @@ impl<'c> Translation<'c> { } } - let target_ty = self.convert_type(enum_type_id.ctype)?; - val = mk().cast_expr(val, target_ty); + val = self.enum_constructor_expr(enum_id, val); Ok(WithStmts::new_val(val)) } /// Given an integer value this attempts to either generate the corresponding enum /// variant directly, otherwise it converts a number to the enum type. - fn enum_for_i64(&self, enum_type_id: CTypeId, value: i64) -> Box { - let enum_id = match self.ast_context.resolve_type(enum_type_id).kind { - CTypeKind::Enum(enum_id) => enum_id, - _ => panic!("{:?} does not point to an `enum` type", enum_type_id), - }; - + fn enum_for_i64(&self, enum_id: CEnumId, value: i64) -> Box { if let Some(enum_constant_id) = self.enum_variant_for_i64(enum_id, value) { return self.enum_constant_expr(enum_constant_id); } @@ -164,8 +157,7 @@ impl<'c> Translation<'c> { _ => signed_int_expr(value), }; - let target_ty = self.convert_type(enum_type_id).unwrap(); - mk().cast_expr(value, target_ty) + self.enum_constructor_expr(enum_id, value) } /// Returns the id of the variant of `enum_id` whose value matches `value`, if any. @@ -192,6 +184,17 @@ impl<'c> Translation<'c> { mk().ident_expr(name) } + fn enum_constructor_expr(&self, enum_id: CEnumId, value: Box) -> Box { + let enum_name = self + .type_converter + .borrow() + .resolve_decl_name(enum_id) + .unwrap(); + self.add_import(enum_id, &enum_name); + + mk().cast_expr(value, mk().ident_ty(enum_name)) + } + fn is_variant_of_enum(&self, enum_id: CEnumId, enum_constant_id: CEnumConstantId) -> bool { let variants = match self.ast_context[enum_id].kind { CDeclKind::Enum { ref variants, .. } => variants, diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index c38aa381fb..a94b9fd49e 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3734,10 +3734,8 @@ impl<'c> Translation<'c> { self.ast_context[source_cty.ctype].kind { self.f128_cast_to(val, target_ty_kind) - } else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind { - val.and_then_try(|val| { - self.convert_cast_to_enum(ctx, target_cty, enum_decl_id, expr, val) - }) + } else if let &CTypeKind::Enum(enum_id) = target_ty_kind { + val.and_then_try(|val| self.convert_cast_to_enum(ctx, enum_id, expr, val)) } else if target_ty_kind.is_floating_type() && source_ty_kind.is_bool() { Ok(val.map(|val| { mk().cast_expr(mk().cast_expr(val, mk().path_ty(vec!["u8"])), target_ty) @@ -4009,7 +4007,7 @@ impl<'c> Translation<'c> { } // Transmute the number `0` into the enum type - CDeclKind::Enum { .. } => self.convert_enum_zero_initializer(type_id), + CDeclKind::Enum { .. } => self.convert_enum_zero_initializer(decl_id), _ => { return Err(TranslationError::generic( diff --git a/c2rust-transpile/src/translator/pointers.rs b/c2rust-transpile/src/translator/pointers.rs index 9b5cdd6cfb..ce859fd010 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -522,10 +522,8 @@ impl<'c> Translation<'c> { Ok(val.and_then(|val| { WithStmts::new_val(transmute_expr(source_ty, target_ty, val)).set_unsafe() })) - } else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind { - val.and_then_try(|val| { - self.convert_cast_to_enum(ctx, target_cty, enum_decl_id, expr, val) - }) + } else if let &CTypeKind::Enum(enum_id) = target_ty_kind { + val.and_then_try(|val| self.convert_cast_to_enum(ctx, enum_id, expr, val)) } else { Ok(val.map(|val| mk().cast_expr(val, target_ty))) } From fc1776e1a7bd7c7b6e181c3d8bb587134c4025ed Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 17:26:21 +0200 Subject: [PATCH 5/8] transpile: Cast enums only if actually needed --- c2rust-transpile/src/translator/enums.rs | 48 +++++++++++++++---- c2rust-transpile/src/translator/mod.rs | 12 +++-- c2rust-transpile/src/translator/pointers.rs | 6 +-- ...shots__transpile@exprs.c.2021.clang15.snap | 2 +- ...shots__transpile@exprs.c.2024.clang15.snap | 2 +- ...s__transpile@macrocase.c.2021.clang15.snap | 2 +- ...s__transpile@macrocase.c.2024.clang15.snap | 2 +- 7 files changed, 54 insertions(+), 20 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index 6a4f0848af..b0c1eeea76 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -66,26 +66,36 @@ impl<'c> Translation<'c> { /// Translates a `DeclRef` for an `EnumConstant`. pub fn convert_enum_constant_decl_ref( &self, + ctx: ExprContext, enum_constant_id: CEnumConstantId, target_type_id: CQualTypeId, ) -> TranslationResult>> { + let enum_id = self.ast_context.parents[&enum_constant_id]; let val = self.enum_constant_expr(enum_constant_id); // Add a cast to the expected integral type. - self.convert_cast_from_enum(target_type_id, val) + self.convert_cast_from_enum(ctx, enum_id, target_type_id, val) } /// Translate a cast where the source type, but not the target type, is an `enum` type. pub fn convert_cast_from_enum( &self, + ctx: ExprContext, + enum_id: CEnumId, target_cty: CQualTypeId, - mut val: Box, + val: Box, ) -> TranslationResult>> { - // Convert it to the expected integral type. - let ty = self.convert_type(target_cty.ctype)?; - val = mk().cast_expr(val, ty); - - Ok(WithStmts::new_val(val)) + // Cast from the enum's integral type to the expected integral type. + let source_cty = self.enum_integral_type(enum_id); + self.convert_cast( + ctx, + source_cty, + target_cty, + WithStmts::new_val(val), + None, + None, + None, + ) } /// Translate a cast where the target type is an `enum` type. @@ -97,6 +107,7 @@ impl<'c> Translation<'c> { pub fn convert_cast_to_enum( &self, ctx: ExprContext, + mut source_cty: CQualTypeId, enum_id: CEnumId, expr: Option, mut val: Box, @@ -138,9 +149,28 @@ impl<'c> Translation<'c> { } } - val = self.enum_constructor_expr(enum_id, val); + // We could be casting from enum to enum... + if let CTypeKind::Enum(source_enum_id) = + self.ast_context.resolve_type(source_cty.ctype).kind + { + // Casting to ourselves, the audacity! + if source_enum_id == enum_id { + return Ok(WithStmts::new_val(val)); + } + + source_cty = self.enum_integral_type(source_enum_id); + } + + let enum_integral_type = self.enum_integral_type(enum_id); + let mut val = WithStmts::new_val(val); + let source_type_kind = &self.ast_context.resolve_type(source_cty.ctype).kind; + let enum_integral_type_kind = &self.ast_context.resolve_type(enum_integral_type.ctype).kind; + + if source_type_kind != enum_integral_type_kind { + val = val.map(|val| self.enum_constructor_expr(enum_id, val)); + } - Ok(WithStmts::new_val(val)) + Ok(val) } /// Given an integer value this attempts to either generate the corresponding enum diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index a94b9fd49e..af007358d9 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3436,7 +3436,7 @@ impl<'c> Translation<'c> { } if let CDeclKind::EnumConstant { .. } = decl { - return self.convert_enum_constant_decl_ref(decl_id, qual_ty); + return self.convert_enum_constant_decl_ref(ctx, decl_id, qual_ty); } let varname = decl.get_name().expect("expected variable name").to_owned(); @@ -3735,13 +3735,17 @@ impl<'c> Translation<'c> { { self.f128_cast_to(val, target_ty_kind) } else if let &CTypeKind::Enum(enum_id) = target_ty_kind { - val.and_then_try(|val| self.convert_cast_to_enum(ctx, enum_id, expr, val)) + val.and_then_try(|val| { + self.convert_cast_to_enum(ctx, source_cty, enum_id, expr, val) + }) } else if target_ty_kind.is_floating_type() && source_ty_kind.is_bool() { Ok(val.map(|val| { mk().cast_expr(mk().cast_expr(val, mk().path_ty(vec!["u8"])), target_ty) })) - } else if let &CTypeKind::Enum(..) = source_ty_kind { - val.and_then_try(|val| self.convert_cast_from_enum(target_cty, val)) + } else if let &CTypeKind::Enum(enum_id) = source_ty_kind { + val.and_then_try(|val| { + self.convert_cast_from_enum(ctx, enum_id, target_cty, val) + }) } else { Ok(val.map(|val| mk().cast_expr(val, target_ty))) } diff --git a/c2rust-transpile/src/translator/pointers.rs b/c2rust-transpile/src/translator/pointers.rs index ce859fd010..c23df41d9e 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -492,8 +492,8 @@ impl<'c> Translation<'c> { val = mk().cast_expr(val, mk().abs_path_ty(vec!["libc", "size_t"])); mk().cast_expr(val, target_ty) })) - } else if let &CTypeKind::Enum(..) = source_ty_kind { - val.and_then_try(|val| self.convert_cast_from_enum(target_cty, val)) + } else if let &CTypeKind::Enum(enum_id) = source_ty_kind { + val.and_then_try(|val| self.convert_cast_from_enum(ctx, enum_id, target_cty, val)) } else { Ok(val.map(|val| mk().cast_expr(val, target_ty))) } @@ -523,7 +523,7 @@ impl<'c> Translation<'c> { WithStmts::new_val(transmute_expr(source_ty, target_ty, val)).set_unsafe() })) } else if let &CTypeKind::Enum(enum_id) = target_ty_kind { - val.and_then_try(|val| self.convert_cast_to_enum(ctx, enum_id, expr, val)) + val.and_then_try(|val| self.convert_cast_to_enum(ctx, source_cty, enum_id, expr, val)) } else { Ok(val.map(|val| mk().cast_expr(val, target_ty))) } diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap index 56ee5f78bf..2f45733bbe 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap @@ -60,7 +60,7 @@ pub unsafe extern "C" fn unsigned_compound_desugaring() { let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; let mut u: ::core::ffi::c_uint = 0 as ::core::ffi::c_uint; let mut e: E = EA; - e = (e as ::core::ffi::c_uint).wrapping_add(u) as E; + e = e.wrapping_add(u); i = (i as ::core::ffi::c_uint).wrapping_add(u) as ::core::ffi::c_int; } #[no_mangle] diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap index 04e6019c9c..13e0833e62 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap @@ -60,7 +60,7 @@ pub unsafe extern "C" fn unsigned_compound_desugaring() { let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; let mut u: ::core::ffi::c_uint = 0 as ::core::ffi::c_uint; let mut e: E = EA; - e = (e as ::core::ffi::c_uint).wrapping_add(u) as E; + e = e.wrapping_add(u); i = (i as ::core::ffi::c_uint).wrapping_add(u) as ::core::ffi::c_int; } #[unsafe(no_mangle)] diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.clang15.snap index 07857d1fdf..50ff8785d9 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.clang15.snap @@ -18,7 +18,7 @@ pub const ZSTD_d_format: ::core::ffi::c_uint = 1000 as ::core::ffi::c_uint; #[no_mangle] pub unsafe extern "C" fn ZSTD_dParam_getBounds(mut dParam: ZSTD_dParameter) -> ::core::ffi::c_int { let mut bounds: ::core::ffi::c_int = 0 as ::core::ffi::c_int; - match dParam as ::core::ffi::c_uint { + match dParam { 100 => { bounds = 1 as ::core::ffi::c_int; return bounds; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.clang15.snap index cdf1b52d30..b4b6f37e89 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.clang15.snap @@ -19,7 +19,7 @@ pub const ZSTD_d_format: ::core::ffi::c_uint = 1000 as ::core::ffi::c_uint; #[unsafe(no_mangle)] pub unsafe extern "C" fn ZSTD_dParam_getBounds(mut dParam: ZSTD_dParameter) -> ::core::ffi::c_int { let mut bounds: ::core::ffi::c_int = 0 as ::core::ffi::c_int; - match dParam as ::core::ffi::c_uint { + match dParam { 100 => { bounds = 1 as ::core::ffi::c_int; return bounds; From feca2cd67c7777557f8389cd3dcd700bb6efdce4 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 18:31:55 +0200 Subject: [PATCH 6/8] transpile: Use correct types for enums in `convert_pre_increment` --- c2rust-transpile/src/translator/enums.rs | 2 +- c2rust-transpile/src/translator/operators.rs | 29 +++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index b0c1eeea76..a6eda2bae9 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -234,7 +234,7 @@ impl<'c> Translation<'c> { variants.contains(&enum_constant_id) } - fn enum_integral_type(&self, enum_id: CEnumId) -> CQualTypeId { + pub fn enum_integral_type(&self, enum_id: CEnumId) -> CQualTypeId { match self.ast_context[enum_id].kind { CDeclKind::Enum { integral_type: Some(integral_type), diff --git a/c2rust-transpile/src/translator/operators.rs b/c2rust-transpile/src/translator/operators.rs index 07d99e441f..16336aa4fc 100644 --- a/c2rust-transpile/src/translator/operators.rs +++ b/c2rust-transpile/src/translator/operators.rs @@ -640,26 +640,35 @@ impl<'c> Translation<'c> { _ => mk().lit_expr(mk().int_unsuffixed_lit(1)), }; - let one_type_id = - if let CTypeKind::Pointer(..) = self.ast_context.resolve_type(arg_type.ctype).kind { - CQualTypeId::new( + let mut rhs_type_id = arg_type; + let mut compute_lhs_type_id = arg_type; + let mut compute_res_type_id = ty; + + match self.ast_context.resolve_type(arg_type.ctype).kind { + CTypeKind::Pointer(..) => { + rhs_type_id = CQualTypeId::new( self.ast_context .type_for_kind(&CTypeKind::Int) .ok_or_else(|| format_err!("couldn't find type for CTypeKind::Int"))?, - ) - } else { - arg_type - }; + ); + } + CTypeKind::Enum(enum_id) => { + rhs_type_id = self.enum_integral_type(enum_id); + compute_lhs_type_id = rhs_type_id; + compute_res_type_id = rhs_type_id; + } + _ => {} + }; self.convert_assignment_operator_with_rhs( ctx.used(), op, ty, arg, - one_type_id, + rhs_type_id, WithStmts::new_val(one), - Some(arg_type), - Some(ty), + Some(compute_lhs_type_id), + Some(compute_res_type_id), ) } From b08a57273ccd706c7c0ae13907aadfbc4a8c43ea Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 17:37:55 +0200 Subject: [PATCH 7/8] transpile: Add `EnumMode` to select enum output type --- c2rust-transpile/src/lib.rs | 3 ++- c2rust-transpile/src/translator/enums.rs | 33 +++++++++++++++++------- c2rust-transpile/src/translator/mod.rs | 5 ++++ c2rust-transpile/tests/snapshots.rs | 4 +-- c2rust/src/bin/c2rust-transpile.rs | 3 ++- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/c2rust-transpile/src/lib.rs b/c2rust-transpile/src/lib.rs index 20fdc8cfea..a1db5911cc 100644 --- a/c2rust-transpile/src/lib.rs +++ b/c2rust-transpile/src/lib.rs @@ -37,7 +37,7 @@ use c2rust_ast_exporter as ast_exporter; use crate::build_files::{emit_build_files, get_build_dir, CrateConfig}; use crate::compile_cmds::get_compile_commands; -pub use crate::translator::ReplaceMode; +pub use crate::translator::{EnumMode, ReplaceMode}; use std::prelude::v1::Vec; type PragmaVec = Vec<(&'static str, Vec<&'static str>)>; @@ -108,6 +108,7 @@ pub struct TranspilerConfig { pub log_level: log::LevelFilter, pub edition: RustEdition, pub deny_unsafe_op_in_unsafe_fn: bool, + pub enum_mode: EnumMode, /// Run `c2rust-postprocess` after transpiling and potentially refactoring. pub postprocess: bool, diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index a6eda2bae9..a387e087b2 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -5,7 +5,7 @@ use syn::Expr; use crate::c_ast::CUnOp; use crate::{ diagnostics::TranslationResult, - translator::{signed_int_expr, ConvertedDecl, ExprContext, Translation}, + translator::{signed_int_expr, ConvertedDecl, EnumMode, ExprContext, Translation}, with_stmts::WithStmts, CDeclKind, CEnumConstantId, CEnumId, CExprId, CExprKind, CLiteral, CQualTypeId, CTypeKind, ConstIntExpr, @@ -23,10 +23,15 @@ impl<'c> Translation<'c> { .borrow() .resolve_decl_name(enum_id) .expect("Enums should already be renamed"); - let ty = self.convert_type(integral_type.ctype)?; - Ok(ConvertedDecl::Item( - mk().span(span).pub_().type_item(enum_name, ty), - )) + let integral_type_rs = self.convert_type(integral_type.ctype)?; + let item = match self.tcfg.enum_mode { + EnumMode::Consts => mk() + .span(span) + .pub_() + .type_item(enum_name, integral_type_rs), + }; + + Ok(ConvertedDecl::Item(item)) } pub fn convert_enum_constant( @@ -163,11 +168,17 @@ impl<'c> Translation<'c> { let enum_integral_type = self.enum_integral_type(enum_id); let mut val = WithStmts::new_val(val); - let source_type_kind = &self.ast_context.resolve_type(source_cty.ctype).kind; - let enum_integral_type_kind = &self.ast_context.resolve_type(enum_integral_type.ctype).kind; - if source_type_kind != enum_integral_type_kind { - val = val.map(|val| self.enum_constructor_expr(enum_id, val)); + match self.tcfg.enum_mode { + EnumMode::Consts => { + let source_type_kind = &self.ast_context.resolve_type(source_cty.ctype).kind; + let enum_integral_type_kind = + &self.ast_context.resolve_type(enum_integral_type.ctype).kind; + + if source_type_kind != enum_integral_type_kind { + val = val.map(|val| self.enum_constructor_expr(enum_id, val)); + } + } } Ok(val) @@ -222,7 +233,9 @@ impl<'c> Translation<'c> { .unwrap(); self.add_import(enum_id, &enum_name); - mk().cast_expr(value, mk().ident_ty(enum_name)) + match self.tcfg.enum_mode { + EnumMode::Consts => mk().cast_expr(value, mk().ident_ty(enum_name)), + } } fn is_variant_of_enum(&self, enum_id: CEnumId, enum_constant_id: CEnumConstantId) -> bool { diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index af007358d9..76f93d71c7 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -4437,3 +4437,8 @@ fn neg_expr(arg: Box) -> Box { fn wrapping_neg_expr(arg: Box) -> Box { mk().method_call_expr(arg, "wrapping_neg", vec![]) } + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum EnumMode { + Consts, +} diff --git a/c2rust-transpile/tests/snapshots.rs b/c2rust-transpile/tests/snapshots.rs index 4f10e330ea..c796a3165e 100644 --- a/c2rust-transpile/tests/snapshots.rs +++ b/c2rust-transpile/tests/snapshots.rs @@ -11,8 +11,7 @@ use c2rust_rust_tools::RustEdition; use c2rust_rust_tools::RustEdition::Edition2021; use c2rust_rust_tools::RustEdition::Edition2024; use c2rust_transpile::renamer::RUST_KEYWORDS; -use c2rust_transpile::ReplaceMode; -use c2rust_transpile::TranspilerConfig; +use c2rust_transpile::{EnumMode, ReplaceMode, TranspilerConfig}; use itertools::Itertools; fn config(edition: RustEdition) -> TranspilerConfig { @@ -68,6 +67,7 @@ fn config(edition: RustEdition) -> TranspilerConfig { .unwrap() .to_path_buf(), ), + enum_mode: EnumMode::Consts, } } diff --git a/c2rust/src/bin/c2rust-transpile.rs b/c2rust/src/bin/c2rust-transpile.rs index 39f5ada8e7..f4a74bc84c 100644 --- a/c2rust/src/bin/c2rust-transpile.rs +++ b/c2rust/src/bin/c2rust-transpile.rs @@ -4,7 +4,7 @@ use regex::Regex; use std::{ffi::OsStr, fs, path::PathBuf}; use c2rust_rust_tools::RustEdition; -use c2rust_transpile::{Diagnostic, ReplaceMode, TranspilerConfig}; +use c2rust_transpile::{Diagnostic, EnumMode, ReplaceMode, TranspilerConfig}; #[derive(Debug, Parser)] #[clap( @@ -326,6 +326,7 @@ fn main() { log_level: args.log_level, edition: args.edition, deny_unsafe_op_in_unsafe_fn: args.deny_unsafe_op_in_unsafe_fn, + enum_mode: EnumMode::Consts, }; // binaries imply emit-build-files if !tcfg.binaries.is_empty() { From 6084127e7b181094ff448a8092295d26f477547b Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 19:59:32 +0200 Subject: [PATCH 8/8] transpile: Add `EnumMode::NewType` and make it the default --- c2rust-transpile/src/translator/enums.rs | 49 +++++++++++++++---- c2rust-transpile/src/translator/mod.rs | 4 +- c2rust-transpile/src/translator/pointers.rs | 11 ++++- c2rust-transpile/tests/snapshots.rs | 2 +- ...shots__transpile@exprs.c.2021.clang15.snap | 20 +++++--- ...shots__transpile@exprs.c.2024.clang15.snap | 20 +++++--- ...s__transpile@macrocase.c.2021.clang15.snap | 10 ++-- ...s__transpile@macrocase.c.2024.clang15.snap | 10 ++-- ...ots__transpile@records.c.2021.clang15.snap | 20 +++++--- ...ots__transpile@records.c.2024.clang15.snap | 20 +++++--- ..._transpile@scalar_init.c.2021.clang15.snap | 6 ++- ..._transpile@scalar_init.c.2024.clang15.snap | 6 ++- c2rust/src/bin/c2rust-transpile.rs | 2 +- tests/unit/enums/src/test_enums.rs | 4 +- tests/unit/misc/src/test_uninitialized.rs | 6 +-- 15 files changed, 127 insertions(+), 63 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index a387e087b2..6ddc44b26b 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -25,6 +25,15 @@ impl<'c> Translation<'c> { .expect("Enums should already be renamed"); let integral_type_rs = self.convert_type(integral_type.ctype)?; let item = match self.tcfg.enum_mode { + EnumMode::NewType => { + let field = mk().pub_().enum_field(integral_type_rs); + mk().span(span) + .call_attr("derive", vec!["Clone", "Copy"]) + .call_attr("repr", vec!["transparent"]) + .pub_() + .struct_item(enum_name, vec![field], true) + } + EnumMode::Consts => mk() .span(span) .pub_() @@ -51,16 +60,16 @@ impl<'c> Translation<'c> { .borrow() .resolve_decl_name(enum_id) .expect("Enums should already be renamed"); - self.add_import(enum_id, &enum_name); let ty = mk().ident_ty(enum_name); let val = match value { ConstIntExpr::I(value) => signed_int_expr(value), ConstIntExpr::U(value) => mk().lit_expr(mk().int_unsuffixed_lit(value as u128)), }; + let init = self.enum_constructor_expr(enum_id, val); Ok(ConvertedDecl::Item( - mk().span(span).pub_().const_item(name, ty, val), + mk().span(span).pub_().const_item(name, ty, init), )) } @@ -88,8 +97,14 @@ impl<'c> Translation<'c> { ctx: ExprContext, enum_id: CEnumId, target_cty: CQualTypeId, - val: Box, + mut val: Box, ) -> TranslationResult>> { + match self.tcfg.enum_mode { + // First extract the enum's inner type... + EnumMode::NewType => val = self.integer_from_enum(val), + EnumMode::Consts => {} + } + // Cast from the enum's integral type to the expected integral type. let source_cty = self.enum_integral_type(enum_id); self.convert_cast( @@ -103,12 +118,15 @@ impl<'c> Translation<'c> { ) } - /// Translate a cast where the target type is an `enum` type. - /// - /// When translating variable references to `EnumConstant`s, we always insert casts to the - /// expected type. In C, `EnumConstant`s have some integral type, _not_ the enum type. However, - /// if we then immediately have a cast to convert this variable back into an enum type, we would - /// like to produce Rust with _no_ casts. This function handles this simplification. + /// Gets the inner integral value of an enum value. + pub fn integer_from_enum(&self, val: Box) -> Box { + match self.tcfg.enum_mode { + EnumMode::NewType => mk().anon_field_expr(val, 0), + EnumMode::Consts => val, + } + } + + /// Translates a cast where the target type is an `enum` type. pub fn convert_cast_to_enum( &self, ctx: ExprContext, @@ -163,6 +181,12 @@ impl<'c> Translation<'c> { return Ok(WithStmts::new_val(val)); } + match self.tcfg.enum_mode { + // Enum-to-enum casts need to be translated via the inner value as an intermediate. + EnumMode::NewType => val = self.integer_from_enum(val), + EnumMode::Consts => {} + } + source_cty = self.enum_integral_type(source_enum_id); } @@ -170,6 +194,12 @@ impl<'c> Translation<'c> { let mut val = WithStmts::new_val(val); match self.tcfg.enum_mode { + EnumMode::NewType => { + val = + self.convert_cast(ctx, source_cty, enum_integral_type, val, None, None, None)?; + val = val.map(|val| self.enum_constructor_expr(enum_id, val)); + } + EnumMode::Consts => { let source_type_kind = &self.ast_context.resolve_type(source_cty.ctype).kind; let enum_integral_type_kind = @@ -234,6 +264,7 @@ impl<'c> Translation<'c> { self.add_import(enum_id, &enum_name); match self.tcfg.enum_mode { + EnumMode::NewType => mk().call_expr(mk().ident_expr(enum_name), vec![value]), EnumMode::Consts => mk().cast_expr(value, mk().ident_ty(enum_name)), } } diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 76f93d71c7..8001e602d6 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -4010,7 +4010,6 @@ impl<'c> Translation<'c> { field.map(|field| mk().struct_expr(vec![name], vec![field])) } - // Transmute the number `0` into the enum type CDeclKind::Enum { .. } => self.convert_enum_zero_initializer(decl_id), _ => { @@ -4115,7 +4114,7 @@ impl<'c> Translation<'c> { } let val = if ty.is_enum() { - mk().cast_expr(val, mk().path_ty(vec!["u64"])) + self.integer_from_enum(val) } else { val }; @@ -4440,5 +4439,6 @@ fn wrapping_neg_expr(arg: Box) -> Box { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum EnumMode { + NewType, Consts, } diff --git a/c2rust-transpile/src/translator/pointers.rs b/c2rust-transpile/src/translator/pointers.rs index c23df41d9e..29daf108fa 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -244,6 +244,10 @@ impl<'c> Translation<'c> { let lhs_node_type = lhs_node .get_type() .ok_or_else(|| format_err!("lhs node bad type"))?; + let rhs_node_type = rhs_node + .get_type() + .ok_or_else(|| format_err!("rhs node bad type"))?; + if self .ast_context .resolve_type(lhs_node_type) @@ -257,7 +261,12 @@ impl<'c> Translation<'c> { } let rhs = self.convert_expr(ctx.used(), rhs, None)?; - rhs.and_then_try(|rhs| { + rhs.and_then_try(|mut rhs| { + // C allows enums to index arrays directly without inserting a numeric cast. + if let CTypeKind::Enum(..) = self.ast_context.resolve_type(rhs_node_type).kind { + rhs = self.integer_from_enum(rhs); + } + let simple_index_array = if ctx.needs_address() { // We can't necessarily index into an array if we're using // that element to compute an address. diff --git a/c2rust-transpile/tests/snapshots.rs b/c2rust-transpile/tests/snapshots.rs index c796a3165e..3f1e38d7d6 100644 --- a/c2rust-transpile/tests/snapshots.rs +++ b/c2rust-transpile/tests/snapshots.rs @@ -67,7 +67,7 @@ fn config(edition: RustEdition) -> TranspilerConfig { .unwrap() .to_path_buf(), ), - enum_mode: EnumMode::Consts, + enum_mode: EnumMode::NewType, } } diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap index 2f45733bbe..ead4f9b7fb 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap @@ -15,13 +15,17 @@ expression: cat tests/snapshots/exprs.2021.clang15.rs extern "C" { fn puts(str: *const ::core::ffi::c_char) -> ::core::ffi::c_int; } -pub type E = ::core::ffi::c_uint; -pub const EA: E = 0; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct E(pub ::core::ffi::c_uint); +pub const EA: E = E(0); pub type int_t = ::core::ffi::c_int; -pub type C2Rust_Unnamed = ::core::ffi::c_uint; -pub const C: C2Rust_Unnamed = 2; -pub const B: C2Rust_Unnamed = 1; -pub const A: C2Rust_Unnamed = 0; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct C2Rust_Unnamed(pub ::core::ffi::c_uint); +pub const C: C2Rust_Unnamed = C2Rust_Unnamed(2); +pub const B: C2Rust_Unnamed = C2Rust_Unnamed(1); +pub const A: C2Rust_Unnamed = C2Rust_Unnamed(0); unsafe extern "C" fn side_effect() -> ::core::ffi::c_int { puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char); return 10 as ::core::ffi::c_int; @@ -60,7 +64,7 @@ pub unsafe extern "C" fn unsigned_compound_desugaring() { let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; let mut u: ::core::ffi::c_uint = 0 as ::core::ffi::c_uint; let mut e: E = EA; - e = e.wrapping_add(u); + e = E(e.0.wrapping_add(u)); i = (i as ::core::ffi::c_uint).wrapping_add(u) as ::core::ffi::c_int; } #[no_mangle] @@ -72,7 +76,7 @@ pub unsafe extern "C" fn cast_literals() { } #[no_mangle] pub unsafe extern "C" fn compound_literal() { - let mut i: ::core::ffi::c_int = B as ::core::ffi::c_int; + let mut i: ::core::ffi::c_int = B.0 as ::core::ffi::c_int; } #[no_mangle] pub unsafe extern "C" fn statement_expr() { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap index 13e0833e62..94b05654a1 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap @@ -15,13 +15,17 @@ expression: cat tests/snapshots/exprs.2024.clang15.rs unsafe extern "C" { unsafe fn puts(str: *const ::core::ffi::c_char) -> ::core::ffi::c_int; } -pub type E = ::core::ffi::c_uint; -pub const EA: E = 0; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct E(pub ::core::ffi::c_uint); +pub const EA: E = E(0); pub type int_t = ::core::ffi::c_int; -pub type C2Rust_Unnamed = ::core::ffi::c_uint; -pub const C: C2Rust_Unnamed = 2; -pub const B: C2Rust_Unnamed = 1; -pub const A: C2Rust_Unnamed = 0; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct C2Rust_Unnamed(pub ::core::ffi::c_uint); +pub const C: C2Rust_Unnamed = C2Rust_Unnamed(2); +pub const B: C2Rust_Unnamed = C2Rust_Unnamed(1); +pub const A: C2Rust_Unnamed = C2Rust_Unnamed(0); unsafe extern "C" fn side_effect() -> ::core::ffi::c_int { puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char); return 10 as ::core::ffi::c_int; @@ -60,7 +64,7 @@ pub unsafe extern "C" fn unsigned_compound_desugaring() { let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; let mut u: ::core::ffi::c_uint = 0 as ::core::ffi::c_uint; let mut e: E = EA; - e = e.wrapping_add(u); + e = E(e.0.wrapping_add(u)); i = (i as ::core::ffi::c_uint).wrapping_add(u) as ::core::ffi::c_int; } #[unsafe(no_mangle)] @@ -72,7 +76,7 @@ pub unsafe extern "C" fn cast_literals() { } #[unsafe(no_mangle)] pub unsafe extern "C" fn compound_literal() { - let mut i: ::core::ffi::c_int = B as ::core::ffi::c_int; + let mut i: ::core::ffi::c_int = B.0 as ::core::ffi::c_int; } #[unsafe(no_mangle)] pub unsafe extern "C" fn statement_expr() { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.clang15.snap index 50ff8785d9..c41d837292 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.clang15.snap @@ -11,14 +11,16 @@ expression: cat tests/snapshots/macrocase.2021.clang15.rs unused_assignments, unused_mut )] -pub type ZSTD_dParameter = ::core::ffi::c_uint; -pub const ZSTD_d_experimentalParam1: ZSTD_dParameter = 1000; -pub const ZSTD_d_windowLogMax: ZSTD_dParameter = 100; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct ZSTD_dParameter(pub ::core::ffi::c_uint); +pub const ZSTD_d_experimentalParam1: ZSTD_dParameter = ZSTD_dParameter(1000); +pub const ZSTD_d_windowLogMax: ZSTD_dParameter = ZSTD_dParameter(100); pub const ZSTD_d_format: ::core::ffi::c_uint = 1000 as ::core::ffi::c_uint; #[no_mangle] pub unsafe extern "C" fn ZSTD_dParam_getBounds(mut dParam: ZSTD_dParameter) -> ::core::ffi::c_int { let mut bounds: ::core::ffi::c_int = 0 as ::core::ffi::c_int; - match dParam { + match dParam.0 { 100 => { bounds = 1 as ::core::ffi::c_int; return bounds; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.clang15.snap index b4b6f37e89..e4cc4f1de0 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.clang15.snap @@ -12,14 +12,16 @@ expression: cat tests/snapshots/macrocase.2024.clang15.rs unused_assignments, unused_mut )] -pub type ZSTD_dParameter = ::core::ffi::c_uint; -pub const ZSTD_d_experimentalParam1: ZSTD_dParameter = 1000; -pub const ZSTD_d_windowLogMax: ZSTD_dParameter = 100; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct ZSTD_dParameter(pub ::core::ffi::c_uint); +pub const ZSTD_d_experimentalParam1: ZSTD_dParameter = ZSTD_dParameter(1000); +pub const ZSTD_d_windowLogMax: ZSTD_dParameter = ZSTD_dParameter(100); pub const ZSTD_d_format: ::core::ffi::c_uint = 1000 as ::core::ffi::c_uint; #[unsafe(no_mangle)] pub unsafe extern "C" fn ZSTD_dParam_getBounds(mut dParam: ZSTD_dParameter) -> ::core::ffi::c_int { let mut bounds: ::core::ffi::c_int = 0 as ::core::ffi::c_int; - match dParam { + match dParam.0 { 100 => { bounds = 1 as ::core::ffi::c_int; return bounds; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.clang15.snap index d24f14826f..8cfbb62b5d 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.clang15.snap @@ -14,9 +14,11 @@ expression: cat tests/snapshots/records.2021.clang15.rs #[derive(Copy, Clone)] #[repr(C)] pub struct AnonEnumInStruct {} -pub type C2Rust_Unnamed = ::core::ffi::c_uint; -pub const VALUE2: C2Rust_Unnamed = 1; -pub const VALUE1: C2Rust_Unnamed = 0; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct C2Rust_Unnamed(pub ::core::ffi::c_uint); +pub const VALUE2: C2Rust_Unnamed = C2Rust_Unnamed(1); +pub const VALUE1: C2Rust_Unnamed = C2Rust_Unnamed(0); #[derive(Copy, Clone)] #[repr(C)] pub struct AnonStructInStruct { @@ -40,9 +42,11 @@ pub struct InsideStruct { pub union AnonEnumInUnion { pub a: ::core::ffi::c_int, } -pub type C2Rust_Unnamed_1 = ::core::ffi::c_uint; -pub const VALUE4: C2Rust_Unnamed_1 = 1; -pub const VALUE3: C2Rust_Unnamed_1 = 0; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct C2Rust_Unnamed_1(pub ::core::ffi::c_uint); +pub const VALUE4: C2Rust_Unnamed_1 = C2Rust_Unnamed_1(1); +pub const VALUE3: C2Rust_Unnamed_1 = C2Rust_Unnamed_1(0); #[derive(Copy, Clone)] #[repr(C)] pub union AnonStructInUnion { @@ -66,7 +70,7 @@ pub struct InsideUnion { } #[no_mangle] pub unsafe extern "C" fn struct_declaration() { - let mut value: ::core::ffi::c_int = VALUE2 as ::core::ffi::c_int; + let mut value: ::core::ffi::c_int = VALUE2.0 as ::core::ffi::c_int; let mut a: AnonEnumInStruct = AnonEnumInStruct {}; let mut b: AnonStructInStruct = AnonStructInStruct { c2rust_unnamed: C2Rust_Unnamed_0 { some_number: 0 }, @@ -77,7 +81,7 @@ pub unsafe extern "C" fn struct_declaration() { } #[no_mangle] pub unsafe extern "C" fn union_declaration() { - let mut value: ::core::ffi::c_int = VALUE4 as ::core::ffi::c_int; + let mut value: ::core::ffi::c_int = VALUE4.0 as ::core::ffi::c_int; let mut a: AnonEnumInUnion = AnonEnumInUnion { a: 0 }; let mut b: AnonStructInUnion = AnonStructInUnion { c2rust_unnamed: C2Rust_Unnamed_2 { some_number: 0 }, diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.clang15.snap index 4ee9a80c6a..46cf4abce5 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.clang15.snap @@ -15,9 +15,11 @@ expression: cat tests/snapshots/records.2024.clang15.rs #[derive(Copy, Clone)] #[repr(C)] pub struct AnonEnumInStruct {} -pub type C2Rust_Unnamed = ::core::ffi::c_uint; -pub const VALUE2: C2Rust_Unnamed = 1; -pub const VALUE1: C2Rust_Unnamed = 0; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct C2Rust_Unnamed(pub ::core::ffi::c_uint); +pub const VALUE2: C2Rust_Unnamed = C2Rust_Unnamed(1); +pub const VALUE1: C2Rust_Unnamed = C2Rust_Unnamed(0); #[derive(Copy, Clone)] #[repr(C)] pub struct AnonStructInStruct { @@ -41,9 +43,11 @@ pub struct InsideStruct { pub union AnonEnumInUnion { pub a: ::core::ffi::c_int, } -pub type C2Rust_Unnamed_1 = ::core::ffi::c_uint; -pub const VALUE4: C2Rust_Unnamed_1 = 1; -pub const VALUE3: C2Rust_Unnamed_1 = 0; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct C2Rust_Unnamed_1(pub ::core::ffi::c_uint); +pub const VALUE4: C2Rust_Unnamed_1 = C2Rust_Unnamed_1(1); +pub const VALUE3: C2Rust_Unnamed_1 = C2Rust_Unnamed_1(0); #[derive(Copy, Clone)] #[repr(C)] pub union AnonStructInUnion { @@ -67,7 +71,7 @@ pub struct InsideUnion { } #[unsafe(no_mangle)] pub unsafe extern "C" fn struct_declaration() { - let mut value: ::core::ffi::c_int = VALUE2 as ::core::ffi::c_int; + let mut value: ::core::ffi::c_int = VALUE2.0 as ::core::ffi::c_int; let mut a: AnonEnumInStruct = AnonEnumInStruct {}; let mut b: AnonStructInStruct = AnonStructInStruct { c2rust_unnamed: C2Rust_Unnamed_0 { some_number: 0 }, @@ -78,7 +82,7 @@ pub unsafe extern "C" fn struct_declaration() { } #[unsafe(no_mangle)] pub unsafe extern "C" fn union_declaration() { - let mut value: ::core::ffi::c_int = VALUE4 as ::core::ffi::c_int; + let mut value: ::core::ffi::c_int = VALUE4.0 as ::core::ffi::c_int; let mut a: AnonEnumInUnion = AnonEnumInUnion { a: 0 }; let mut b: AnonStructInUnion = AnonStructInUnion { c2rust_unnamed: C2Rust_Unnamed_2 { some_number: 0 }, diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2021.clang15.snap index 983068e241..912ed190b6 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2021.clang15.snap @@ -12,8 +12,10 @@ expression: cat tests/snapshots/scalar_init.2021.clang15.rs unused_mut )] #![feature(raw_ref_op)] -pub type E = ::core::ffi::c_uint; -pub const A: E = 0; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct E(pub ::core::ffi::c_uint); +pub const A: E = E(0); pub const true_0: ::core::ffi::c_int = 1 as ::core::ffi::c_int; #[no_mangle] pub unsafe extern "C" fn scalar_init() { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.clang15.snap index be7f3a5d96..d6a4077d3a 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.clang15.snap @@ -12,8 +12,10 @@ expression: cat tests/snapshots/scalar_init.2024.clang15.rs unused_assignments, unused_mut )] -pub type E = ::core::ffi::c_uint; -pub const A: E = 0; +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct E(pub ::core::ffi::c_uint); +pub const A: E = E(0); pub const true_0: ::core::ffi::c_int = 1 as ::core::ffi::c_int; #[unsafe(no_mangle)] pub unsafe extern "C" fn scalar_init() { diff --git a/c2rust/src/bin/c2rust-transpile.rs b/c2rust/src/bin/c2rust-transpile.rs index f4a74bc84c..34a272ac67 100644 --- a/c2rust/src/bin/c2rust-transpile.rs +++ b/c2rust/src/bin/c2rust-transpile.rs @@ -326,7 +326,7 @@ fn main() { log_level: args.log_level, edition: args.edition, deny_unsafe_op_in_unsafe_fn: args.deny_unsafe_op_in_unsafe_fn, - enum_mode: EnumMode::Consts, + enum_mode: EnumMode::NewType, }; // binaries imply emit-build-files if !tcfg.binaries.is_empty() { diff --git a/tests/unit/enums/src/test_enums.rs b/tests/unit/enums/src/test_enums.rs index 1e373fd354..c100fd91cc 100644 --- a/tests/unit/enums/src/test_enums.rs +++ b/tests/unit/enums/src/test_enums.rs @@ -35,8 +35,8 @@ const BUFFER_SIZE6: usize = 1; #[test] pub fn test_variants() { - assert_eq!(A as u32, 0); - assert_eq!(B as u32, 1); + assert_eq!(A.0 as u32, 0); + assert_eq!(B.0 as u32, 1); } #[test] diff --git a/tests/unit/misc/src/test_uninitialized.rs b/tests/unit/misc/src/test_uninitialized.rs index 87425c5b32..505aee8937 100644 --- a/tests/unit/misc/src/test_uninitialized.rs +++ b/tests/unit/misc/src/test_uninitialized.rs @@ -26,9 +26,9 @@ pub fn test_buffer() { #[test] pub fn test_types() { - assert_eq!(foo as u32, 1); - assert_eq!(bar as u32, 2); - assert_eq!(baz as u32, 3); + assert_eq!(foo.0 as u32, 1); + assert_eq!(bar.0 as u32, 2); + assert_eq!(baz.0 as u32, 3); // FIXME: union fields are private // let my_union = u { x: 32 };