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 , 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 {
0 commit comments