Skip to content

Commit acdff78

Browse files
committed
transpile: Add EnumMode::NewType and make it the default
1 parent 29626c3 commit acdff78

15 files changed

Lines changed: 125 additions & 63 deletions

c2rust-transpile/src/translator/enums.rs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ impl<'c> Translation<'c> {
2525
.expect("Enums should already be renamed");
2626
let integral_type_rs = self.convert_type(integral_type.ctype)?;
2727
let item = match self.tcfg.enum_mode {
28+
EnumMode::NewType => {
29+
let field = mk().pub_().enum_field(integral_type_rs);
30+
mk().span(span)
31+
.call_attr("derive", vec!["Clone", "Copy"])
32+
.call_attr("repr", vec!["transparent"])
33+
.pub_()
34+
.struct_item(enum_name, vec![field], true)
35+
}
36+
2837
EnumMode::Consts => mk()
2938
.span(span)
3039
.pub_()
@@ -51,16 +60,16 @@ impl<'c> Translation<'c> {
5160
.borrow()
5261
.resolve_decl_name(enum_id)
5362
.expect("Enums should already be renamed");
54-
self.add_import(enum_id, &enum_name);
5563

5664
let ty = mk().ident_ty(enum_name);
5765
let val = match value {
5866
ConstIntExpr::I(value) => signed_int_expr(value),
5967
ConstIntExpr::U(value) => mk().lit_expr(mk().int_unsuffixed_lit(value as u128)),
6068
};
69+
let init = self.enum_constructor_expr(enum_id, val);
6170

6271
Ok(ConvertedDecl::Item(
63-
mk().span(span).pub_().const_item(name, ty, val),
72+
mk().span(span).pub_().const_item(name, ty, init),
6473
))
6574
}
6675

@@ -88,8 +97,14 @@ impl<'c> Translation<'c> {
8897
ctx: ExprContext,
8998
enum_id: CEnumId,
9099
target_cty: CQualTypeId,
91-
val: Box<Expr>,
100+
mut val: Box<Expr>,
92101
) -> TranslationResult<WithStmts<Box<Expr>>> {
102+
match self.tcfg.enum_mode {
103+
// First extract the enum's inner type...
104+
EnumMode::NewType => val = self.integer_from_enum(val),
105+
EnumMode::Consts => {}
106+
}
107+
93108
// Cast from the enum's integral type to the expected integral type.
94109
let source_cty = self.enum_integral_type(enum_id);
95110
self.convert_cast(
@@ -103,12 +118,15 @@ impl<'c> Translation<'c> {
103118
)
104119
}
105120

106-
/// Translate a cast where the target type is an `enum` type.
107-
///
108-
/// When translating variable references to `EnumConstant`s, we always insert casts to the
109-
/// expected type. In C, `EnumConstant`s have some integral type, _not_ the enum type. However,
110-
/// if we then immediately have a cast to convert this variable back into an enum type, we would
111-
/// like to produce Rust with _no_ casts. This function handles this simplification.
121+
/// Gets the inner integral value of an enum value.
122+
pub fn integer_from_enum(&self, val: Box<Expr>) -> Box<Expr> {
123+
match self.tcfg.enum_mode {
124+
EnumMode::NewType => mk().anon_field_expr(val, 0),
125+
EnumMode::Consts => val,
126+
}
127+
}
128+
129+
/// Translates a cast where the target type is an `enum` type.
112130
pub fn convert_cast_to_enum(
113131
&self,
114132
ctx: ExprContext,
@@ -163,13 +181,23 @@ impl<'c> Translation<'c> {
163181
return Ok(WithStmts::new_val(val));
164182
}
165183

184+
match self.tcfg.enum_mode {
185+
// Enum-to-enum casts need to be translated via the inner value as an intermediate.
186+
EnumMode::NewType => val = self.integer_from_enum(val),
187+
EnumMode::Consts => {}
188+
}
189+
166190
source_cty = self.enum_integral_type(source_enum_id);
167191
}
168192

169193
let enum_integral_type = self.enum_integral_type(enum_id);
170194
let mut val = WithStmts::new_val(val);
171195

172196
match self.tcfg.enum_mode {
197+
EnumMode::NewType => {
198+
val = val.map(|val| self.enum_constructor_expr(enum_id, val));
199+
}
200+
173201
EnumMode::Consts => {
174202
let source_type_kind = &self.ast_context.resolve_type(source_cty.ctype).kind;
175203
let enum_integral_type_kind =
@@ -234,6 +262,7 @@ impl<'c> Translation<'c> {
234262
self.add_import(enum_id, &enum_name);
235263

236264
match self.tcfg.enum_mode {
265+
EnumMode::NewType => mk().call_expr(mk().ident_expr(enum_name), vec![value]),
237266
EnumMode::Consts => mk().cast_expr(value, mk().ident_ty(enum_name)),
238267
}
239268
}

c2rust-transpile/src/translator/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4021,7 +4021,6 @@ impl<'c> Translation<'c> {
40214021
field.map(|field| mk().struct_expr(vec![name], vec![field]))
40224022
}
40234023

4024-
// Transmute the number `0` into the enum type
40254024
CDeclKind::Enum { .. } => self.convert_enum_zero_initializer(decl_id),
40264025

40274026
_ => {
@@ -4126,7 +4125,7 @@ impl<'c> Translation<'c> {
41264125
}
41274126

41284127
let val = if ty.is_enum() {
4129-
mk().cast_expr(val, mk().path_ty(vec!["u64"]))
4128+
self.integer_from_enum(val)
41304129
} else {
41314130
val
41324131
};
@@ -4450,5 +4449,6 @@ fn wrapping_neg_expr(arg: Box<Expr>) -> Box<Expr> {
44504449

44514450
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44524451
pub enum EnumMode {
4452+
NewType,
44534453
Consts,
44544454
}

c2rust-transpile/src/translator/pointers.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ impl<'c> Translation<'c> {
249249
let lhs_node_type = lhs_node
250250
.get_type()
251251
.ok_or_else(|| format_err!("lhs node bad type"))?;
252+
let rhs_node_type = rhs_node
253+
.get_type()
254+
.ok_or_else(|| format_err!("rhs node bad type"))?;
255+
252256
if self
253257
.ast_context
254258
.resolve_type(lhs_node_type)
@@ -262,7 +266,12 @@ impl<'c> Translation<'c> {
262266
}
263267

264268
let rhs = self.convert_expr(ctx.used(), rhs, None)?;
265-
rhs.and_then(|rhs| {
269+
rhs.and_then(|mut rhs| {
270+
// C allows enums to index arrays directly without inserting a numeric cast.
271+
if let CTypeKind::Enum(..) = self.ast_context.resolve_type(rhs_node_type).kind {
272+
rhs = self.integer_from_enum(rhs);
273+
}
274+
266275
let simple_index_array = if ctx.needs_address() {
267276
// We can't necessarily index into an array if we're using
268277
// that element to compute an address.

c2rust-transpile/tests/snapshots.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ fn config(edition: RustEdition) -> TranspilerConfig {
6666
.unwrap()
6767
.to_path_buf(),
6868
),
69-
enum_mode: EnumMode::Consts,
69+
enum_mode: EnumMode::NewType,
7070
}
7171
}
7272

c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.snap

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ expression: cat tests/snapshots/exprs.2021.rs
1616
extern "C" {
1717
fn puts(str: *const ::core::ffi::c_char) -> ::core::ffi::c_int;
1818
}
19-
pub type E = ::core::ffi::c_uint;
20-
pub const EA: E = 0;
19+
#[derive(Clone, Copy)]
20+
#[repr(transparent)]
21+
pub struct E(pub ::core::ffi::c_uint);
22+
pub const EA: E = E(0);
2123
pub type int_t = ::core::ffi::c_int;
22-
pub type C2Rust_Unnamed = ::core::ffi::c_uint;
23-
pub const C: C2Rust_Unnamed = 2;
24-
pub const B: C2Rust_Unnamed = 1;
25-
pub const A: C2Rust_Unnamed = 0;
24+
#[derive(Clone, Copy)]
25+
#[repr(transparent)]
26+
pub struct C2Rust_Unnamed(pub ::core::ffi::c_uint);
27+
pub const C: C2Rust_Unnamed = C2Rust_Unnamed(2);
28+
pub const B: C2Rust_Unnamed = C2Rust_Unnamed(1);
29+
pub const A: C2Rust_Unnamed = C2Rust_Unnamed(0);
2630
unsafe extern "C" fn side_effect() -> ::core::ffi::c_int {
2731
puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char);
2832
return 10 as ::core::ffi::c_int;
@@ -61,7 +65,7 @@ pub unsafe extern "C" fn unsigned_compound_desugaring() {
6165
let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int;
6266
let mut u: ::core::ffi::c_uint = 0 as ::core::ffi::c_uint;
6367
let mut e: E = EA;
64-
e = e.wrapping_add(u);
68+
e = E(e.0.wrapping_add(u));
6569
i = (i as ::core::ffi::c_uint).wrapping_add(u) as ::core::ffi::c_int;
6670
}
6771
#[no_mangle]
@@ -73,7 +77,7 @@ pub unsafe extern "C" fn cast_literals() {
7377
}
7478
#[no_mangle]
7579
pub unsafe extern "C" fn compound_literal() {
76-
let mut i: ::core::ffi::c_int = B as ::core::ffi::c_int;
80+
let mut i: ::core::ffi::c_int = B.0 as ::core::ffi::c_int;
7781
}
7882
#[no_mangle]
7983
pub unsafe extern "C" fn statement_expr() {

c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.snap

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ expression: cat tests/snapshots/exprs.2024.rs
1616
unsafe extern "C" {
1717
unsafe fn puts(str: *const ::core::ffi::c_char) -> ::core::ffi::c_int;
1818
}
19-
pub type E = ::core::ffi::c_uint;
20-
pub const EA: E = 0;
19+
#[derive(Clone, Copy)]
20+
#[repr(transparent)]
21+
pub struct E(pub ::core::ffi::c_uint);
22+
pub const EA: E = E(0);
2123
pub type int_t = ::core::ffi::c_int;
22-
pub type C2Rust_Unnamed = ::core::ffi::c_uint;
23-
pub const C: C2Rust_Unnamed = 2;
24-
pub const B: C2Rust_Unnamed = 1;
25-
pub const A: C2Rust_Unnamed = 0;
24+
#[derive(Clone, Copy)]
25+
#[repr(transparent)]
26+
pub struct C2Rust_Unnamed(pub ::core::ffi::c_uint);
27+
pub const C: C2Rust_Unnamed = C2Rust_Unnamed(2);
28+
pub const B: C2Rust_Unnamed = C2Rust_Unnamed(1);
29+
pub const A: C2Rust_Unnamed = C2Rust_Unnamed(0);
2630
unsafe extern "C" fn side_effect() -> ::core::ffi::c_int {
2731
puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char);
2832
return 10 as ::core::ffi::c_int;
@@ -61,7 +65,7 @@ pub unsafe extern "C" fn unsigned_compound_desugaring() {
6165
let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int;
6266
let mut u: ::core::ffi::c_uint = 0 as ::core::ffi::c_uint;
6367
let mut e: E = EA;
64-
e = e.wrapping_add(u);
68+
e = E(e.0.wrapping_add(u));
6569
i = (i as ::core::ffi::c_uint).wrapping_add(u) as ::core::ffi::c_int;
6670
}
6771
#[unsafe(no_mangle)]
@@ -73,7 +77,7 @@ pub unsafe extern "C" fn cast_literals() {
7377
}
7478
#[unsafe(no_mangle)]
7579
pub unsafe extern "C" fn compound_literal() {
76-
let mut i: ::core::ffi::c_int = B as ::core::ffi::c_int;
80+
let mut i: ::core::ffi::c_int = B.0 as ::core::ffi::c_int;
7781
}
7882
#[unsafe(no_mangle)]
7983
pub unsafe extern "C" fn statement_expr() {

c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2021.snap

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ expression: cat tests/snapshots/macrocase.2021.rs
1111
unused_assignments,
1212
unused_mut
1313
)]
14-
pub type ZSTD_dParameter = ::core::ffi::c_uint;
15-
pub const ZSTD_d_experimentalParam1: ZSTD_dParameter = 1000;
16-
pub const ZSTD_d_windowLogMax: ZSTD_dParameter = 100;
14+
#[derive(Clone, Copy)]
15+
#[repr(transparent)]
16+
pub struct ZSTD_dParameter(pub ::core::ffi::c_uint);
17+
pub const ZSTD_d_experimentalParam1: ZSTD_dParameter = ZSTD_dParameter(1000);
18+
pub const ZSTD_d_windowLogMax: ZSTD_dParameter = ZSTD_dParameter(100);
1719
pub const ZSTD_d_format: ::core::ffi::c_uint = 1000 as ::core::ffi::c_uint;
1820
#[no_mangle]
1921
pub unsafe extern "C" fn ZSTD_dParam_getBounds(mut dParam: ZSTD_dParameter) -> ::core::ffi::c_int {
2022
let mut bounds: ::core::ffi::c_int = 0 as ::core::ffi::c_int;
21-
match dParam {
23+
match dParam.0 {
2224
100 => {
2325
bounds = 1 as ::core::ffi::c_int;
2426
return bounds;

c2rust-transpile/tests/snapshots/snapshots__transpile@macrocase.c.2024.snap

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,16 @@ expression: cat tests/snapshots/macrocase.2024.rs
1212
unused_assignments,
1313
unused_mut
1414
)]
15-
pub type ZSTD_dParameter = ::core::ffi::c_uint;
16-
pub const ZSTD_d_experimentalParam1: ZSTD_dParameter = 1000;
17-
pub const ZSTD_d_windowLogMax: ZSTD_dParameter = 100;
15+
#[derive(Clone, Copy)]
16+
#[repr(transparent)]
17+
pub struct ZSTD_dParameter(pub ::core::ffi::c_uint);
18+
pub const ZSTD_d_experimentalParam1: ZSTD_dParameter = ZSTD_dParameter(1000);
19+
pub const ZSTD_d_windowLogMax: ZSTD_dParameter = ZSTD_dParameter(100);
1820
pub const ZSTD_d_format: ::core::ffi::c_uint = 1000 as ::core::ffi::c_uint;
1921
#[unsafe(no_mangle)]
2022
pub unsafe extern "C" fn ZSTD_dParam_getBounds(mut dParam: ZSTD_dParameter) -> ::core::ffi::c_int {
2123
let mut bounds: ::core::ffi::c_int = 0 as ::core::ffi::c_int;
22-
match dParam {
24+
match dParam.0 {
2325
100 => {
2426
bounds = 1 as ::core::ffi::c_int;
2527
return bounds;

c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2021.snap

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ expression: cat tests/snapshots/records.2021.rs
1414
#[derive(Copy, Clone)]
1515
#[repr(C)]
1616
pub struct AnonEnumInStruct {}
17-
pub type C2Rust_Unnamed = ::core::ffi::c_uint;
18-
pub const VALUE2: C2Rust_Unnamed = 1;
19-
pub const VALUE1: C2Rust_Unnamed = 0;
17+
#[derive(Clone, Copy)]
18+
#[repr(transparent)]
19+
pub struct C2Rust_Unnamed(pub ::core::ffi::c_uint);
20+
pub const VALUE2: C2Rust_Unnamed = C2Rust_Unnamed(1);
21+
pub const VALUE1: C2Rust_Unnamed = C2Rust_Unnamed(0);
2022
#[derive(Copy, Clone)]
2123
#[repr(C)]
2224
pub struct AnonStructInStruct {
@@ -40,9 +42,11 @@ pub struct InsideStruct {
4042
pub union AnonEnumInUnion {
4143
pub a: ::core::ffi::c_int,
4244
}
43-
pub type C2Rust_Unnamed_1 = ::core::ffi::c_uint;
44-
pub const VALUE4: C2Rust_Unnamed_1 = 1;
45-
pub const VALUE3: C2Rust_Unnamed_1 = 0;
45+
#[derive(Clone, Copy)]
46+
#[repr(transparent)]
47+
pub struct C2Rust_Unnamed_1(pub ::core::ffi::c_uint);
48+
pub const VALUE4: C2Rust_Unnamed_1 = C2Rust_Unnamed_1(1);
49+
pub const VALUE3: C2Rust_Unnamed_1 = C2Rust_Unnamed_1(0);
4650
#[derive(Copy, Clone)]
4751
#[repr(C)]
4852
pub union AnonStructInUnion {
@@ -66,7 +70,7 @@ pub struct InsideUnion {
6670
}
6771
#[no_mangle]
6872
pub unsafe extern "C" fn struct_declaration() {
69-
let mut value: ::core::ffi::c_int = VALUE2 as ::core::ffi::c_int;
73+
let mut value: ::core::ffi::c_int = VALUE2.0 as ::core::ffi::c_int;
7074
let mut a: AnonEnumInStruct = AnonEnumInStruct {};
7175
let mut b: AnonStructInStruct = AnonStructInStruct {
7276
c2rust_unnamed: C2Rust_Unnamed_0 { some_number: 0 },
@@ -77,7 +81,7 @@ pub unsafe extern "C" fn struct_declaration() {
7781
}
7882
#[no_mangle]
7983
pub unsafe extern "C" fn union_declaration() {
80-
let mut value: ::core::ffi::c_int = VALUE4 as ::core::ffi::c_int;
84+
let mut value: ::core::ffi::c_int = VALUE4.0 as ::core::ffi::c_int;
8185
let mut a: AnonEnumInUnion = AnonEnumInUnion { a: 0 };
8286
let mut b: AnonStructInUnion = AnonStructInUnion {
8387
c2rust_unnamed: C2Rust_Unnamed_2 { some_number: 0 },

c2rust-transpile/tests/snapshots/snapshots__transpile@records.c.2024.snap

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ expression: cat tests/snapshots/records.2024.rs
1515
#[derive(Copy, Clone)]
1616
#[repr(C)]
1717
pub struct AnonEnumInStruct {}
18-
pub type C2Rust_Unnamed = ::core::ffi::c_uint;
19-
pub const VALUE2: C2Rust_Unnamed = 1;
20-
pub const VALUE1: C2Rust_Unnamed = 0;
18+
#[derive(Clone, Copy)]
19+
#[repr(transparent)]
20+
pub struct C2Rust_Unnamed(pub ::core::ffi::c_uint);
21+
pub const VALUE2: C2Rust_Unnamed = C2Rust_Unnamed(1);
22+
pub const VALUE1: C2Rust_Unnamed = C2Rust_Unnamed(0);
2123
#[derive(Copy, Clone)]
2224
#[repr(C)]
2325
pub struct AnonStructInStruct {
@@ -41,9 +43,11 @@ pub struct InsideStruct {
4143
pub union AnonEnumInUnion {
4244
pub a: ::core::ffi::c_int,
4345
}
44-
pub type C2Rust_Unnamed_1 = ::core::ffi::c_uint;
45-
pub const VALUE4: C2Rust_Unnamed_1 = 1;
46-
pub const VALUE3: C2Rust_Unnamed_1 = 0;
46+
#[derive(Clone, Copy)]
47+
#[repr(transparent)]
48+
pub struct C2Rust_Unnamed_1(pub ::core::ffi::c_uint);
49+
pub const VALUE4: C2Rust_Unnamed_1 = C2Rust_Unnamed_1(1);
50+
pub const VALUE3: C2Rust_Unnamed_1 = C2Rust_Unnamed_1(0);
4751
#[derive(Copy, Clone)]
4852
#[repr(C)]
4953
pub union AnonStructInUnion {
@@ -67,7 +71,7 @@ pub struct InsideUnion {
6771
}
6872
#[unsafe(no_mangle)]
6973
pub unsafe extern "C" fn struct_declaration() {
70-
let mut value: ::core::ffi::c_int = VALUE2 as ::core::ffi::c_int;
74+
let mut value: ::core::ffi::c_int = VALUE2.0 as ::core::ffi::c_int;
7175
let mut a: AnonEnumInStruct = AnonEnumInStruct {};
7276
let mut b: AnonStructInStruct = AnonStructInStruct {
7377
c2rust_unnamed: C2Rust_Unnamed_0 { some_number: 0 },
@@ -78,7 +82,7 @@ pub unsafe extern "C" fn struct_declaration() {
7882
}
7983
#[unsafe(no_mangle)]
8084
pub unsafe extern "C" fn union_declaration() {
81-
let mut value: ::core::ffi::c_int = VALUE4 as ::core::ffi::c_int;
85+
let mut value: ::core::ffi::c_int = VALUE4.0 as ::core::ffi::c_int;
8286
let mut a: AnonEnumInUnion = AnonEnumInUnion { a: 0 };
8387
let mut b: AnonStructInUnion = AnonStructInUnion {
8488
c2rust_unnamed: C2Rust_Unnamed_2 { some_number: 0 },

0 commit comments

Comments
 (0)