11use c2rust_ast_builder:: mk;
22use proc_macro2:: Span ;
3- use syn:: Expr ;
3+ use syn:: { Expr , ImplItem } ;
44
55use crate :: {
6- c_ast,
6+ c_ast:: { self , iterators :: SomeId } ,
77 diagnostics:: TranslationResult ,
88 translator:: { signed_int_expr, ConvertedDecl , ExprContext , Translation } ,
99 with_stmts:: WithStmts ,
@@ -17,6 +17,7 @@ impl<'c> Translation<'c> {
1717 enum_id : CEnumId ,
1818 span : Span ,
1919 integral_type : CQualTypeId ,
20+ variants : & [ CEnumConstantId ] ,
2021 ) -> TranslationResult < ConvertedDecl > {
2122 let enum_name = & self
2223 . type_converter
@@ -34,43 +35,61 @@ impl<'c> Translation<'c> {
3435 . pub_ ( )
3536 . struct_item ( enum_name, vec ! [ field] , true ) ;
3637
37- Ok ( ConvertedDecl :: Item ( item) )
38- }
38+ if variants. is_empty ( ) {
39+ return Ok ( ConvertedDecl :: Item ( item) ) ;
40+ }
3941
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" ) ;
42+ let self_ty = mk ( ) . ident_ty ( "Self" ) ;
43+ let constants: Vec < ImplItem > = variants
44+ . iter ( )
45+ . map ( |& enum_constant_id| {
46+ let span = self
47+ . get_span ( SomeId :: Decl ( enum_constant_id) )
48+ . unwrap_or_else ( Span :: call_site) ;
5749
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) ;
50+ let ( name, value) = match self . ast_context [ enum_constant_id] . kind {
51+ CDeclKind :: EnumConstant {
52+ ref name, value, ..
53+ } => ( name, value) ,
54+ _ => panic ! ( "{:?} does not point to an enum variant" , enum_constant_id) ,
55+ } ;
56+ let name = self . type_converter . borrow_mut ( ) . declare_field_name (
57+ enum_id,
58+ enum_constant_id,
59+ name,
60+ ) ;
6461
65- Ok ( ConvertedDecl :: Item (
66- mk ( ) . span ( span) . pub_ ( ) . const_item ( name, ty, init) ,
67- ) )
62+ let val = match value {
63+ ConstIntExpr :: I ( value) => signed_int_expr ( value) ,
64+ ConstIntExpr :: U ( value) => mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( value as u128 ) ) ,
65+ } ;
66+ let init = self . enum_constructor_expr ( enum_id, val, true ) ;
67+
68+ mk ( ) . span ( span)
69+ . pub_ ( )
70+ . const_impl_item ( name, self_ty. clone ( ) , init)
71+ } )
72+ . collect ( ) ;
73+ let impl_block = mk ( ) . impl_item ( mk ( ) . ident_ty ( enum_name) , constants) ;
74+
75+ Ok ( ConvertedDecl :: Items ( vec ! [ item, impl_block] ) )
6876 }
6977
7078 pub fn convert_enum_zero_initializer ( & self , enum_id : CEnumId ) -> WithStmts < Box < Expr > > {
7179 WithStmts :: new_val ( self . enum_for_i64 ( enum_id, 0 ) )
7280 }
7381
82+ /// Translates a `DeclRef` for an `EnumConstant`.
83+ pub fn convert_enum_constant_decl_ref (
84+ & self ,
85+ enum_constant_id : CEnumConstantId ,
86+ target_cty : CTypeId ,
87+ ) -> TranslationResult < Box < Expr > > {
88+ let enum_id = self . ast_context . parents [ & enum_constant_id] ;
89+ let val = self . enum_constant_expr ( enum_id, enum_constant_id) ;
90+ self . convert_cast_from_enum ( target_cty, val)
91+ }
92+
7493 /// Translate a cast where the source type, but not the target type, is an `enum` type.
7594 pub fn convert_cast_from_enum (
7695 & self ,
@@ -117,7 +136,7 @@ impl<'c> Translation<'c> {
117136 // If this DeclRef expanded to a const macro, we actually need to insert a cast,
118137 // because the translation of a const macro skips implicit casts in its context.
119138 if !expr_is_macro {
120- return Ok ( self . enum_constant_expr ( enum_constant_id) ) ;
139+ return Ok ( self . enum_constant_expr ( enum_id , enum_constant_id) ) ;
121140 }
122141 }
123142
@@ -152,14 +171,14 @@ impl<'c> Translation<'c> {
152171 val = mk ( ) . cast_expr ( val, ty) ;
153172 }
154173
155- Ok ( self . enum_constructor_expr ( enum_id, val) )
174+ Ok ( self . enum_constructor_expr ( enum_id, val, false ) )
156175 }
157176
158177 /// Given an integer value this attempts to either generate the corresponding enum
159178 /// variant directly, otherwise it converts a number to the enum type.
160179 fn enum_for_i64 ( & self , enum_id : CEnumId , value : i64 ) -> Box < Expr > {
161180 if let Some ( enum_constant_id) = self . enum_variant_for_i64 ( enum_id, value) {
162- return self . enum_constant_expr ( enum_constant_id) ;
181+ return self . enum_constant_expr ( enum_id , enum_constant_id) ;
163182 }
164183
165184 let underlying_type_id = self . enum_integral_type ( enum_id) ;
@@ -169,7 +188,7 @@ impl<'c> Translation<'c> {
169188 _ => signed_int_expr ( value) ,
170189 } ;
171190
172- self . enum_constructor_expr ( enum_id, value)
191+ self . enum_constructor_expr ( enum_id, value, false )
173192 }
174193
175194 /// Returns the id of the variant of `enum_id` whose value matches `value`, if any.
@@ -190,20 +209,41 @@ impl<'c> Translation<'c> {
190209 } )
191210 }
192211
193- fn enum_constructor_expr ( & self , enum_id : CEnumId , value : Box < Expr > ) -> Box < Expr > {
212+ fn enum_constructor_expr (
213+ & self ,
214+ enum_id : CEnumId ,
215+ value : Box < Expr > ,
216+ use_self_ty : bool ,
217+ ) -> Box < Expr > {
218+ let func = if use_self_ty {
219+ mk ( ) . ident_expr ( "Self" )
220+ } else {
221+ let enum_name = self
222+ . type_converter
223+ . borrow ( )
224+ . resolve_decl_name ( enum_id)
225+ . unwrap ( ) ;
226+ self . add_import ( enum_id, & enum_name) ;
227+ mk ( ) . ident_expr ( enum_name)
228+ } ;
229+
230+ mk ( ) . call_expr ( func, vec ! [ value] )
231+ }
232+
233+ fn enum_constant_expr ( & self , enum_id : CEnumId , enum_constant_id : CEnumConstantId ) -> Box < Expr > {
194234 let enum_name = self
195235 . type_converter
196236 . borrow ( )
197237 . resolve_decl_name ( enum_id)
198238 . unwrap ( ) ;
199- self . add_import ( enum_id, & enum_name) ;
200- mk ( ) . call_expr ( mk ( ) . ident_expr ( enum_name) , vec ! [ value] )
201- }
239+ let name = self
240+ . type_converter
241+ . borrow ( )
242+ . resolve_field_name ( Some ( enum_id) , enum_constant_id)
243+ . unwrap ( ) ;
202244
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)
245+ self . add_import ( enum_id, & enum_name) ;
246+ mk ( ) . path_expr ( vec ! [ enum_name, name] )
207247 }
208248
209249 fn is_variant_of_enum ( & self , enum_id : CEnumId , enum_constant_id : CEnumConstantId ) -> bool {
0 commit comments