Skip to content

Commit 1168841

Browse files
committed
transpile: Translate EnumConstant with associated constants
1 parent 5ed9da7 commit 1168841

13 files changed

Lines changed: 177 additions & 94 deletions

c2rust-ast-builder/src/builder.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,26 @@ impl Builder {
14161416
}))
14171417
}
14181418

1419+
pub fn const_impl_item<I>(self, name: I, ty: Box<Type>, init: Box<Expr>) -> ImplItem
1420+
where
1421+
I: Make<Ident>,
1422+
{
1423+
let name = name.make(&self);
1424+
ImplItem::Const(ImplItemConst {
1425+
attrs: self.attrs,
1426+
vis: self.vis,
1427+
defaultness: None,
1428+
const_token: Token![const](self.span),
1429+
ident: name,
1430+
generics: self.generics,
1431+
colon_token: Token![:](self.span),
1432+
ty: *ty,
1433+
eq_token: Token![=](self.span),
1434+
expr: *init,
1435+
semi_token: Token![;](self.span),
1436+
})
1437+
}
1438+
14191439
pub fn fn_item<S>(self, sig: S, mut block: Block) -> Box<Item>
14201440
where
14211441
S: Make<Signature>,

c2rust-transpile/src/translator/enums.rs

Lines changed: 84 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use c2rust_ast_builder::mk;
22
use proc_macro2::Span;
3-
use syn::Expr;
3+
use syn::{Expr, ImplItem};
44

55
use crate::c_ast::CUnOp;
66
use crate::{
7+
c_ast::iterators::SomeId,
78
diagnostics::TranslationResult,
89
translator::{signed_int_expr, ConvertedDecl, ExprContext, Translation},
910
with_stmts::WithStmts,
@@ -17,6 +18,7 @@ impl<'c> Translation<'c> {
1718
enum_id: CEnumId,
1819
span: Span,
1920
integral_type: CQualTypeId,
21+
variants: &[CEnumConstantId],
2022
) -> TranslationResult<ConvertedDecl> {
2123
let enum_name = &self
2224
.type_converter
@@ -34,43 +36,62 @@ impl<'c> Translation<'c> {
3436
.pub_()
3537
.struct_item(enum_name, vec![field], true);
3638

37-
Ok(ConvertedDecl::Item(item))
38-
}
39+
if variants.is_empty() {
40+
return Ok(ConvertedDecl::Item(item));
41+
}
3942

40-
pub fn convert_enum_constant(
41-
&self,
42-
enum_constant_id: CEnumConstantId,
43-
span: Span,
44-
value: ConstIntExpr,
45-
) -> TranslationResult<ConvertedDecl> {
46-
let name = self
47-
.renamer
48-
.borrow_mut()
49-
.get(&enum_constant_id)
50-
.expect("Enum constant not named");
51-
let enum_id = self.ast_context.parents[&enum_constant_id];
52-
let enum_name = self
53-
.type_converter
54-
.borrow()
55-
.resolve_decl_name(enum_id)
56-
.expect("Enums should already be renamed");
43+
let self_ty = mk().ident_ty("Self");
44+
let constants: Vec<ImplItem> = variants
45+
.iter()
46+
.map(|&enum_constant_id| {
47+
let span = self
48+
.get_span(SomeId::Decl(enum_constant_id))
49+
.unwrap_or_else(Span::call_site);
5750

58-
let ty = mk().ident_ty(enum_name.clone());
59-
let val = match value {
60-
ConstIntExpr::I(value) => signed_int_expr(value),
61-
ConstIntExpr::U(value) => mk().lit_expr(mk().int_unsuffixed_lit(value as u128)),
62-
};
63-
let init = self.enum_constructor_expr(enum_id, val);
51+
let (name, value) = match self.ast_context[enum_constant_id].kind {
52+
CDeclKind::EnumConstant {
53+
ref name, value, ..
54+
} => (name, value),
55+
_ => panic!("{:?} does not point to an enum variant", enum_constant_id),
56+
};
57+
let name = self.type_converter.borrow_mut().declare_field_name(
58+
enum_id,
59+
enum_constant_id,
60+
name,
61+
);
6462

65-
Ok(ConvertedDecl::Item(
66-
mk().span(span).pub_().const_item(name, ty, init),
67-
))
63+
let val = match value {
64+
ConstIntExpr::I(value) => signed_int_expr(value),
65+
ConstIntExpr::U(value) => mk().lit_expr(mk().int_unsuffixed_lit(value as u128)),
66+
};
67+
let init = self.enum_constructor_expr(enum_id, val, true);
68+
69+
mk().span(span)
70+
.pub_()
71+
.const_impl_item(name, self_ty.clone(), init)
72+
})
73+
.collect();
74+
let impl_block = mk().impl_item(mk().ident_ty(enum_name), constants);
75+
76+
Ok(ConvertedDecl::Items(vec![item, impl_block]))
6877
}
6978

7079
pub fn convert_enum_zero_initializer(&self, enum_id: CEnumId) -> WithStmts<Box<Expr>> {
7180
WithStmts::new_val(self.enum_for_i64(enum_id, 0))
7281
}
7382

83+
/// Translates a `DeclRef` for an `EnumConstant`.
84+
pub fn convert_enum_constant_decl_ref(
85+
&self,
86+
ctx: ExprContext,
87+
enum_constant_id: CEnumConstantId,
88+
target_cty: CQualTypeId,
89+
) -> TranslationResult<WithStmts<Box<Expr>>> {
90+
let enum_id = self.ast_context.parents[&enum_constant_id];
91+
let val = WithStmts::new_val(self.enum_constant_expr(enum_id, enum_constant_id));
92+
self.convert_cast_from_enum(ctx, enum_id, target_cty, val)
93+
}
94+
7495
/// Translate a cast where the source type, but not the target type, is an `enum` type.
7596
pub fn convert_cast_from_enum(
7697
&self,
@@ -115,7 +136,8 @@ impl<'c> Translation<'c> {
115136
// If this DeclRef expanded to a const macro, we actually need to insert a cast,
116137
// because the translation of a const macro skips implicit casts in its context.
117138
if !expr_is_macro {
118-
val = WithStmts::new_val(self.enum_constant_expr(enum_constant_id));
139+
val =
140+
WithStmts::new_val(self.enum_constant_expr(enum_id, enum_constant_id));
119141
return Ok(val);
120142
}
121143
}
@@ -150,7 +172,7 @@ impl<'c> Translation<'c> {
150172
// First cast to the enum's inner type, then construct a new enum value.
151173
let target_cty = self.enum_integral_type(enum_id);
152174
val = self.convert_cast(ctx, source_cty, target_cty, val, None, None, None)?;
153-
val = val.map(|val| self.enum_constructor_expr(enum_id, val));
175+
val = val.map(|val| self.enum_constructor_expr(enum_id, val, false));
154176

155177
Ok(val)
156178
}
@@ -159,7 +181,7 @@ impl<'c> Translation<'c> {
159181
/// variant directly, otherwise it converts a number to the enum type.
160182
fn enum_for_i64(&self, enum_id: CEnumId, value: i64) -> Box<Expr> {
161183
if let Some(enum_constant_id) = self.enum_variant_for_i64(enum_id, value) {
162-
return self.enum_constant_expr(enum_constant_id);
184+
return self.enum_constant_expr(enum_id, enum_constant_id);
163185
}
164186

165187
let underlying_type_id = self.enum_integral_type(enum_id);
@@ -169,7 +191,7 @@ impl<'c> Translation<'c> {
169191
_ => signed_int_expr(value),
170192
};
171193

172-
self.enum_constructor_expr(enum_id, value)
194+
self.enum_constructor_expr(enum_id, value, false)
173195
}
174196

175197
/// Returns the id of the variant of `enum_id` whose value matches `value`, if any.
@@ -190,20 +212,41 @@ impl<'c> Translation<'c> {
190212
})
191213
}
192214

193-
fn enum_constructor_expr(&self, enum_id: CEnumId, value: Box<Expr>) -> Box<Expr> {
215+
fn enum_constructor_expr(
216+
&self,
217+
enum_id: CEnumId,
218+
value: Box<Expr>,
219+
use_self_ty: bool,
220+
) -> Box<Expr> {
221+
let func = if use_self_ty {
222+
mk().ident_expr("Self")
223+
} else {
224+
let enum_name = self
225+
.type_converter
226+
.borrow()
227+
.resolve_decl_name(enum_id)
228+
.unwrap();
229+
self.add_import(enum_id, &enum_name);
230+
mk().ident_expr(enum_name)
231+
};
232+
233+
mk().call_expr(func, vec![value])
234+
}
235+
236+
fn enum_constant_expr(&self, enum_id: CEnumId, enum_constant_id: CEnumConstantId) -> Box<Expr> {
194237
let enum_name = self
195238
.type_converter
196239
.borrow()
197240
.resolve_decl_name(enum_id)
198241
.unwrap();
199-
self.add_import(enum_id, &enum_name);
200-
mk().call_expr(mk().ident_expr(enum_name), vec![value])
201-
}
242+
let name = self
243+
.type_converter
244+
.borrow()
245+
.resolve_field_name(Some(enum_id), enum_constant_id)
246+
.unwrap();
202247

203-
fn enum_constant_expr(&self, enum_constant_id: CEnumConstantId) -> Box<Expr> {
204-
let name = self.renamer.borrow().get(&enum_constant_id).unwrap();
205-
self.add_import(enum_constant_id, &name);
206-
mk().ident_expr(name)
248+
self.add_import(enum_id, &enum_name);
249+
mk().path_expr(vec![enum_name, name])
207250
}
208251

209252
fn is_variant_of_enum(&self, enum_id: CEnumId, enum_constant_id: CEnumConstantId) -> bool {

c2rust-transpile/src/translator/mod.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,6 @@ pub fn translate(
769769
Union { ref name, .. } => some_type_name(name.as_ref().map(String::as_str)),
770770
Typedef { ref name, .. } => Name::Type(name),
771771
Function { ref name, .. } => Name::Var(name),
772-
EnumConstant { ref name, .. } => Name::Var(name),
773772
Variable { ref ident, .. } if t.ast_context.c_decls_top.contains(&decl_id) => {
774773
Name::Var(ident)
775774
}
@@ -847,7 +846,6 @@ pub fn translate(
847846
let needs_export = match decl.kind {
848847
Struct { .. } => true,
849848
Enum { .. } => true,
850-
EnumConstant { .. } => true,
851849
Union { .. } => true,
852850
Typedef { .. } => {
853851
// Only check the key as opposed to `contains`
@@ -1924,11 +1922,13 @@ impl<'c> Translation<'c> {
19241922
)),
19251923

19261924
Enum {
1925+
ref variants,
19271926
integral_type: Some(integral_type),
19281927
..
1929-
} => self.convert_enum(decl_id, span, integral_type),
1928+
} => self.convert_enum(decl_id, span, integral_type, variants),
19301929

1931-
EnumConstant { value, .. } => self.convert_enum_constant(decl_id, span, value),
1930+
// EnumConstant is translated as part of Enum.
1931+
EnumConstant { .. } => Ok(ConvertedDecl::NoItem),
19321932

19331933
// We can allow non top level function declarations (i.e. extern
19341934
// declarations) without any problem. Clang doesn't support nested
@@ -3909,6 +3909,11 @@ impl<'c> Translation<'c> {
39093909
}
39103910

39113911
let varname = decl.get_name().expect("expected variable name").to_owned();
3912+
3913+
if let &CDeclKind::EnumConstant { .. } = decl {
3914+
return self.convert_enum_constant_decl_ref(ctx, decl_id, qual_ty);
3915+
}
3916+
39123917
let rustname = self
39133918
.renamer
39143919
.borrow_mut()
@@ -3926,13 +3931,6 @@ impl<'c> Translation<'c> {
39263931

39273932
let mut val = WithStmts::new_val(mk().path_expr(vec![rustname]));
39283933

3929-
// If the variable is actually an `EnumConstant`, we need to add a cast to the
3930-
// expected integral type.
3931-
if let &CDeclKind::EnumConstant { .. } = decl {
3932-
let enum_id = self.ast_context.parents[&decl_id];
3933-
return self.convert_cast_from_enum(ctx, enum_id, override_ty.unwrap_or(qual_ty), val);
3934-
}
3935-
39363934
// If we are referring to a function and need its address, we
39373935
// need to cast it to fn() to ensure that it has a real address.
39383936
if ctx.needs_address() {

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ extern "C" {
1818
#[derive(Clone, Copy)]
1919
#[repr(transparent)]
2020
pub struct E(pub ::core::ffi::c_uint);
21-
pub const EA: E = E(0);
21+
impl E {
22+
pub const EA: Self = Self(0);
23+
}
2224
#[derive(Clone, Copy)]
2325
#[repr(transparent)]
2426
pub struct C2Rust_Unnamed(pub ::core::ffi::c_uint);
25-
pub const C: C2Rust_Unnamed = C2Rust_Unnamed(2);
26-
pub const B: C2Rust_Unnamed = C2Rust_Unnamed(1);
27-
pub const A: C2Rust_Unnamed = C2Rust_Unnamed(0);
27+
impl C2Rust_Unnamed {
28+
pub const A: Self = Self(0);
29+
pub const B: Self = Self(1);
30+
pub const C: Self = Self(2);
31+
}
2832
unsafe extern "C" fn side_effect() -> ::core::ffi::c_int {
2933
puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char);
3034
return 10 as ::core::ffi::c_int;
@@ -62,13 +66,13 @@ pub unsafe extern "C" fn unary_with_side_effect() {
6266
pub unsafe extern "C" fn unsigned_compound_desugaring() {
6367
let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int;
6468
let mut u: ::core::ffi::c_uint = 0 as ::core::ffi::c_uint;
65-
let mut e: E = EA;
69+
let mut e: E = E::EA;
6670
e = E(e.0.wrapping_add(u));
6771
i = (i as ::core::ffi::c_uint).wrapping_add(u) as ::core::ffi::c_int;
6872
}
6973
#[no_mangle]
7074
pub unsafe extern "C" fn compound_literal() {
71-
let mut i: ::core::ffi::c_int = B.0 as ::core::ffi::c_int;
75+
let mut i: ::core::ffi::c_int = C2Rust_Unnamed::B.0 as ::core::ffi::c_int;
7276
}
7377
#[no_mangle]
7478
pub unsafe extern "C" fn statement_expr() {

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ unsafe extern "C" {
1818
#[derive(Clone, Copy)]
1919
#[repr(transparent)]
2020
pub struct E(pub ::core::ffi::c_uint);
21-
pub const EA: E = E(0);
21+
impl E {
22+
pub const EA: Self = Self(0);
23+
}
2224
#[derive(Clone, Copy)]
2325
#[repr(transparent)]
2426
pub struct C2Rust_Unnamed(pub ::core::ffi::c_uint);
25-
pub const C: C2Rust_Unnamed = C2Rust_Unnamed(2);
26-
pub const B: C2Rust_Unnamed = C2Rust_Unnamed(1);
27-
pub const A: C2Rust_Unnamed = C2Rust_Unnamed(0);
27+
impl C2Rust_Unnamed {
28+
pub const A: Self = Self(0);
29+
pub const B: Self = Self(1);
30+
pub const C: Self = Self(2);
31+
}
2832
unsafe extern "C" fn side_effect() -> ::core::ffi::c_int {
2933
puts(b"the return of side effect\0".as_ptr() as *const ::core::ffi::c_char);
3034
return 10 as ::core::ffi::c_int;
@@ -62,13 +66,13 @@ pub unsafe extern "C" fn unary_with_side_effect() {
6266
pub unsafe extern "C" fn unsigned_compound_desugaring() {
6367
let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int;
6468
let mut u: ::core::ffi::c_uint = 0 as ::core::ffi::c_uint;
65-
let mut e: E = EA;
69+
let mut e: E = E::EA;
6670
e = E(e.0.wrapping_add(u));
6771
i = (i as ::core::ffi::c_uint).wrapping_add(u) as ::core::ffi::c_int;
6872
}
6973
#[unsafe(no_mangle)]
7074
pub unsafe extern "C" fn compound_literal() {
71-
let mut i: ::core::ffi::c_int = B.0 as ::core::ffi::c_int;
75+
let mut i: ::core::ffi::c_int = C2Rust_Unnamed::B.0 as ::core::ffi::c_int;
7276
}
7377
#[unsafe(no_mangle)]
7478
pub unsafe extern "C" fn statement_expr() {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ expression: cat tests/snapshots/macrocase.2021.rs
1313
#[derive(Clone, Copy)]
1414
#[repr(transparent)]
1515
pub struct ZSTD_dParameter(pub ::core::ffi::c_uint);
16-
pub const ZSTD_d_experimentalParam1: ZSTD_dParameter = ZSTD_dParameter(1000);
17-
pub const ZSTD_d_windowLogMax: ZSTD_dParameter = ZSTD_dParameter(100);
16+
impl ZSTD_dParameter {
17+
pub const ZSTD_d_windowLogMax: Self = Self(100);
18+
pub const ZSTD_d_experimentalParam1: Self = Self(1000);
19+
}
1820
pub const ZSTD_d_format: ::core::ffi::c_uint = 1000 as ::core::ffi::c_uint;
1921
#[no_mangle]
2022
pub unsafe extern "C" fn ZSTD_dParam_getBounds(mut dParam: ZSTD_dParameter) -> ::core::ffi::c_int {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ expression: cat tests/snapshots/macrocase.2024.rs
1414
#[derive(Clone, Copy)]
1515
#[repr(transparent)]
1616
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);
17+
impl ZSTD_dParameter {
18+
pub const ZSTD_d_windowLogMax: Self = Self(100);
19+
pub const ZSTD_d_experimentalParam1: Self = Self(1000);
20+
}
1921
pub const ZSTD_d_format: ::core::ffi::c_uint = 1000 as ::core::ffi::c_uint;
2022
#[unsafe(no_mangle)]
2123
pub unsafe extern "C" fn ZSTD_dParam_getBounds(mut dParam: ZSTD_dParameter) -> ::core::ffi::c_int {

0 commit comments

Comments
 (0)