From 103681414ca7d3fd94fa901a45628ee56f7939d8 Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 26 Apr 2026 12:27:43 +0200 Subject: [PATCH 01/11] transpile: Split off `convert_decl_ref` --- c2rust-transpile/src/translator/mod.rs | 232 +++++++++++++------------ 1 file changed, 121 insertions(+), 111 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index ad2a65089c..2975ed267d 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3063,117 +3063,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]); - - // If the variable is actually an `EnumConstant`, we need to add a cast to the - // expected integral type. - if let &CDeclKind::EnumConstant { .. } = decl { - val = self.convert_cast_from_enum(qual_ty.ctype, val)?; - } - - // 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. - let mut set_unsafe = false; - if ctx.needs_address() { - if let CDeclKind::Function { parameters, .. } = decl { - 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); - } - } - } - } - - 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)?); - } - } - - let mut res = WithStmts::new_val(val); - res.merge_unsafe(set_unsafe); - Ok(res) - } + DeclRef(qual_ty, decl_id, lrvalue) => self + .convert_decl_ref(ctx, qual_ty, decl_id, lrvalue, override_ty) + .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( @@ -3535,6 +3427,124 @@ impl<'c> Translation<'c> { } } + fn convert_decl_ref( + &self, + ctx: ExprContext, + qual_ty: CQualTypeId, + decl_id: CDeclId, + lrvalue: LRValue, + override_ty: Option, + ) -> 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]); + + // If the variable is actually an `EnumConstant`, we need to add a cast to the + // expected integral type. + if let &CDeclKind::EnumConstant { .. } = decl { + val = self.convert_cast_from_enum(qual_ty.ctype, val)?; + } + + // 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. + let mut set_unsafe = false; + if ctx.needs_address() { + if let CDeclKind::Function { parameters, .. } = decl { + 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); + } + } + } + } + + 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)?); + } + } + + let mut res = WithStmts::new_val(val); + res.merge_unsafe(set_unsafe); + Ok(res) + } + 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 662ca957cc01732bbc30e4709f44a18acbd4d24e Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 25 Apr 2026 21:35:42 +0200 Subject: [PATCH 02/11] 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, 51 insertions(+), 51 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index d1a9c0b8c9..ed82cb7cc2 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[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[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 2975ed267d..4bc357b441 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3483,7 +3483,7 @@ impl<'c> Translation<'c> { // If the variable is actually an `EnumConstant`, we need to add a cast to the // expected integral type. if let &CDeclKind::EnumConstant { .. } = decl { - val = self.convert_cast_from_enum(qual_ty.ctype, val)?; + return self.convert_cast_from_enum(qual_ty, val); } // If we are referring to a function and need its address, we @@ -3706,20 +3706,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 @@ -3754,16 +3750,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.result_map(|val| { - self.convert_cast_to_enum(ctx, target_cty.ctype, enum_decl_id, expr, val) + val.and_then(|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.result_map(|val| self.convert_cast_from_enum(target_cty.ctype, val)) + val.and_then(|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 5fd92a4718..7526aedac5 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -431,28 +431,28 @@ 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); val.and_then(|val| { Ok(WithStmts::new_unsafe_val(transmute_expr( @@ -461,7 +461,7 @@ impl<'c> Translation<'c> { }) } 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))) } } @@ -469,14 +469,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, @@ -502,7 +502,7 @@ impl<'c> Translation<'c> { mk().cast_expr(val, target_ty) })) } else if let &CTypeKind::Enum(..) = source_ty_kind { - val.result_map(|val| self.convert_cast_from_enum(target_cty, val)) + val.and_then(|val| self.convert_cast_from_enum(target_cty, val)) } else { Ok(val.map(|val| mk().cast_expr(val, target_ty))) } @@ -511,8 +511,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>> { @@ -523,20 +523,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) { val.and_then(|val| { Ok(WithStmts::new_unsafe_val(transmute_expr( source_ty, target_ty, val, ))) }) } else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind { - val.result_map(|val| { - self.convert_cast_to_enum(ctx, target_cty, enum_decl_id, expr, val) - }) + val.and_then(|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 e76f305d674c7e246c452ebc0e5976389bdfd053 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 19:20:40 +0200 Subject: [PATCH 03/11] 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 ed82cb7cc2..0a41690704 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 4bc357b441..bdef885a1c 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3462,6 +3462,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 @@ -3480,12 +3484,6 @@ impl<'c> Translation<'c> { let mut val = mk().path_expr(vec![rustname]); - // If the variable is actually an `EnumConstant`, we need to add a cast to the - // expected integral type. - if let &CDeclKind::EnumConstant { .. } = decl { - return self.convert_cast_from_enum(qual_ty, val); - } - // 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. let mut set_unsafe = false; From 595492146f92f7b59f1bacf2cbe23271259f219f Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 18:11:57 +0200 Subject: [PATCH 04/11] 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 | 4 +-- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index 0a41690704..d5d4594645 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[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 bdef885a1c..1fa43048ce 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3747,10 +3747,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(|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(|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) @@ -4022,7 +4020,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 7526aedac5..0dbe2b20f6 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -533,8 +533,8 @@ impl<'c> Translation<'c> { source_ty, target_ty, val, ))) }) - } else if let &CTypeKind::Enum(enum_decl_id) = target_ty_kind { - val.and_then(|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(|val| self.convert_cast_to_enum(ctx, enum_id, expr, val)) } else { Ok(val.map(|val| mk().cast_expr(val, target_ty))) } From 5090d8ec595630c6137d38727ee5ac8eae784042 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 17:26:21 +0200 Subject: [PATCH 05/11] transpile: Cast enums only if actually needed --- c2rust-transpile/src/translator/enums.rs | 48 +++++++++++++++---- c2rust-transpile/src/translator/mod.rs | 10 ++-- c2rust-transpile/src/translator/pointers.rs | 6 +-- .../snapshots__transpile@exprs.c.2021.snap | 2 +- .../snapshots__transpile@exprs.c.2024.snap | 2 +- ...snapshots__transpile@macrocase.c.2021.snap | 2 +- ...snapshots__transpile@macrocase.c.2024.snap | 2 +- 7 files changed, 52 insertions(+), 20 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index d5d4594645..04f1390fd9 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 1fa43048ce..30fabdc686 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3463,7 +3463,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(); @@ -3748,13 +3748,15 @@ 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(|val| self.convert_cast_to_enum(ctx, enum_id, expr, val)) + val.and_then(|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(|val| self.convert_cast_from_enum(target_cty, val)) + } else if let &CTypeKind::Enum(enum_id) = source_ty_kind { + val.and_then(|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 0dbe2b20f6..e9b9148ada 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -501,8 +501,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(|val| self.convert_cast_from_enum(target_cty, val)) + } else if let &CTypeKind::Enum(enum_id) = source_ty_kind { + val.and_then(|val| self.convert_cast_from_enum(ctx, enum_id, target_cty, val)) } else { Ok(val.map(|val| mk().cast_expr(val, target_ty))) } @@ -534,7 +534,7 @@ impl<'c> Translation<'c> { ))) }) } else if let &CTypeKind::Enum(enum_id) = target_ty_kind { - val.and_then(|val| self.convert_cast_to_enum(ctx, enum_id, expr, val)) + val.and_then(|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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap index a5a516345c..280eeb197e 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap @@ -61,7 +61,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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.snap index ea96797d26..6acb6a8752 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.snap @@ -61,7 +61,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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.snap index 1d6f669dd7..5cbe1e5b8c 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.snap index 3c0a0e3f8e..ae30a0238e 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.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 09ea2e0f93d437f61e426a3768c8f9c847077b64 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 18:31:55 +0200 Subject: [PATCH 06/11] 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 04f1390fd9..a5c15c3469 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 befdd79b99..79f9843c2a 100644 --- a/c2rust-transpile/src/translator/operators.rs +++ b/c2rust-transpile/src/translator/operators.rs @@ -723,26 +723,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 29626c3ea3978d05d391b79cf97896d9c111bff2 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 17:37:55 +0200 Subject: [PATCH 07/11] 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 a5c15c3469..cdee2a08ec 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 30fabdc686..f3df6af85c 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -4447,3 +4447,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 31c16e1abc..42d79ed9b5 100644 --- a/c2rust-transpile/tests/snapshots.rs +++ b/c2rust-transpile/tests/snapshots.rs @@ -10,8 +10,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 { @@ -67,6 +66,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 b42ca48336c2f0df59b2a6b5d95d76ba5b449208 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 19:59:32 +0200 Subject: [PATCH 08/11] 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 +- .../snapshots__transpile@exprs.c.2021.snap | 20 +++++--- .../snapshots__transpile@exprs.c.2024.snap | 20 +++++--- ...snapshots__transpile@macrocase.c.2021.snap | 10 ++-- ...snapshots__transpile@macrocase.c.2024.snap | 10 ++-- .../snapshots__transpile@records.c.2021.snap | 20 +++++--- .../snapshots__transpile@records.c.2024.snap | 20 +++++--- ...apshots__transpile@scalar_init.c.2021.snap | 6 ++- ...apshots__transpile@scalar_init.c.2024.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 cdee2a08ec..1458090934 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 f3df6af85c..e080cefa36 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -4021,7 +4021,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), _ => { @@ -4126,7 +4125,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 }; @@ -4450,5 +4449,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 e9b9148ada..6ba497e487 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -249,6 +249,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) @@ -262,7 +266,12 @@ impl<'c> Translation<'c> { } let rhs = self.convert_expr(ctx.used(), rhs, None)?; - rhs.and_then(|rhs| { + rhs.and_then(|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 42d79ed9b5..7961105342 100644 --- a/c2rust-transpile/tests/snapshots.rs +++ b/c2rust-transpile/tests/snapshots.rs @@ -66,7 +66,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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap index 280eeb197e..b596bcebef 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap @@ -16,13 +16,17 @@ expression: cat tests/snapshots/exprs.2021.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; @@ -61,7 +65,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] @@ -73,7 +77,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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.snap index 6acb6a8752..c6eb6f59ba 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.snap @@ -16,13 +16,17 @@ expression: cat tests/snapshots/exprs.2024.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; @@ -61,7 +65,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)] @@ -73,7 +77,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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.snap index 5cbe1e5b8c..80f72a78ae 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.snap @@ -11,14 +11,16 @@ expression: cat tests/snapshots/macrocase.2021.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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.snap index ae30a0238e..b43e54ee7c 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.snap @@ -12,14 +12,16 @@ expression: cat tests/snapshots/macrocase.2024.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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.snap index c318ef5002..58318ae207 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.snap @@ -14,9 +14,11 @@ expression: cat tests/snapshots/records.2021.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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.snap index 9542e98d9d..d56651d10e 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.snap @@ -15,9 +15,11 @@ expression: cat tests/snapshots/records.2024.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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2021.snap index 218d95ca55..939779e06b 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2021.snap @@ -12,8 +12,10 @@ expression: cat tests/snapshots/scalar_init.2021.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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.snap index 5109df4c13..191a7f06a1 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.snap @@ -12,8 +12,10 @@ expression: cat tests/snapshots/scalar_init.2024.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 }; From 2cf6560ec2f3a259ffd3c91a96ed3918fdcbfda8 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 19:23:28 +0200 Subject: [PATCH 09/11] transpile: Split off `make_enum_constant_init` --- c2rust-transpile/src/translator/enums.rs | 27 ++++++++++++++++++------ c2rust-transpile/src/translator/mod.rs | 2 +- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index 1458090934..faed461796 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -2,6 +2,7 @@ use c2rust_ast_builder::mk; use proc_macro2::Span; use syn::Expr; +use crate::c_ast::iterators::SomeId; use crate::c_ast::CUnOp; use crate::{ diagnostics::TranslationResult, @@ -46,8 +47,6 @@ impl<'c> Translation<'c> { pub fn convert_enum_constant( &self, enum_constant_id: CEnumConstantId, - span: Span, - value: ConstIntExpr, ) -> TranslationResult { let name = self .renamer @@ -62,17 +61,31 @@ impl<'c> Translation<'c> { .expect("Enums should already be renamed"); 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); + let (span, init) = self.make_enum_constant_init(enum_constant_id); Ok(ConvertedDecl::Item( mk().span(span).pub_().const_item(name, ty, init), )) } + fn make_enum_constant_init(&self, enum_constant_id: CEnumConstantId) -> (Span, Box) { + let value = match self.ast_context[enum_constant_id].kind { + CDeclKind::EnumConstant { value, .. } => value, + _ => panic!("{:?} does not point to an enum variant", enum_constant_id), + }; + let value_rs = match value { + ConstIntExpr::I(value) => signed_int_expr(value), + ConstIntExpr::U(value) => mk().lit_expr(mk().int_unsuffixed_lit(value as u128)), + }; + let enum_id = self.ast_context.parents[&enum_constant_id]; + let init = self.enum_constructor_expr(enum_id, value_rs); + let span = self + .get_span(SomeId::Decl(enum_constant_id)) + .unwrap_or_else(Span::call_site); + + (span, init) + } + pub fn convert_enum_zero_initializer(&self, enum_id: CEnumId) -> WithStmts> { WithStmts::new_val(self.enum_for_i64(enum_id, 0)) } diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index e080cefa36..605d4c31b5 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -1931,7 +1931,7 @@ impl<'c> Translation<'c> { .. } => self.convert_enum(decl_id, span, integral_type), - EnumConstant { value, .. } => self.convert_enum_constant(decl_id, span, value), + EnumConstant { .. } => self.convert_enum_constant(decl_id), // We can allow non top level function declarations (i.e. extern // declarations) without any problem. Clang doesn't support nested From 0a68c0cebcb44003157241c77a3d5e7d61e263f4 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 19:23:44 +0200 Subject: [PATCH 10/11] transpile: Handle `EnumConstant` as part of `Enum` --- c2rust-transpile/src/translator/enums.rs | 43 +++++++++++------------- c2rust-transpile/src/translator/mod.rs | 6 ++-- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index faed461796..4b95f63c89 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -18,6 +18,7 @@ impl<'c> Translation<'c> { enum_id: CEnumId, span: Span, integral_type: CQualTypeId, + variants: &[CEnumConstantId], ) -> TranslationResult { let enum_name = &self .type_converter @@ -25,7 +26,7 @@ impl<'c> Translation<'c> { .resolve_decl_name(enum_id) .expect("Enums should already be renamed"); let integral_type_rs = self.convert_type(integral_type.ctype)?; - let item = match self.tcfg.enum_mode { + let enum_item = match self.tcfg.enum_mode { EnumMode::NewType => { let field = mk().pub_().enum_field(integral_type_rs); mk().span(span) @@ -41,31 +42,25 @@ impl<'c> Translation<'c> { .type_item(enum_name, integral_type_rs), }; - Ok(ConvertedDecl::Item(item)) - } - - pub fn convert_enum_constant( - &self, - enum_constant_id: CEnumConstantId, - ) -> TranslationResult { - let name = self - .renamer - .borrow_mut() - .get(&enum_constant_id) - .expect("Enum constant not named"); - let enum_id = self.ast_context.parents[&enum_constant_id]; - let enum_name = self - .type_converter - .borrow() - .resolve_decl_name(enum_id) - .expect("Enums should already be renamed"); + if variants.is_empty() { + return Ok(ConvertedDecl::Item(enum_item)); + } - let ty = mk().ident_ty(enum_name); - let (span, init) = self.make_enum_constant_init(enum_constant_id); + let enum_type = mk().ident_ty(enum_name); + let constants_iter = variants.iter().map(|&enum_constant_id| { + let name = self + .renamer + .borrow_mut() + .get(&enum_constant_id) + .expect("Enum constant not named"); + let (span, init) = self.make_enum_constant_init(enum_constant_id); + mk().span(span) + .pub_() + .const_item(name, enum_type.clone(), init) + }); - Ok(ConvertedDecl::Item( - mk().span(span).pub_().const_item(name, ty, init), - )) + let items = std::iter::once(enum_item).chain(constants_iter).collect(); + Ok(ConvertedDecl::Items(items)) } fn make_enum_constant_init(&self, enum_constant_id: CEnumConstantId) -> (Span, Box) { diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 605d4c31b5..f36dbd632b 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -1927,11 +1927,13 @@ impl<'c> Translation<'c> { )), Enum { + ref variants, integral_type: Some(integral_type), .. - } => self.convert_enum(decl_id, span, integral_type), + } => self.convert_enum(decl_id, span, integral_type, variants), - EnumConstant { .. } => self.convert_enum_constant(decl_id), + // EnumConstant is translated as part of Enum. + EnumConstant { .. } => Ok(ConvertedDecl::NoItem), // We can allow non top level function declarations (i.e. extern // declarations) without any problem. Clang doesn't support nested From ef79d453f31894c20d40072bfa17918a94b4d5e6 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 5 May 2026 19:27:04 +0200 Subject: [PATCH 11/11] transpile: Translate `EnumConstant` with associated constants --- c2rust-ast-builder/src/builder.rs | 20 +++ c2rust-transpile/src/translator/enums.rs | 138 +++++++++++++----- c2rust-transpile/src/translator/mod.rs | 11 +- .../snapshots__transpile@exprs.c.2021.snap | 16 +- .../snapshots__transpile@exprs.c.2024.snap | 16 +- ...snapshots__transpile@macrocase.c.2021.snap | 6 +- ...snapshots__transpile@macrocase.c.2024.snap | 6 +- .../snapshots__transpile@records.c.2021.snap | 16 +- .../snapshots__transpile@records.c.2024.snap | 16 +- ...apshots__transpile@scalar_init.c.2021.snap | 6 +- ...apshots__transpile@scalar_init.c.2024.snap | 6 +- tests/unit/enums/src/test_enums.rs | 10 +- tests/unit/misc/src/test_uninitialized.rs | 8 +- 13 files changed, 196 insertions(+), 79 deletions(-) diff --git a/c2rust-ast-builder/src/builder.rs b/c2rust-ast-builder/src/builder.rs index 07518e0f33..b611f56235 100644 --- a/c2rust-ast-builder/src/builder.rs +++ b/c2rust-ast-builder/src/builder.rs @@ -1416,6 +1416,26 @@ impl Builder { })) } + pub fn const_impl_item(self, name: I, ty: Box, init: Box) -> ImplItem + where + I: Make, + { + let name = name.make(&self); + ImplItem::Const(ImplItemConst { + attrs: self.attrs, + vis: self.vis, + defaultness: None, + const_token: Token![const](self.span), + ident: name, + generics: self.generics, + colon_token: Token![:](self.span), + ty: *ty, + eq_token: Token![=](self.span), + expr: *init, + semi_token: Token![;](self.span), + }) + } + pub fn fn_item(self, sig: S, mut block: Block) -> Box where S: Make, diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index 4b95f63c89..924f5a4ed1 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -46,21 +46,48 @@ impl<'c> Translation<'c> { return Ok(ConvertedDecl::Item(enum_item)); } - let enum_type = mk().ident_ty(enum_name); - let constants_iter = variants.iter().map(|&enum_constant_id| { - let name = self - .renamer - .borrow_mut() - .get(&enum_constant_id) - .expect("Enum constant not named"); - let (span, init) = self.make_enum_constant_init(enum_constant_id); - mk().span(span) - .pub_() - .const_item(name, enum_type.clone(), init) - }); + match self.tcfg.enum_mode { + EnumMode::NewType => { + let enum_type = mk().ident_ty("Self"); + let constants = variants + .iter() + .map(|&enum_constant_id| { + let name = match self.ast_context[enum_constant_id].kind { + CDeclKind::EnumConstant { ref name, .. } => self + .type_converter + .borrow_mut() + .declare_field_name(enum_id, enum_constant_id, name), + _ => panic!("{:?} does not point to an enum variant", enum_constant_id), + }; + let (span, init) = self.make_enum_constant_init(enum_constant_id); + mk().span(span) + .pub_() + .const_impl_item(name, enum_type.clone(), init) + }) + .collect(); + + let impl_block = mk().impl_item(mk().ident_ty(enum_name), constants); + Ok(ConvertedDecl::Items(vec![enum_item, impl_block])) + } - let items = std::iter::once(enum_item).chain(constants_iter).collect(); - Ok(ConvertedDecl::Items(items)) + EnumMode::Consts => { + let enum_type = mk().ident_ty(enum_name); + let constants_iter = variants.iter().map(|&enum_constant_id| { + let name = self + .renamer + .borrow_mut() + .get(&enum_constant_id) + .expect("Enum constant not named"); + let (span, init) = self.make_enum_constant_init(enum_constant_id); + mk().span(span) + .pub_() + .const_item(name, enum_type.clone(), init) + }); + + let items = std::iter::once(enum_item).chain(constants_iter).collect(); + Ok(ConvertedDecl::Items(items)) + } + } } fn make_enum_constant_init(&self, enum_constant_id: CEnumConstantId) -> (Span, Box) { @@ -73,7 +100,7 @@ impl<'c> Translation<'c> { ConstIntExpr::U(value) => mk().lit_expr(mk().int_unsuffixed_lit(value as u128)), }; let enum_id = self.ast_context.parents[&enum_constant_id]; - let init = self.enum_constructor_expr(enum_id, value_rs); + let init = self.enum_constructor_expr(enum_id, value_rs, true); let span = self .get_span(SomeId::Decl(enum_constant_id)) .unwrap_or_else(Span::call_site); @@ -93,7 +120,7 @@ impl<'c> Translation<'c> { target_type_id: CQualTypeId, ) -> TranslationResult>> { let enum_id = self.ast_context.parents[&enum_constant_id]; - let val = self.enum_constant_expr(enum_constant_id); + let val = self.enum_constant_expr(enum_id, enum_constant_id); // Add a cast to the expected integral type. self.convert_cast_from_enum(ctx, enum_id, target_type_id, val) @@ -157,7 +184,7 @@ 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 { - val = self.enum_constant_expr(enum_constant_id); + val = self.enum_constant_expr(enum_id, enum_constant_id); return Ok(WithStmts::new_val(val)); } } @@ -205,7 +232,7 @@ impl<'c> Translation<'c> { 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)); + val = val.map(|val| self.enum_constructor_expr(enum_id, val, false)); } EnumMode::Consts => { @@ -214,7 +241,7 @@ impl<'c> Translation<'c> { &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)); + val = val.map(|val| self.enum_constructor_expr(enum_id, val, false)); } } } @@ -226,7 +253,7 @@ impl<'c> Translation<'c> { /// variant directly, otherwise it converts a number to the enum type. 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); + return self.enum_constant_expr(enum_id, enum_constant_id); } let underlying_type_id = self.enum_integral_type(enum_id); @@ -236,7 +263,7 @@ impl<'c> Translation<'c> { _ => signed_int_expr(value), }; - self.enum_constructor_expr(enum_id, value) + self.enum_constructor_expr(enum_id, value, false) } /// Returns the id of the variant of `enum_id` whose value matches `value`, if any. @@ -257,23 +284,64 @@ impl<'c> Translation<'c> { }) } - fn enum_constant_expr(&self, enum_constant_id: CEnumConstantId) -> Box { - let name = self.renamer.borrow().get(&enum_constant_id).unwrap(); - self.add_import(enum_constant_id, &name); - mk().ident_expr(name) - } + fn enum_constant_expr(&self, enum_id: CEnumId, enum_constant_id: CEnumConstantId) -> Box { + match self.tcfg.enum_mode { + EnumMode::NewType => { + let enum_name = self + .type_converter + .borrow() + .resolve_decl_name(enum_id) + .unwrap(); + let name = self + .type_converter + .borrow() + .resolve_field_name(Some(enum_id), enum_constant_id) + .unwrap(); + + self.add_import(enum_id, &enum_name); + mk().path_expr(vec![enum_name, 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); + EnumMode::Consts => { + let name = self.renamer.borrow().get(&enum_constant_id).unwrap(); + self.add_import(enum_constant_id, &name); + mk().ident_expr(name) + } + } + } + fn enum_constructor_expr( + &self, + enum_id: CEnumId, + value: Box, + use_self_ty: bool, + ) -> Box { 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)), + EnumMode::NewType => { + let func = if use_self_ty { + mk().ident_expr("Self") + } else { + let enum_name = self + .type_converter + .borrow() + .resolve_decl_name(enum_id) + .unwrap(); + self.add_import(enum_id, &enum_name); + mk().ident_expr(enum_name) + }; + + mk().call_expr(func, vec![value]) + } + EnumMode::Consts => { + 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)) + } } } diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index f36dbd632b..48ee5ce26f 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -769,7 +769,10 @@ pub fn translate( Union { ref name, .. } => some_type_name(name.as_ref().map(String::as_str)), Typedef { ref name, .. } => Name::Type(name), Function { ref name, .. } => Name::Var(name), - EnumConstant { ref name, .. } => Name::Var(name), + EnumConstant { ref name, .. } => match t.tcfg.enum_mode { + EnumMode::NewType => Name::None, + EnumMode::Consts => Name::Var(name), + }, Variable { ref ident, .. } if t.ast_context.c_decls_top.contains(&decl_id) => { Name::Var(ident) } @@ -847,7 +850,6 @@ pub fn translate( let needs_export = match decl.kind { Struct { .. } => true, Enum { .. } => true, - EnumConstant { .. } => true, Union { .. } => true, Typedef { .. } => { // Only check the key as opposed to `contains` @@ -3469,6 +3471,11 @@ impl<'c> Translation<'c> { } let varname = decl.get_name().expect("expected variable name").to_owned(); + + if let &CDeclKind::EnumConstant { .. } = decl { + return self.convert_enum_constant_decl_ref(ctx, decl_id, qual_ty); + } + let rustname = self .renamer .borrow_mut() diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap index b596bcebef..03139a17ad 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap @@ -19,14 +19,18 @@ extern "C" { #[derive(Clone, Copy)] #[repr(transparent)] pub struct E(pub ::core::ffi::c_uint); -pub const EA: E = E(0); +impl E { + pub const EA: Self = Self(0); +} pub type int_t = ::core::ffi::c_int; #[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); +impl C2Rust_Unnamed { + pub const A: Self = Self(0); + pub const B: Self = Self(1); + pub const C: Self = Self(2); +} 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; @@ -64,7 +68,7 @@ pub unsafe extern "C" fn unary_with_side_effect() { 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; + let mut e: E = E::EA; e = E(e.0.wrapping_add(u)); i = (i as ::core::ffi::c_uint).wrapping_add(u) as ::core::ffi::c_int; } @@ -77,7 +81,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.0 as ::core::ffi::c_int; + let mut i: ::core::ffi::c_int = C2Rust_Unnamed::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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.snap index c6eb6f59ba..9c60e753a3 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.snap @@ -19,14 +19,18 @@ unsafe extern "C" { #[derive(Clone, Copy)] #[repr(transparent)] pub struct E(pub ::core::ffi::c_uint); -pub const EA: E = E(0); +impl E { + pub const EA: Self = Self(0); +} pub type int_t = ::core::ffi::c_int; #[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); +impl C2Rust_Unnamed { + pub const A: Self = Self(0); + pub const B: Self = Self(1); + pub const C: Self = Self(2); +} 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; @@ -64,7 +68,7 @@ pub unsafe extern "C" fn unary_with_side_effect() { 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; + let mut e: E = E::EA; e = E(e.0.wrapping_add(u)); i = (i as ::core::ffi::c_uint).wrapping_add(u) as ::core::ffi::c_int; } @@ -77,7 +81,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.0 as ::core::ffi::c_int; + let mut i: ::core::ffi::c_int = C2Rust_Unnamed::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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.snap index 80f72a78ae..7c51911348 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.snap @@ -14,8 +14,10 @@ expression: cat tests/snapshots/macrocase.2021.rs #[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); +impl ZSTD_dParameter { + pub const ZSTD_d_windowLogMax: Self = Self(100); + pub const ZSTD_d_experimentalParam1: Self = Self(1000); +} 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 { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.snap index b43e54ee7c..cf45f89d09 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.snap @@ -15,8 +15,10 @@ expression: cat tests/snapshots/macrocase.2024.rs #[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); +impl ZSTD_dParameter { + pub const ZSTD_d_windowLogMax: Self = Self(100); + pub const ZSTD_d_experimentalParam1: Self = Self(1000); +} 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 { diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.snap index 58318ae207..cf27817a68 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.snap @@ -17,8 +17,10 @@ pub struct AnonEnumInStruct {} #[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); +impl C2Rust_Unnamed { + pub const VALUE1: Self = Self(0); + pub const VALUE2: Self = Self(1); +} #[derive(Copy, Clone)] #[repr(C)] pub struct AnonStructInStruct { @@ -45,8 +47,10 @@ pub union AnonEnumInUnion { #[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); +impl C2Rust_Unnamed_1 { + pub const VALUE3: Self = Self(0); + pub const VALUE4: Self = Self(1); +} #[derive(Copy, Clone)] #[repr(C)] pub union AnonStructInUnion { @@ -70,7 +74,7 @@ pub struct InsideUnion { } #[no_mangle] pub unsafe extern "C" fn struct_declaration() { - let mut value: ::core::ffi::c_int = VALUE2.0 as ::core::ffi::c_int; + let mut value: ::core::ffi::c_int = C2Rust_Unnamed::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 }, @@ -81,7 +85,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.0 as ::core::ffi::c_int; + let mut value: ::core::ffi::c_int = C2Rust_Unnamed_1::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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.snap index d56651d10e..a275115830 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.snap @@ -18,8 +18,10 @@ pub struct AnonEnumInStruct {} #[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); +impl C2Rust_Unnamed { + pub const VALUE1: Self = Self(0); + pub const VALUE2: Self = Self(1); +} #[derive(Copy, Clone)] #[repr(C)] pub struct AnonStructInStruct { @@ -46,8 +48,10 @@ pub union AnonEnumInUnion { #[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); +impl C2Rust_Unnamed_1 { + pub const VALUE3: Self = Self(0); + pub const VALUE4: Self = Self(1); +} #[derive(Copy, Clone)] #[repr(C)] pub union AnonStructInUnion { @@ -71,7 +75,7 @@ pub struct InsideUnion { } #[unsafe(no_mangle)] pub unsafe extern "C" fn struct_declaration() { - let mut value: ::core::ffi::c_int = VALUE2.0 as ::core::ffi::c_int; + let mut value: ::core::ffi::c_int = C2Rust_Unnamed::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 }, @@ -82,7 +86,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.0 as ::core::ffi::c_int; + let mut value: ::core::ffi::c_int = C2Rust_Unnamed_1::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.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2021.snap index 939779e06b..0be49a45c9 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2021.snap @@ -15,7 +15,9 @@ expression: cat tests/snapshots/scalar_init.2021.rs #[derive(Clone, Copy)] #[repr(transparent)] pub struct E(pub ::core::ffi::c_uint); -pub const A: E = E(0); +impl E { + pub const A: Self = Self(0); +} pub const true_0: ::core::ffi::c_int = 1 as ::core::ffi::c_int; #[no_mangle] pub unsafe extern "C" fn scalar_init() { @@ -26,7 +28,7 @@ pub unsafe extern "C" fn scalar_init() { let mut f: ::core::ffi::c_float = 42.0f32; let mut d: ::core::ffi::c_double = 42.0f64; let mut ld: ::f128::f128 = ::f128::f128::new(42.0); - let mut e: E = A; + let mut e: E = E::A; let mut p: *mut ::core::ffi::c_int = &raw mut i; let mut eb: bool = false; let mut ec: ::core::ffi::c_char = 0; diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.snap index 191a7f06a1..0324cb9b79 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@scalar_init.c.2024.snap @@ -15,7 +15,9 @@ expression: cat tests/snapshots/scalar_init.2024.rs #[derive(Clone, Copy)] #[repr(transparent)] pub struct E(pub ::core::ffi::c_uint); -pub const A: E = E(0); +impl E { + pub const A: Self = Self(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() { @@ -26,7 +28,7 @@ pub unsafe extern "C" fn scalar_init() { let mut f: ::core::ffi::c_float = 42.0f32; let mut d: ::core::ffi::c_double = 42.0f64; let mut ld: ::f128::f128 = ::f128::f128::new(42.0); - let mut e: E = A; + let mut e: E = E::A; let mut p: *mut ::core::ffi::c_int = &raw mut i; let mut eb: bool = false; let mut ec: ::core::ffi::c_char = 0; diff --git a/tests/unit/enums/src/test_enums.rs b/tests/unit/enums/src/test_enums.rs index c100fd91cc..17224cd324 100644 --- a/tests/unit/enums/src/test_enums.rs +++ b/tests/unit/enums/src/test_enums.rs @@ -1,12 +1,10 @@ use crate::big_enum::{rust_entry5, E1, E2, E3}; -use crate::enum_as_int::{rust_entry, A, B, E}; +use crate::enum_as_int::{rust_entry, E}; use crate::enum_compound::rust_entry6; use crate::enum_duplicate::{e, rust_entry3}; use crate::enum_fwd_decl::rust_foo; use crate::enum_ret::{rust_entry2, Color}; -use crate::non_canonical_enum_def::{ - hrtimer_restart, rust_abc, HRTIMER_NORESTART, HRTIMER_RESTART, -}; +use crate::non_canonical_enum_def::{hrtimer_restart, rust_abc}; use crate::top_enum::{rust_entry4, E as otherE}; use std::ffi::{c_int, c_uint}; @@ -35,8 +33,8 @@ const BUFFER_SIZE6: usize = 1; #[test] pub fn test_variants() { - assert_eq!(A.0 as u32, 0); - assert_eq!(B.0 as u32, 1); + assert_eq!(E::A.0 as u32, 0); + assert_eq!(E::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 505aee8937..111b1d0b7f 100644 --- a/tests/unit/misc/src/test_uninitialized.rs +++ b/tests/unit/misc/src/test_uninitialized.rs @@ -1,6 +1,6 @@ //! feature_raw_ref_op -use crate::uninitialized::{bar, baz, e, foo, rust_entry2, s, /*myint, myintp,*/ u}; +use crate::uninitialized::{e, rust_entry2, s, /*myint, myintp,*/ u}; use std::ffi::{c_int, c_uint}; unsafe extern "C" { @@ -26,9 +26,9 @@ pub fn test_buffer() { #[test] pub fn test_types() { - assert_eq!(foo.0 as u32, 1); - assert_eq!(bar.0 as u32, 2); - assert_eq!(baz.0 as u32, 3); + assert_eq!(e::foo.0 as u32, 1); + assert_eq!(e::bar.0 as u32, 2); + assert_eq!(e::baz.0 as u32, 3); // FIXME: union fields are private // let my_union = u { x: 32 };