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) ;
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 ,
@@ -116,7 +135,7 @@ impl<'c> Translation<'c> {
116135 // If this DeclRef expanded to a const macro, we actually need to insert a cast,
117136 // because the translation of a const macro skips implicit casts in its context.
118137 if !expr_is_macro {
119- return Ok ( self . enum_constant_expr ( enum_constant_id) ) ;
138+ return Ok ( self . enum_constant_expr ( enum_id , enum_constant_id) ) ;
120139 }
121140 }
122141
@@ -151,7 +170,7 @@ impl<'c> Translation<'c> {
151170 if needs_cast {
152171 let ty = self . convert_type ( integral_type. ctype ) ?;
153172 val = mk ( ) . cast_expr ( val, ty) ;
154- val = self . enum_constructor_expr ( enum_id, val) ;
173+ val = self . enum_constructor_expr ( enum_id, val, false ) ;
155174 }
156175
157176 Ok ( val)
@@ -161,7 +180,7 @@ impl<'c> Translation<'c> {
161180 /// variant directly, otherwise it converts a number to the enum type.
162181 fn enum_for_i64 ( & self , enum_id : CEnumId , value : i64 ) -> Box < Expr > {
163182 if let Some ( enum_constant_id) = self . enum_variant_for_i64 ( enum_id, value) {
164- return self . enum_constant_expr ( enum_constant_id) ;
183+ return self . enum_constant_expr ( enum_id , enum_constant_id) ;
165184 }
166185
167186 let underlying_type_id = self . enum_integral_type ( enum_id) ;
@@ -171,7 +190,7 @@ impl<'c> Translation<'c> {
171190 _ => signed_int_expr ( value) ,
172191 } ;
173192
174- self . enum_constructor_expr ( enum_id, value)
193+ self . enum_constructor_expr ( enum_id, value, false )
175194 }
176195
177196 /// Returns the id of the variant of `enum_id` whose value matches `value`, if any.
@@ -201,20 +220,41 @@ impl<'c> Translation<'c> {
201220 variants. contains ( & enum_constant_id)
202221 }
203222
204- fn enum_constructor_expr ( & self , enum_id : CEnumId , value : Box < Expr > ) -> Box < Expr > {
223+ fn enum_constructor_expr (
224+ & self ,
225+ enum_id : CEnumId ,
226+ value : Box < Expr > ,
227+ use_self_ty : bool ,
228+ ) -> Box < Expr > {
229+ let func = if use_self_ty {
230+ mk ( ) . ident_expr ( "Self" )
231+ } else {
232+ let enum_name = self
233+ . type_converter
234+ . borrow ( )
235+ . resolve_decl_name ( enum_id)
236+ . unwrap ( ) ;
237+ self . add_import ( enum_id, & enum_name) ;
238+ mk ( ) . ident_expr ( enum_name)
239+ } ;
240+
241+ mk ( ) . call_expr ( func, vec ! [ value] )
242+ }
243+
244+ fn enum_constant_expr ( & self , enum_id : CEnumId , enum_constant_id : CEnumConstantId ) -> Box < Expr > {
205245 let enum_name = self
206246 . type_converter
207247 . borrow ( )
208248 . resolve_decl_name ( enum_id)
209249 . unwrap ( ) ;
210- self . add_import ( enum_id, & enum_name) ;
211- mk ( ) . call_expr ( mk ( ) . ident_expr ( enum_name) , vec ! [ value] )
212- }
250+ let name = self
251+ . type_converter
252+ . borrow ( )
253+ . resolve_field_name ( Some ( enum_id) , enum_constant_id)
254+ . unwrap ( ) ;
213255
214- fn enum_constant_expr ( & self , enum_constant_id : CEnumConstantId ) -> Box < Expr > {
215- let name = self . renamer . borrow ( ) . get ( & enum_constant_id) . unwrap ( ) ;
216- self . add_import ( enum_constant_id, & name) ;
217- mk ( ) . ident_expr ( name)
256+ self . add_import ( enum_id, & enum_name) ;
257+ mk ( ) . path_expr ( vec ! [ enum_name, name] )
218258 }
219259
220260 fn enum_integral_type ( & self , enum_id : CEnumId ) -> CQualTypeId {
0 commit comments