@@ -201,6 +201,7 @@ use ext::base::ExtCtxt;
201
201
use ext:: build:: AstBuilder ;
202
202
use codemap:: { self , DUMMY_SP } ;
203
203
use codemap:: Span ;
204
+ use diagnostic:: SpanHandler ;
204
205
use fold:: MoveMap ;
205
206
use owned_slice:: OwnedSlice ;
206
207
use parse:: token:: InternedString ;
@@ -391,6 +392,7 @@ impl<'a> TraitDef<'a> {
391
392
ast:: ItemEnum ( ref enum_def, ref generics) => {
392
393
self . expand_enum_def ( cx,
393
394
enum_def,
395
+ & item. attrs [ ..] ,
394
396
item. ident ,
395
397
generics)
396
398
}
@@ -653,6 +655,7 @@ impl<'a> TraitDef<'a> {
653
655
fn expand_enum_def ( & self ,
654
656
cx : & mut ExtCtxt ,
655
657
enum_def : & EnumDef ,
658
+ type_attrs : & [ ast:: Attribute ] ,
656
659
type_ident : Ident ,
657
660
generics : & Generics ) -> P < ast:: Item > {
658
661
let mut field_tys = Vec :: new ( ) ;
@@ -687,6 +690,7 @@ impl<'a> TraitDef<'a> {
687
690
method_def. expand_enum_method_body ( cx,
688
691
self ,
689
692
enum_def,
693
+ type_attrs,
690
694
type_ident,
691
695
self_args,
692
696
& nonself_args[ ..] )
@@ -706,13 +710,30 @@ impl<'a> TraitDef<'a> {
706
710
}
707
711
}
708
712
709
- fn variant_to_pat ( cx : & mut ExtCtxt , sp : Span , enum_ident : ast:: Ident , variant : & ast:: Variant )
710
- -> P < ast:: Pat > {
711
- let path = cx. path ( sp, vec ! [ enum_ident, variant. node. name] ) ;
712
- cx. pat ( sp, match variant. node . kind {
713
- ast:: TupleVariantKind ( ..) => ast:: PatEnum ( path, None ) ,
714
- ast:: StructVariantKind ( ..) => ast:: PatStruct ( path, Vec :: new ( ) , true ) ,
715
- } )
713
+ fn find_repr_type_name ( diagnostic : & SpanHandler ,
714
+ type_attrs : & [ ast:: Attribute ] ) -> & ' static str {
715
+ let mut repr_type_name = "i32" ;
716
+ for a in type_attrs {
717
+ for r in & attr:: find_repr_attrs ( diagnostic, a) {
718
+ repr_type_name = match * r {
719
+ attr:: ReprAny | attr:: ReprPacked => continue ,
720
+ attr:: ReprExtern => "i32" ,
721
+
722
+ attr:: ReprInt ( _, attr:: SignedInt ( ast:: TyIs ) ) => "isize" ,
723
+ attr:: ReprInt ( _, attr:: SignedInt ( ast:: TyI8 ) ) => "i8" ,
724
+ attr:: ReprInt ( _, attr:: SignedInt ( ast:: TyI16 ) ) => "i16" ,
725
+ attr:: ReprInt ( _, attr:: SignedInt ( ast:: TyI32 ) ) => "i32" ,
726
+ attr:: ReprInt ( _, attr:: SignedInt ( ast:: TyI64 ) ) => "i64" ,
727
+
728
+ attr:: ReprInt ( _, attr:: UnsignedInt ( ast:: TyUs ) ) => "usize" ,
729
+ attr:: ReprInt ( _, attr:: UnsignedInt ( ast:: TyU8 ) ) => "u8" ,
730
+ attr:: ReprInt ( _, attr:: UnsignedInt ( ast:: TyU16 ) ) => "u16" ,
731
+ attr:: ReprInt ( _, attr:: UnsignedInt ( ast:: TyU32 ) ) => "u32" ,
732
+ attr:: ReprInt ( _, attr:: UnsignedInt ( ast:: TyU64 ) ) => "u64" ,
733
+ }
734
+ }
735
+ }
736
+ repr_type_name
716
737
}
717
738
718
739
impl < ' a > MethodDef < ' a > {
@@ -983,12 +1004,13 @@ impl<'a> MethodDef<'a> {
983
1004
cx : & mut ExtCtxt ,
984
1005
trait_ : & TraitDef ,
985
1006
enum_def : & EnumDef ,
1007
+ type_attrs : & [ ast:: Attribute ] ,
986
1008
type_ident : Ident ,
987
1009
self_args : Vec < P < Expr > > ,
988
1010
nonself_args : & [ P < Expr > ] )
989
1011
-> P < Expr > {
990
1012
self . build_enum_match_tuple (
991
- cx, trait_, enum_def, type_ident, self_args, nonself_args)
1013
+ cx, trait_, enum_def, type_attrs , type_ident, self_args, nonself_args)
992
1014
}
993
1015
994
1016
@@ -1022,6 +1044,7 @@ impl<'a> MethodDef<'a> {
1022
1044
cx : & mut ExtCtxt ,
1023
1045
trait_ : & TraitDef ,
1024
1046
enum_def : & EnumDef ,
1047
+ type_attrs : & [ ast:: Attribute ] ,
1025
1048
type_ident : Ident ,
1026
1049
self_args : Vec < P < Expr > > ,
1027
1050
nonself_args : & [ P < Expr > ] ) -> P < Expr > {
@@ -1044,8 +1067,8 @@ impl<'a> MethodDef<'a> {
1044
1067
. collect :: < Vec < ast:: Ident > > ( ) ;
1045
1068
1046
1069
// The `vi_idents` will be bound, solely in the catch-all, to
1047
- // a series of let statements mapping each self_arg to a usize
1048
- // corresponding to its variant index .
1070
+ // a series of let statements mapping each self_arg to an int
1071
+ // value corresponding to its discriminant .
1049
1072
let vi_idents: Vec < ast:: Ident > = self_arg_names. iter ( )
1050
1073
. map ( |name| { let vi_suffix = format ! ( "{}_vi" , & name[ ..] ) ;
1051
1074
cx. ident_of ( & vi_suffix[ ..] ) } )
@@ -1160,33 +1183,44 @@ impl<'a> MethodDef<'a> {
1160
1183
// unreachable-pattern error.
1161
1184
//
1162
1185
if variants. len ( ) > 1 && self_args. len ( ) > 1 {
1163
- let arms: Vec < ast:: Arm > = variants. iter ( ) . enumerate ( )
1164
- . map ( |( index, variant) | {
1165
- let pat = variant_to_pat ( cx, sp, type_ident, & * * variant) ;
1166
- let lit = ast:: LitInt ( index as u64 , ast:: UnsignedIntLit ( ast:: TyUs ) ) ;
1167
- cx. arm ( sp, vec ! [ pat] , cx. expr_lit ( sp, lit) )
1168
- } ) . collect ( ) ;
1169
-
1170
1186
// Build a series of let statements mapping each self_arg
1171
- // to a usize corresponding to its variant index.
1187
+ // to its discriminant value. If this is a C-style enum
1188
+ // with a specific repr type, then casts the values to
1189
+ // that type. Otherwise casts to `i32` (the default repr
1190
+ // type).
1191
+ //
1172
1192
// i.e. for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
1173
1193
// with three Self args, builds three statements:
1174
1194
//
1175
1195
// ```
1176
- // let __self0_vi = match self {
1177
- // A => 0, B(..) => 1, C(..) => 2
1178
- // };
1179
- // let __self1_vi = match __arg1 {
1180
- // A => 0, B(..) => 1, C(..) => 2
1181
- // };
1182
- // let __self2_vi = match __arg2 {
1183
- // A => 0, B(..) => 1, C(..) => 2
1184
- // };
1196
+ // let __self0_vi = unsafe {
1197
+ // std::intrinsics::discriminant_value(&self) } as i32;
1198
+ // let __self1_vi = unsafe {
1199
+ // std::intrinsics::discriminant_value(&__arg1) } as i32;
1200
+ // let __self2_vi = unsafe {
1201
+ // std::intrinsics::discriminant_value(&__arg2) } as i32;
1185
1202
// ```
1186
1203
let mut index_let_stmts: Vec < P < ast:: Stmt > > = Vec :: new ( ) ;
1204
+
1205
+ let target_type_name =
1206
+ find_repr_type_name ( & cx. parse_sess . span_diagnostic , type_attrs) ;
1207
+
1187
1208
for ( & ident, self_arg) in vi_idents. iter ( ) . zip ( self_args. iter ( ) ) {
1188
- let variant_idx = cx. expr_match ( sp, self_arg. clone ( ) , arms. clone ( ) ) ;
1189
- let let_stmt = cx. stmt_let ( sp, false , ident, variant_idx) ;
1209
+ let path = vec ! [ cx. ident_of_std( "core" ) ,
1210
+ cx. ident_of( "intrinsics" ) ,
1211
+ cx. ident_of( "discriminant_value" ) ] ;
1212
+ let call = cx. expr_call_global (
1213
+ sp, path, vec ! [ cx. expr_addr_of( sp, self_arg. clone( ) ) ] ) ;
1214
+ let variant_value = cx. expr_block ( P ( ast:: Block {
1215
+ stmts : vec ! [ ] ,
1216
+ expr : Some ( call) ,
1217
+ id : ast:: DUMMY_NODE_ID ,
1218
+ rules : ast:: UnsafeBlock ( ast:: CompilerGenerated ) ,
1219
+ span : sp } ) ) ;
1220
+
1221
+ let target_ty = cx. ty_ident ( sp, cx. ident_of ( target_type_name) ) ;
1222
+ let variant_disr = cx. expr_cast ( sp, variant_value, target_ty) ;
1223
+ let let_stmt = cx. stmt_let ( sp, false , ident, variant_disr) ;
1190
1224
index_let_stmts. push ( let_stmt) ;
1191
1225
}
1192
1226
0 commit comments