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/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 d1a9c0b8c9..924f5a4ed1 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -2,13 +2,14 @@ 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, - 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, CTypeId, - CTypeKind, ConstIntExpr, + CDeclKind, CEnumConstantId, CEnumId, CExprId, CExprKind, CLiteral, CQualTypeId, CTypeKind, + ConstIntExpr, }; impl<'c> Translation<'c> { @@ -17,77 +18,158 @@ impl<'c> Translation<'c> { enum_id: CEnumId, span: Span, integral_type: CQualTypeId, + variants: &[CEnumConstantId], ) -> TranslationResult { let enum_name = &self .type_converter .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 enum_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) + } - pub fn convert_enum_constant( - &self, - enum_constant_id: CEnumConstantId, - span: Span, - value: ConstIntExpr, - ) -> 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"); - self.add_import(enum_id, &enum_name); + EnumMode::Consts => mk() + .span(span) + .pub_() + .type_item(enum_name, integral_type_rs), + }; + + if variants.is_empty() { + return Ok(ConvertedDecl::Item(enum_item)); + } + + 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 ty = mk().ident_ty(enum_name); - let val = match value { + 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) { + 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, true); + let span = self + .get_span(SomeId::Decl(enum_constant_id)) + .unwrap_or_else(Span::call_site); - Ok(ConvertedDecl::Item( - mk().span(span).pub_().const_item(name, ty, val), - )) + (span, init) } - 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`. + 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_id, enum_constant_id); + + // Add a cast to the expected integral type. + 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, - target_cty: CTypeId, - val: Box, - ) -> TranslationResult> { - // Convert it to the expected integral type. - let ty = self.convert_type(target_cty)?; - Ok(mk().cast_expr(val, ty)) + ctx: ExprContext, + enum_id: CEnumId, + target_cty: CQualTypeId, + 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( + ctx, + source_cty, + target_cty, + WithStmts::new_val(val), + None, + None, + None, + ) } - /// 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, - enum_type_id: CTypeId, + mut source_cty: 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 +184,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_id, 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_id, 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_id, -(i as i64)); + return Ok(WithStmts::new_val(val)); } } @@ -122,20 +207,53 @@ impl<'c> Translation<'c> { } } - let target_ty = self.convert_type(enum_type_id)?; - Ok(mk().cast_expr(val, target_ty)) + // 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)); + } + + 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); + } + + let enum_integral_type = self.enum_integral_type(enum_id); + 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, false)); + } + + 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, false)); + } + } + } + + Ok(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); + return self.enum_constant_expr(enum_id, enum_constant_id); } let underlying_type_id = self.enum_integral_type(enum_id); @@ -145,8 +263,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, false) } /// Returns the id of the variant of `enum_id` whose value matches `value`, if any. @@ -167,10 +284,65 @@ 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]) + } + + 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 => { + 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)) + } + } } fn is_variant_of_enum(&self, enum_id: CEnumId, enum_constant_id: CEnumConstantId) -> bool { @@ -182,7 +354,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/mod.rs b/c2rust-transpile/src/translator/mod.rs index ad2a65089c..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` @@ -1927,11 +1929,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 { value, .. } => self.convert_enum_constant(decl_id, span, value), + // 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 @@ -3063,117 +3067,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 +3431,127 @@ 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", + )); + } + } + + if let CDeclKind::EnumConstant { .. } = decl { + return self.convert_enum_constant_decl_ref(ctx, decl_id, qual_ty); + } + + 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() + .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 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)), @@ -3696,20 +3713,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 @@ -3743,17 +3756,16 @@ 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 { - // Casts targeting `enum` types... - val.result_map(|val| { - self.convert_cast_to_enum(ctx, target_cty.ctype, 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, 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.result_map(|val| self.convert_cast_from_enum(target_cty.ctype, 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))) } @@ -4018,8 +4030,7 @@ 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(type_id), + CDeclKind::Enum { .. } => self.convert_enum_zero_initializer(decl_id), _ => { return Err(TranslationError::generic( @@ -4123,7 +4134,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 }; @@ -4444,3 +4455,9 @@ 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 { + NewType, + Consts, +} 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), ) } diff --git a/c2rust-transpile/src/translator/pointers.rs b/c2rust-transpile/src/translator/pointers.rs index 5fd92a4718..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. @@ -431,28 +440,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 +470,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 +478,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, @@ -501,8 +510,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.result_map(|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))) } @@ -511,8 +520,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 +532,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) - }) + } else if let &CTypeKind::Enum(enum_id) = target_ty_kind { + 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.rs b/c2rust-transpile/tests/snapshots.rs index 31c16e1abc..7961105342 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::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 a5a516345c..03139a17ad 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,21 @@ 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); +impl E { + pub const EA: Self = Self(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); +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; @@ -60,8 +68,8 @@ 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; - e = (e as ::core::ffi::c_uint).wrapping_add(u) as E; + 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; } #[no_mangle] @@ -73,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 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 ea96797d26..9c60e753a3 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,21 @@ 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); +impl E { + pub const EA: Self = Self(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); +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; @@ -60,8 +68,8 @@ 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; - e = (e as ::core::ffi::c_uint).wrapping_add(u) as E; + 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; } #[unsafe(no_mangle)] @@ -73,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 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 1d6f669dd7..7c51911348 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,18 @@ 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); +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 { let mut bounds: ::core::ffi::c_int = 0 as ::core::ffi::c_int; - match dParam as ::core::ffi::c_uint { + 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 3c0a0e3f8e..cf45f89d09 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,18 @@ 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); +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 { let mut bounds: ::core::ffi::c_int = 0 as ::core::ffi::c_int; - match dParam as ::core::ffi::c_uint { + 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..cf27817a68 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,13 @@ 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); +impl C2Rust_Unnamed { + pub const VALUE1: Self = Self(0); + pub const VALUE2: Self = Self(1); +} #[derive(Copy, Clone)] #[repr(C)] pub struct AnonStructInStruct { @@ -40,9 +44,13 @@ 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); +impl C2Rust_Unnamed_1 { + pub const VALUE3: Self = Self(0); + pub const VALUE4: Self = Self(1); +} #[derive(Copy, Clone)] #[repr(C)] pub union AnonStructInUnion { @@ -66,7 +74,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 = 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 }, @@ -77,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 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 9542e98d9d..a275115830 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,13 @@ 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); +impl C2Rust_Unnamed { + pub const VALUE1: Self = Self(0); + pub const VALUE2: Self = Self(1); +} #[derive(Copy, Clone)] #[repr(C)] pub struct AnonStructInStruct { @@ -41,9 +45,13 @@ 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); +impl C2Rust_Unnamed_1 { + pub const VALUE3: Self = Self(0); + pub const VALUE4: Self = Self(1); +} #[derive(Copy, Clone)] #[repr(C)] pub union AnonStructInUnion { @@ -67,7 +75,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 = 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 }, @@ -78,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 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 218d95ca55..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 @@ -12,8 +12,12 @@ 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); +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() { @@ -24,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 5109df4c13..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 @@ -12,8 +12,12 @@ 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); +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() { @@ -24,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/src/bin/c2rust-transpile.rs b/c2rust/src/bin/c2rust-transpile.rs index 39f5ada8e7..34a272ac67 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::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..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 as u32, 0); - assert_eq!(B 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 87425c5b32..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 as u32, 1); - assert_eq!(bar as u32, 2); - assert_eq!(baz 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 };