11use c2rust_ast_builder:: mk;
22use proc_macro2:: Span ;
3- use syn:: Expr ;
3+ use syn:: { Expr , ImplItem } ;
44
55use crate :: c_ast:: CUnOp ;
66use crate :: {
7+ c_ast:: iterators:: SomeId ,
78 diagnostics:: TranslationResult ,
89 translator:: { signed_int_expr, ConvertedDecl , EnumMode , ExprContext , Translation } ,
910 with_stmts:: WithStmts ,
@@ -17,32 +18,67 @@ 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
2325 . borrow ( )
2426 . resolve_decl_name ( enum_id)
2527 . expect ( "Enums should already be renamed" ) ;
2628
27- let item = match self . tcfg . enum_mode {
29+ match self . tcfg . enum_mode {
2830 EnumMode :: NewType => {
2931 let field = mk ( )
3032 . pub_ ( )
3133 . enum_field ( self . convert_type ( integral_type. ctype ) ?) ;
32- mk ( ) . span ( span)
34+ let item = mk ( )
35+ . span ( span)
3336 . call_attr ( "derive" , vec ! [ "Clone" , "Copy" ] )
3437 . call_attr ( "repr" , vec ! [ "transparent" ] )
3538 . pub_ ( )
36- . struct_item ( enum_name, vec ! [ field] , true )
39+ . struct_item ( enum_name, vec ! [ field] , true ) ;
40+
41+ if variants. is_empty ( ) {
42+ return Ok ( ConvertedDecl :: Item ( item) ) ;
43+ }
44+
45+ let self_ty = mk ( ) . ident_ty ( "Self" ) ;
46+ let constants: Vec < ImplItem > = variants
47+ . iter ( )
48+ . map ( |& enum_constant_id| {
49+ let span = self
50+ . get_span ( SomeId :: Decl ( enum_constant_id) )
51+ . unwrap_or_else ( Span :: call_site) ;
52+
53+ let ( name, value) = match self . ast_context [ enum_constant_id] . kind {
54+ CDeclKind :: EnumConstant {
55+ ref name, value, ..
56+ } => ( name, value) ,
57+ _ => panic ! ( "{:?} does not point to an enum variant" , enum_constant_id) ,
58+ } ;
59+ let name = self . type_converter . borrow_mut ( ) . declare_field_name (
60+ enum_id,
61+ enum_constant_id,
62+ name,
63+ ) ;
64+ let init = self . make_enum_constant_init ( enum_id, value) ;
65+
66+ mk ( ) . span ( span)
67+ . pub_ ( )
68+ . const_impl_item ( name, self_ty. clone ( ) , init)
69+ } )
70+ . collect ( ) ;
71+ let impl_block = mk ( ) . impl_item ( mk ( ) . ident_ty ( enum_name) , constants) ;
72+
73+ Ok ( ConvertedDecl :: Items ( vec ! [ item, impl_block] ) )
3774 }
3875
3976 EnumMode :: Consts => {
4077 let ty = self . convert_type ( integral_type. ctype ) ?;
41- mk ( ) . span ( span) . pub_ ( ) . type_item ( enum_name, ty)
78+ let item = mk ( ) . span ( span) . pub_ ( ) . type_item ( enum_name, ty) ;
79+ Ok ( ConvertedDecl :: Item ( item) )
4280 }
43- } ;
44-
45- Ok ( ConvertedDecl :: Item ( item) )
81+ }
4682 }
4783
4884 pub fn convert_enum_constant (
@@ -51,34 +87,64 @@ impl<'c> Translation<'c> {
5187 span : Span ,
5288 value : ConstIntExpr ,
5389 ) -> TranslationResult < ConvertedDecl > {
54- let name = self
55- . renamer
56- . borrow_mut ( )
57- . get ( & enum_constant_id)
58- . expect ( "Enum constant not named" ) ;
59- let enum_id = self . ast_context . parents [ & enum_constant_id] ;
60- let enum_name = self
61- . type_converter
62- . borrow ( )
63- . resolve_decl_name ( enum_id)
64- . expect ( "Enums should already be renamed" ) ;
90+ match self . tcfg . enum_mode {
91+ EnumMode :: NewType => Ok ( ConvertedDecl :: NoItem ) ,
92+
93+ EnumMode :: Consts => {
94+ let name = self
95+ . renamer
96+ . borrow_mut ( )
97+ . get ( & enum_constant_id)
98+ . expect ( "Enum constant not named" ) ;
99+ let enum_id = self . ast_context . parents [ & enum_constant_id] ;
100+ let enum_name = self
101+ . type_converter
102+ . borrow ( )
103+ . resolve_decl_name ( enum_id)
104+ . expect ( "Enums should already be renamed" ) ;
105+ let ty = mk ( ) . ident_ty ( enum_name) ;
106+ let init = self . make_enum_constant_init ( enum_id, value) ;
107+
108+ Ok ( ConvertedDecl :: Item (
109+ mk ( ) . span ( span) . pub_ ( ) . const_item ( name, ty, init) ,
110+ ) )
111+ }
112+ }
113+ }
65114
66- let ty = mk ( ) . ident_ty ( enum_name ) ;
115+ fn make_enum_constant_init ( & self , enum_id : CEnumId , value : ConstIntExpr ) -> Box < Expr > {
67116 let val = match value {
68117 ConstIntExpr :: I ( value) => signed_int_expr ( value) ,
69118 ConstIntExpr :: U ( value) => mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( value as u128 ) ) ,
70119 } ;
71- let init = self . enum_constructor_expr ( enum_id, val) ;
72-
73- Ok ( ConvertedDecl :: Item (
74- mk ( ) . span ( span) . pub_ ( ) . const_item ( name, ty, init) ,
75- ) )
120+ self . enum_constructor_expr ( enum_id, val, true )
76121 }
77122
78123 pub fn convert_enum_zero_initializer ( & self , enum_id : CEnumId ) -> WithStmts < Box < Expr > > {
79124 WithStmts :: new_val ( self . enum_for_i64 ( enum_id, 0 ) )
80125 }
81126
127+ /// Translates a `DeclRef` for an `EnumConstant`.
128+ pub fn convert_enum_constant_decl_ref (
129+ & self ,
130+ ctx : ExprContext ,
131+ enum_constant_id : CEnumConstantId ,
132+ target_cty : CQualTypeId ,
133+ ) -> TranslationResult < WithStmts < Box < Expr > > > {
134+ let enum_id = self . ast_context . parents [ & enum_constant_id] ;
135+ let val = self . enum_constant_expr ( enum_id, enum_constant_id) ;
136+
137+ // If our target type is this enum type, don't bother with a cast.
138+ if matches ! (
139+ self . ast_context. resolve_type( target_cty. ctype) . kind,
140+ CTypeKind :: Enum ( target_enum_id) if target_enum_id == enum_id
141+ ) {
142+ Ok ( WithStmts :: new_val ( val) )
143+ } else {
144+ self . convert_cast_from_enum ( ctx, enum_id, target_cty, val)
145+ }
146+ }
147+
82148 /// Translate a cast where the source type, but not the target type, is an `enum` type.
83149 pub fn convert_cast_from_enum (
84150 & self ,
@@ -145,7 +211,7 @@ impl<'c> Translation<'c> {
145211 // If this DeclRef expanded to a const macro, we actually need to insert a cast,
146212 // because the translation of a const macro skips implicit casts in its context.
147213 if !expr_is_macro {
148- val = self . enum_constant_expr ( enum_constant_id) ;
214+ val = self . enum_constant_expr ( enum_id , enum_constant_id) ;
149215 return Ok ( WithStmts :: new_val ( val) ) ;
150216 }
151217 }
@@ -202,14 +268,14 @@ impl<'c> Translation<'c> {
202268 }
203269
204270 // Construct a new enum value.
205- Ok ( val. map ( |val| self . enum_constructor_expr ( enum_id, val) ) )
271+ Ok ( val. map ( |val| self . enum_constructor_expr ( enum_id, val, false ) ) )
206272 }
207273
208274 /// Given an integer value this attempts to either generate the corresponding enum
209275 /// variant directly, otherwise it converts a number to the enum type.
210276 fn enum_for_i64 ( & self , enum_id : CEnumId , value : i64 ) -> Box < Expr > {
211277 if let Some ( enum_constant_id) = self . enum_variant_for_i64 ( enum_id, value) {
212- return self . enum_constant_expr ( enum_constant_id) ;
278+ return self . enum_constant_expr ( enum_id , enum_constant_id) ;
213279 }
214280
215281 let underlying_type_id = self . enum_integral_type ( enum_id) ;
@@ -219,7 +285,7 @@ impl<'c> Translation<'c> {
219285 _ => signed_int_expr ( value) ,
220286 } ;
221287
222- self . enum_constructor_expr ( enum_id, value)
288+ self . enum_constructor_expr ( enum_id, value, false )
223289 }
224290
225291 /// Returns the id of the variant of `enum_id` whose value matches `value`, if any.
@@ -240,24 +306,65 @@ impl<'c> Translation<'c> {
240306 } )
241307 }
242308
243- fn enum_constructor_expr ( & self , enum_id : CEnumId , value : Box < Expr > ) -> Box < Expr > {
244- let enum_name = self
245- . type_converter
246- . borrow ( )
247- . resolve_decl_name ( enum_id)
248- . unwrap ( ) ;
249- self . add_import ( enum_id, & enum_name) ;
250-
309+ fn enum_constructor_expr (
310+ & self ,
311+ enum_id : CEnumId ,
312+ value : Box < Expr > ,
313+ use_self_ty : bool ,
314+ ) -> Box < Expr > {
251315 match self . tcfg . enum_mode {
252- EnumMode :: NewType => mk ( ) . call_expr ( mk ( ) . ident_expr ( enum_name) , vec ! [ value] ) ,
253- EnumMode :: Consts => mk ( ) . cast_expr ( value, mk ( ) . ident_ty ( enum_name) ) ,
316+ EnumMode :: NewType => {
317+ let func = if use_self_ty {
318+ mk ( ) . ident_expr ( "Self" )
319+ } else {
320+ let enum_name = self
321+ . type_converter
322+ . borrow ( )
323+ . resolve_decl_name ( enum_id)
324+ . unwrap ( ) ;
325+ self . add_import ( enum_id, & enum_name) ;
326+ mk ( ) . ident_expr ( enum_name)
327+ } ;
328+
329+ mk ( ) . call_expr ( func, vec ! [ value] )
330+ }
331+ EnumMode :: Consts => {
332+ let enum_name = self
333+ . type_converter
334+ . borrow ( )
335+ . resolve_decl_name ( enum_id)
336+ . unwrap ( ) ;
337+ self . add_import ( enum_id, & enum_name) ;
338+
339+ mk ( ) . cast_expr ( value, mk ( ) . ident_ty ( enum_name) )
340+ }
254341 }
255342 }
256343
257- fn enum_constant_expr ( & self , enum_constant_id : CEnumConstantId ) -> Box < Expr > {
258- let name = self . renamer . borrow ( ) . get ( & enum_constant_id) . unwrap ( ) ;
259- self . add_import ( enum_constant_id, & name) ;
260- mk ( ) . ident_expr ( name)
344+ fn enum_constant_expr ( & self , enum_id : CEnumId , enum_constant_id : CEnumConstantId ) -> Box < Expr > {
345+ match self . tcfg . enum_mode {
346+ EnumMode :: NewType => {
347+ let enum_name = self
348+ . type_converter
349+ . borrow ( )
350+ . resolve_decl_name ( enum_id)
351+ . unwrap ( ) ;
352+ let name = self
353+ . type_converter
354+ . borrow ( )
355+ . resolve_field_name ( Some ( enum_id) , enum_constant_id)
356+ . unwrap ( ) ;
357+
358+ self . add_import ( enum_id, & enum_name) ;
359+ mk ( ) . path_expr ( vec ! [ enum_name, name] )
360+ }
361+
362+ EnumMode :: Consts => {
363+ let name = self . renamer . borrow ( ) . get ( & enum_constant_id) . unwrap ( ) ;
364+ self . add_import ( enum_constant_id, & name) ;
365+ mk ( ) . ident_expr ( name)
366+ }
367+ }
261368 }
262369
263370 fn is_variant_of_enum ( & self , enum_id : CEnumId , enum_constant_id : CEnumConstantId ) -> bool {
0 commit comments