@@ -23,10 +23,18 @@ impl<'c> Translation<'c> {
2323 . borrow ( )
2424 . resolve_decl_name ( enum_id)
2525 . expect ( "Enums should already be renamed" ) ;
26- let ty = self . convert_type ( integral_type. ctype ) ?;
27- Ok ( ConvertedDecl :: Item (
28- mk ( ) . span ( span) . pub_ ( ) . type_item ( enum_name, ty) ,
29- ) )
26+
27+ let field = mk ( )
28+ . pub_ ( )
29+ . enum_field ( self . convert_type ( integral_type. ctype ) ?) ;
30+ let item = mk ( )
31+ . span ( span)
32+ . call_attr ( "derive" , vec ! [ "Clone" , "Copy" ] )
33+ . call_attr ( "repr" , vec ! [ "transparent" ] )
34+ . pub_ ( )
35+ . struct_item ( enum_name, vec ! [ field] , true ) ;
36+
37+ Ok ( ConvertedDecl :: Item ( item) )
3038 }
3139
3240 pub fn convert_enum_constant (
@@ -46,47 +54,51 @@ impl<'c> Translation<'c> {
4654 . borrow ( )
4755 . resolve_decl_name ( enum_id)
4856 . expect ( "Enums should already be renamed" ) ;
49- self . add_import ( enum_id, & enum_name) ;
5057
5158 let ty = mk ( ) . ident_ty ( enum_name) ;
5259 let val = match value {
5360 ConstIntExpr :: I ( value) => signed_int_expr ( value) ,
5461 ConstIntExpr :: U ( value) => mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( value as u128 ) ) ,
5562 } ;
63+ let init = self . enum_constructor_expr ( enum_id, val) ;
5664
5765 Ok ( ConvertedDecl :: Item (
58- mk ( ) . span ( span) . pub_ ( ) . const_item ( name, ty, val ) ,
66+ mk ( ) . span ( span) . pub_ ( ) . const_item ( name, ty, init ) ,
5967 ) )
6068 }
6169
62- pub fn convert_enum_zero_initializer ( & self , type_id : CTypeId ) -> WithStmts < Box < Expr > > {
63- WithStmts :: new_val ( self . enum_for_i64 ( type_id , 0 ) )
70+ pub fn convert_enum_zero_initializer ( & self , enum_id : CEnumId ) -> WithStmts < Box < Expr > > {
71+ WithStmts :: new_val ( self . enum_for_i64 ( enum_id , 0 ) )
6472 }
6573
6674 /// Translate a cast where the source type, but not the target type, is an `enum` type.
6775 pub fn convert_cast_from_enum (
6876 & self ,
6977 target_cty : CTypeId ,
70- val : Box < Expr > ,
78+ mut val : Box < Expr > ,
7179 ) -> TranslationResult < Box < Expr > > {
7280 // Convert it to the expected integral type.
81+ val = self . integer_from_enum ( val) ;
82+
7383 let ty = self . convert_type ( target_cty) ?;
74- Ok ( mk ( ) . cast_expr ( val, ty) )
84+ val = mk ( ) . cast_expr ( val, ty) ;
85+
86+ Ok ( val)
87+ }
88+
89+ /// Gets the inner integral value of an enum value.
90+ pub fn integer_from_enum ( & self , val : Box < Expr > ) -> Box < Expr > {
91+ mk ( ) . anon_field_expr ( val, 0 )
7592 }
7693
77- /// Translate a cast where the target type is an `enum` type.
78- ///
79- /// When translating variable references to `EnumConstant`s, we always insert casts to the
80- /// expected type. In C, `EnumConstant`s have some integral type, _not_ the enum type. However,
81- /// if we then immediately have a cast to convert this variable back into an enum type, we would
82- /// like to produce Rust with _no_ casts. This function handles this simplification.
94+ /// Translates a cast where the target type is an `enum` type.
8395 pub fn convert_cast_to_enum (
8496 & self ,
8597 ctx : ExprContext ,
86- enum_type_id : CTypeId ,
8798 enum_id : CEnumId ,
8899 expr : Option < CExprId > ,
89- val : Box < Expr > ,
100+ source_cty : CQualTypeId ,
101+ mut val : Box < Expr > ,
90102 ) -> TranslationResult < Box < Expr > > {
91103 if let Some ( expr) = expr {
92104 match self . ast_context [ expr] . kind {
@@ -109,53 +121,57 @@ impl<'c> Translation<'c> {
109121 }
110122
111123 CExprKind :: Literal ( _, CLiteral :: Integer ( i, _) ) => {
112- return Ok ( self . enum_for_i64 ( enum_type_id , i as i64 ) ) ;
124+ return Ok ( self . enum_for_i64 ( enum_id , i as i64 ) ) ;
113125 }
114126
115127 CExprKind :: Unary ( _, c_ast:: UnOp :: Negate , subexpr_id, _) => {
116128 if let & CExprKind :: Literal ( _, CLiteral :: Integer ( i, _) ) =
117129 & self . ast_context [ subexpr_id] . kind
118130 {
119- return Ok ( self . enum_for_i64 ( enum_type_id , -( i as i64 ) ) ) ;
131+ return Ok ( self . enum_for_i64 ( enum_id , -( i as i64 ) ) ) ;
120132 }
121133 }
122134
123135 _ => { }
124136 }
125137 }
126138
127- let target_ty = self . convert_type ( enum_type_id) ?;
128- Ok ( mk ( ) . cast_expr ( val, target_ty) )
139+ let integral_type = self . enum_integral_type ( enum_id) ;
140+ let mut needs_cast = true ;
141+
142+ // C allows directly casting from enum to enum, but in Rust we need to use
143+ // the inner integer value as an intermediate.
144+ if let CTypeKind :: Enum ( source_enum_id) =
145+ self . ast_context . resolve_type ( source_cty. ctype ) . kind
146+ {
147+ val = self . integer_from_enum ( val) ;
148+ needs_cast = integral_type. ctype != self . enum_integral_type ( source_enum_id) . ctype ;
149+ }
150+
151+ if needs_cast {
152+ let ty = self . convert_type ( integral_type. ctype ) ?;
153+ val = mk ( ) . cast_expr ( val, ty) ;
154+ val = self . enum_constructor_expr ( enum_id, val) ;
155+ }
156+
157+ Ok ( val)
129158 }
130159
131160 /// Given an integer value this attempts to either generate the corresponding enum
132161 /// variant directly, otherwise it converts a number to the enum type.
133- fn enum_for_i64 ( & self , enum_type_id : CTypeId , value : i64 ) -> Box < Expr > {
134- let enum_id = match self . ast_context . resolve_type ( enum_type_id) . kind {
135- CTypeKind :: Enum ( enum_id) => enum_id,
136- _ => panic ! ( "{:?} does not point to an `enum` type" , enum_type_id) ,
137- } ;
138-
162+ fn enum_for_i64 ( & self , enum_id : CEnumId , value : i64 ) -> Box < Expr > {
139163 if let Some ( enum_constant_id) = self . enum_variant_for_i64 ( enum_id, value) {
140164 return self . enum_constant_expr ( enum_constant_id) ;
141165 }
142166
143- let underlying_type_id = match self . ast_context [ enum_id] . kind {
144- CDeclKind :: Enum {
145- integral_type : Some ( integral_type) ,
146- ..
147- } => integral_type,
148- _ => panic ! ( "{:?} does not point to an `enum` declaration" , enum_id) ,
149- } ;
150-
167+ let underlying_type_id = self . enum_integral_type ( enum_id) ;
151168 let value = match self . ast_context . resolve_type ( underlying_type_id. ctype ) . kind {
152169 CTypeKind :: UInt => mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( ( value as u32 ) as u128 ) ) ,
153170 CTypeKind :: ULong => mk ( ) . lit_expr ( mk ( ) . int_unsuffixed_lit ( ( value as u64 ) as u128 ) ) ,
154171 _ => signed_int_expr ( value) ,
155172 } ;
156173
157- let target_ty = self . convert_type ( enum_type_id) . unwrap ( ) ;
158- mk ( ) . cast_expr ( value, target_ty)
174+ self . enum_constructor_expr ( enum_id, value)
159175 }
160176
161177 /// Returns the id of the variant of `enum_id` whose value matches `value`, if any.
@@ -185,9 +201,29 @@ impl<'c> Translation<'c> {
185201 variants. contains ( & enum_constant_id)
186202 }
187203
204+ fn enum_constructor_expr ( & self , enum_id : CEnumId , value : Box < Expr > ) -> Box < Expr > {
205+ let enum_name = self
206+ . type_converter
207+ . borrow ( )
208+ . resolve_decl_name ( enum_id)
209+ . unwrap ( ) ;
210+ self . add_import ( enum_id, & enum_name) ;
211+ mk ( ) . call_expr ( mk ( ) . ident_expr ( enum_name) , vec ! [ value] )
212+ }
213+
188214 fn enum_constant_expr ( & self , enum_constant_id : CEnumConstantId ) -> Box < Expr > {
189215 let name = self . renamer . borrow ( ) . get ( & enum_constant_id) . unwrap ( ) ;
190216 self . add_import ( enum_constant_id, & name) ;
191217 mk ( ) . ident_expr ( name)
192218 }
219+
220+ fn enum_integral_type ( & self , enum_id : CEnumId ) -> CQualTypeId {
221+ match self . ast_context [ enum_id] . kind {
222+ CDeclKind :: Enum {
223+ integral_type : Some ( integral_type) ,
224+ ..
225+ } => integral_type,
226+ _ => panic ! ( "{:?} does not point to an `enum` declaration" , enum_id) ,
227+ }
228+ }
193229}
0 commit comments