@@ -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
51- let ty = mk ( ) . ident_ty ( enum_name) ;
58+ let ty = mk ( ) . ident_ty ( enum_name. clone ( ) ) ;
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)
7587 }
7688
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 .
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 )
92+ }
93+
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 : CTypeId ,
101+ mut val : Box < Expr > ,
90102 ) -> TranslationResult < Box < Expr > > {
91103 if let Some ( expr) = expr {
92104 match self . ast_context [ expr] . kind {
@@ -110,33 +122,42 @@ impl<'c> Translation<'c> {
110122 }
111123
112124 CExprKind :: Literal ( _, CLiteral :: Integer ( i, _) ) => {
113- return Ok ( self . enum_for_i64 ( enum_type_id , i as i64 ) ) ;
125+ return Ok ( self . enum_for_i64 ( enum_id , i as i64 ) ) ;
114126 }
115127
116128 CExprKind :: Unary ( _, c_ast:: UnOp :: Negate , subexpr_id, _) => {
117129 if let & CExprKind :: Literal ( _, CLiteral :: Integer ( i, _) ) =
118130 & self . ast_context [ subexpr_id] . kind
119131 {
120- return Ok ( self . enum_for_i64 ( enum_type_id , -( i as i64 ) ) ) ;
132+ return Ok ( self . enum_for_i64 ( enum_id , -( i as i64 ) ) ) ;
121133 }
122134 }
123135
124136 _ => { }
125137 }
126138 }
127139
128- let target_ty = self . convert_type ( enum_type_id) ?;
129- Ok ( mk ( ) . cast_expr ( val, target_ty) )
140+ let integral_type = self . enum_integral_type ( enum_id) ;
141+ let mut needs_cast = true ;
142+
143+ // C allows directly casting from enum to enum, but in Rust we need to use
144+ // the inner integer value as an intermediate.
145+ if let CTypeKind :: Enum ( source_enum_id) = self . ast_context . resolve_type ( source_cty) . kind {
146+ val = self . integer_from_enum ( val) ;
147+ needs_cast = integral_type. ctype != self . enum_integral_type ( source_enum_id) . ctype ;
148+ }
149+
150+ if needs_cast {
151+ let ty = self . convert_type ( integral_type. ctype ) ?;
152+ val = mk ( ) . cast_expr ( val, ty) ;
153+ }
154+
155+ Ok ( self . enum_constructor_expr ( enum_id, val) )
130156 }
131157
132158 /// Given an integer value this attempts to either generate the corresponding enum
133159 /// variant directly, otherwise it converts a number to the enum type.
134- fn enum_for_i64 ( & self , enum_type_id : CTypeId , value : i64 ) -> Box < Expr > {
135- let enum_id = match self . ast_context . resolve_type ( enum_type_id) . kind {
136- CTypeKind :: Enum ( enum_id) => enum_id,
137- _ => panic ! ( "{:?} does not point to an `enum` type" , enum_type_id) ,
138- } ;
139-
160+ fn enum_for_i64 ( & self , enum_id : CEnumId , value : i64 ) -> Box < Expr > {
140161 if let Some ( enum_constant_id) = self . enum_variant_for_i64 ( enum_id, value) {
141162 return self . enum_constant_expr ( enum_constant_id) ;
142163 }
@@ -148,8 +169,7 @@ impl<'c> Translation<'c> {
148169 _ => signed_int_expr ( value) ,
149170 } ;
150171
151- let target_ty = self . convert_type ( enum_type_id) . unwrap ( ) ;
152- mk ( ) . cast_expr ( value, target_ty)
172+ self . enum_constructor_expr ( enum_id, value)
153173 }
154174
155175 /// Returns the id of the variant of `enum_id` whose value matches `value`, if any.
@@ -170,6 +190,16 @@ impl<'c> Translation<'c> {
170190 } )
171191 }
172192
193+ fn enum_constructor_expr ( & self , enum_id : CEnumId , value : Box < Expr > ) -> Box < Expr > {
194+ let enum_name = self
195+ . type_converter
196+ . borrow ( )
197+ . resolve_decl_name ( enum_id)
198+ . unwrap ( ) ;
199+ self . add_import ( enum_id, & enum_name) ;
200+ mk ( ) . call_expr ( mk ( ) . ident_expr ( enum_name) , vec ! [ value] )
201+ }
202+
173203 fn enum_constant_expr ( & self , enum_constant_id : CEnumConstantId ) -> Box < Expr > {
174204 let name = self . renamer . borrow ( ) . get ( & enum_constant_id) . unwrap ( ) ;
175205 self . add_import ( enum_constant_id, & name) ;
0 commit comments