@@ -4,6 +4,7 @@ use syn::Expr;
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,68 +18,121 @@ 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" ) ;
26-
27- let item = match self . tcfg . enum_mode {
28+ let integral_type_rs = self . convert_type ( integral_type . ctype ) ? ;
29+ let enum_item = match self . tcfg . enum_mode {
2830 EnumMode :: NewType => {
29- let field = mk ( )
30- . pub_ ( )
31- . enum_field ( self . convert_type ( integral_type. ctype ) ?) ;
31+ let field = mk ( ) . pub_ ( ) . enum_field ( integral_type_rs) ;
3232 mk ( ) . span ( span)
3333 . call_attr ( "derive" , vec ! [ "Clone" , "Copy" ] )
3434 . call_attr ( "repr" , vec ! [ "transparent" ] )
3535 . pub_ ( )
3636 . struct_item ( enum_name, vec ! [ field] , true )
3737 }
3838
39- EnumMode :: Consts => {
40- let ty = self . convert_type ( integral_type . ctype ) ? ;
41- mk ( ) . span ( span ) . pub_ ( ) . type_item ( enum_name , ty )
42- }
39+ EnumMode :: Consts => mk ( )
40+ . span ( span )
41+ . pub_ ( )
42+ . type_item ( enum_name , integral_type_rs ) ,
4343 } ;
4444
45- Ok ( ConvertedDecl :: Item ( item) )
46- }
45+ if variants. is_empty ( ) {
46+ return Ok ( ConvertedDecl :: Item ( enum_item) ) ;
47+ }
4748
48- pub fn convert_enum_constant (
49- & self ,
50- enum_constant_id : CEnumConstantId ,
51- span : Span ,
52- value : ConstIntExpr ,
53- ) -> 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" ) ;
49+ match self . tcfg . enum_mode {
50+ EnumMode :: NewType => {
51+ let enum_type = mk ( ) . ident_ty ( "Self" ) ;
52+ let constants = variants
53+ . iter ( )
54+ . map ( |& enum_constant_id| {
55+ let name = match self . ast_context [ enum_constant_id] . kind {
56+ CDeclKind :: EnumConstant { ref name, .. } => self
57+ . type_converter
58+ . borrow_mut ( )
59+ . declare_field_name ( enum_id, enum_constant_id, name) ,
60+ _ => panic ! ( "{:?} does not point to an enum variant" , enum_constant_id) ,
61+ } ;
62+ let ( span, init) = self . make_enum_constant_init ( enum_constant_id) ;
63+ mk ( ) . span ( span)
64+ . pub_ ( )
65+ . const_impl_item ( name, enum_type. clone ( ) , init)
66+ } )
67+ . collect ( ) ;
68+
69+ let impl_block = mk ( ) . impl_item ( mk ( ) . ident_ty ( enum_name) , constants) ;
70+ Ok ( ConvertedDecl :: Items ( vec ! [ enum_item, impl_block] ) )
71+ }
6572
66- let ty = mk ( ) . ident_ty ( enum_name) ;
73+ EnumMode :: Consts => {
74+ let enum_type = mk ( ) . ident_ty ( enum_name) ;
75+ let constants_iter = variants. iter ( ) . map ( |& enum_constant_id| {
76+ let name = self
77+ . renamer
78+ . borrow_mut ( )
79+ . get ( & enum_constant_id)
80+ . expect ( "Enum constant not named" ) ;
81+ let ( span, init) = self . make_enum_constant_init ( enum_constant_id) ;
82+ mk ( ) . span ( span)
83+ . pub_ ( )
84+ . const_item ( name, enum_type. clone ( ) , init)
85+ } ) ;
86+
87+ let items = std:: iter:: once ( enum_item) . chain ( constants_iter) . collect ( ) ;
88+ Ok ( ConvertedDecl :: Items ( items) )
89+ }
90+ }
91+ }
92+
93+ fn make_enum_constant_init ( & self , enum_constant_id : CEnumConstantId ) -> ( Span , Box < Expr > ) {
94+ let value = match self . ast_context [ enum_constant_id] . kind {
95+ CDeclKind :: EnumConstant { value, .. } => value,
96+ _ => panic ! ( "{:?} does not point to an enum variant" , enum_constant_id) ,
97+ } ;
6798 let val = match value {
6899 ConstIntExpr :: I ( value) => signed_int_expr ( value) ,
69100 ConstIntExpr :: U ( value) => mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( value as u128 ) ) ,
70101 } ;
71- let init = self . enum_constructor_expr ( enum_id, val) ;
102+ let enum_id = self . ast_context . parents [ & enum_constant_id] ;
103+ let init = self . enum_constructor_expr ( enum_id, val, true ) ;
104+ let span = self
105+ . get_span ( SomeId :: Decl ( enum_constant_id) )
106+ . unwrap_or_else ( Span :: call_site) ;
72107
73- Ok ( ConvertedDecl :: Item (
74- mk ( ) . span ( span) . pub_ ( ) . const_item ( name, ty, init) ,
75- ) )
108+ ( span, init)
76109 }
77110
78111 pub fn convert_enum_zero_initializer ( & self , enum_id : CEnumId ) -> WithStmts < Box < Expr > > {
79112 WithStmts :: new_val ( self . enum_for_i64 ( enum_id, 0 ) )
80113 }
81114
115+ /// Translates a `DeclRef` for an `EnumConstant`.
116+ pub fn convert_enum_constant_decl_ref (
117+ & self ,
118+ ctx : ExprContext ,
119+ enum_constant_id : CEnumConstantId ,
120+ target_cty : CQualTypeId ,
121+ ) -> TranslationResult < WithStmts < Box < Expr > > > {
122+ let enum_id = self . ast_context . parents [ & enum_constant_id] ;
123+ let val = self . enum_constant_expr ( enum_id, enum_constant_id) ;
124+
125+ // If our target type is this enum type, don't bother with a cast.
126+ if matches ! (
127+ self . ast_context. resolve_type( target_cty. ctype) . kind,
128+ CTypeKind :: Enum ( target_enum_id) if target_enum_id == enum_id
129+ ) {
130+ Ok ( WithStmts :: new_val ( val) )
131+ } else {
132+ self . convert_cast_from_enum ( ctx, enum_id, target_cty, val)
133+ }
134+ }
135+
82136 /// Translate a cast where the source type, but not the target type, is an `enum` type.
83137 pub fn convert_cast_from_enum (
84138 & self ,
@@ -145,7 +199,7 @@ impl<'c> Translation<'c> {
145199 // If this DeclRef expanded to a const macro, we actually need to insert a cast,
146200 // because the translation of a const macro skips implicit casts in its context.
147201 if !expr_is_macro {
148- val = self . enum_constant_expr ( enum_constant_id) ;
202+ val = self . enum_constant_expr ( enum_id , enum_constant_id) ;
149203 return Ok ( WithStmts :: new_val ( val) ) ;
150204 }
151205 }
@@ -202,14 +256,14 @@ impl<'c> Translation<'c> {
202256 }
203257
204258 // Construct a new enum value.
205- Ok ( val. map ( |val| self . enum_constructor_expr ( enum_id, val) ) )
259+ Ok ( val. map ( |val| self . enum_constructor_expr ( enum_id, val, false ) ) )
206260 }
207261
208262 /// Given an integer value this attempts to either generate the corresponding enum
209263 /// variant directly, otherwise it converts a number to the enum type.
210264 fn enum_for_i64 ( & self , enum_id : CEnumId , value : i64 ) -> Box < Expr > {
211265 if let Some ( enum_constant_id) = self . enum_variant_for_i64 ( enum_id, value) {
212- return self . enum_constant_expr ( enum_constant_id) ;
266+ return self . enum_constant_expr ( enum_id , enum_constant_id) ;
213267 }
214268
215269 let underlying_type_id = self . enum_integral_type ( enum_id) ;
@@ -219,7 +273,7 @@ impl<'c> Translation<'c> {
219273 _ => signed_int_expr ( value) ,
220274 } ;
221275
222- self . enum_constructor_expr ( enum_id, value)
276+ self . enum_constructor_expr ( enum_id, value, false )
223277 }
224278
225279 /// Returns the id of the variant of `enum_id` whose value matches `value`, if any.
@@ -240,24 +294,65 @@ impl<'c> Translation<'c> {
240294 } )
241295 }
242296
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-
297+ fn enum_constructor_expr (
298+ & self ,
299+ enum_id : CEnumId ,
300+ value : Box < Expr > ,
301+ use_self_ty : bool ,
302+ ) -> Box < Expr > {
251303 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) ) ,
304+ EnumMode :: NewType => {
305+ let func = if use_self_ty {
306+ mk ( ) . ident_expr ( "Self" )
307+ } else {
308+ let enum_name = self
309+ . type_converter
310+ . borrow ( )
311+ . resolve_decl_name ( enum_id)
312+ . unwrap ( ) ;
313+ self . add_import ( enum_id, & enum_name) ;
314+ mk ( ) . ident_expr ( enum_name)
315+ } ;
316+
317+ mk ( ) . call_expr ( func, vec ! [ value] )
318+ }
319+ EnumMode :: Consts => {
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+
327+ mk ( ) . cast_expr ( value, mk ( ) . ident_ty ( enum_name) )
328+ }
254329 }
255330 }
256331
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)
332+ fn enum_constant_expr ( & self , enum_id : CEnumId , enum_constant_id : CEnumConstantId ) -> Box < Expr > {
333+ match self . tcfg . enum_mode {
334+ EnumMode :: NewType => {
335+ let enum_name = self
336+ . type_converter
337+ . borrow ( )
338+ . resolve_decl_name ( enum_id)
339+ . unwrap ( ) ;
340+ let name = self
341+ . type_converter
342+ . borrow ( )
343+ . resolve_field_name ( Some ( enum_id) , enum_constant_id)
344+ . unwrap ( ) ;
345+
346+ self . add_import ( enum_id, & enum_name) ;
347+ mk ( ) . path_expr ( vec ! [ enum_name, name] )
348+ }
349+
350+ EnumMode :: Consts => {
351+ let name = self . renamer . borrow ( ) . get ( & enum_constant_id) . unwrap ( ) ;
352+ self . add_import ( enum_constant_id, & name) ;
353+ mk ( ) . ident_expr ( name)
354+ }
355+ }
261356 }
262357
263358 fn is_variant_of_enum ( & self , enum_id : CEnumId , enum_constant_id : CEnumConstantId ) -> bool {
0 commit comments