@@ -121,6 +121,7 @@ use syntax::ast;
121
121
use syntax:: ast_map;
122
122
use syntax:: ast_util:: local_def;
123
123
use syntax:: ast_util;
124
+ use syntax:: attr;
124
125
use syntax:: codemap:: Span ;
125
126
use syntax:: codemap;
126
127
use syntax:: opt_vec:: OptVec ;
@@ -3159,9 +3160,38 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt,
3159
3160
sp : Span ,
3160
3161
vs : & [ ast:: variant ] ,
3161
3162
id : ast:: NodeId ) {
3163
+
3164
+ fn disr_in_range ( ccx : @mut CrateCtxt ,
3165
+ ty : attr:: IntType ,
3166
+ disr : ty:: Disr ) -> bool {
3167
+ fn uint_in_range ( ccx : @mut CrateCtxt , ty : ast:: uint_ty , disr : ty:: Disr ) -> bool {
3168
+ match ty {
3169
+ ast:: ty_u8 => disr as u8 as Disr == disr,
3170
+ ast:: ty_u16 => disr as u16 as Disr == disr,
3171
+ ast:: ty_u32 => disr as u32 as Disr == disr,
3172
+ ast:: ty_u64 => disr as u64 as Disr == disr,
3173
+ ast:: ty_u => uint_in_range ( ccx, ccx. tcx . sess . targ_cfg . uint_type , disr)
3174
+ }
3175
+ }
3176
+ fn int_in_range ( ccx : @mut CrateCtxt , ty : ast:: int_ty , disr : ty:: Disr ) -> bool {
3177
+ match ty {
3178
+ ast:: ty_i8 => disr as i8 as Disr == disr,
3179
+ ast:: ty_i16 => disr as i16 as Disr == disr,
3180
+ ast:: ty_i32 => disr as i32 as Disr == disr,
3181
+ ast:: ty_i64 => disr as i64 as Disr == disr,
3182
+ ast:: ty_i => int_in_range ( ccx, ccx. tcx . sess . targ_cfg . int_type , disr)
3183
+ }
3184
+ }
3185
+ match ty {
3186
+ attr:: UnsignedInt ( ty) => uint_in_range ( ccx, ty, disr) ,
3187
+ attr:: SignedInt ( ty) => int_in_range ( ccx, ty, disr)
3188
+ }
3189
+ }
3190
+
3162
3191
fn do_check ( ccx : @mut CrateCtxt ,
3163
3192
vs : & [ ast:: variant ] ,
3164
- id : ast:: NodeId )
3193
+ id : ast:: NodeId ,
3194
+ hint : attr:: ReprAttr )
3165
3195
-> ~[ @ty:: VariantInfo ] {
3166
3196
3167
3197
let rty = ty:: node_id_to_type ( ccx. tcx , id) ;
@@ -3203,9 +3233,20 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt,
3203
3233
None => ( )
3204
3234
} ;
3205
3235
3206
- // Check for duplicate discriminator values
3236
+ // Check for duplicate discriminant values
3207
3237
if disr_vals. contains ( & current_disr_val) {
3208
- ccx. tcx . sess . span_err ( v. span , "discriminator value already exists" ) ;
3238
+ ccx. tcx . sess . span_err ( v. span , "discriminant value already exists" ) ;
3239
+ }
3240
+ // Check for unrepresentable discriminant values
3241
+ match hint {
3242
+ attr:: ReprAny | attr:: ReprExtern => ( ) ,
3243
+ attr:: ReprInt ( sp, ity) => {
3244
+ if !disr_in_range ( ccx, ity, current_disr_val) {
3245
+ ccx. tcx . sess . span_err ( v. span ,
3246
+ "discriminant value outside specified type" ) ;
3247
+ ccx. tcx . sess . span_note ( sp, "discriminant type specified here" ) ;
3248
+ }
3249
+ }
3209
3250
}
3210
3251
disr_vals. push ( current_disr_val) ;
3211
3252
@@ -3219,8 +3260,13 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt,
3219
3260
}
3220
3261
3221
3262
let rty = ty:: node_id_to_type ( ccx. tcx , id) ;
3263
+ let hint = ty:: lookup_repr_hint ( ccx. tcx , ast:: DefId { crate : ast:: LOCAL_CRATE , node : id } ) ;
3264
+ if hint != attr:: ReprAny && vs. len ( ) <= 1 {
3265
+ ccx. tcx . sess . span_err ( sp, format ! ( "unsupported representation for {}variant enum" ,
3266
+ if vs. len( ) == 1 { "uni" } else { "zero-" } ) )
3267
+ }
3222
3268
3223
- let variants = do_check ( ccx, vs, id) ;
3269
+ let variants = do_check ( ccx, vs, id, hint ) ;
3224
3270
3225
3271
// cache so that ty::enum_variants won't repeat this work
3226
3272
ccx. tcx . enum_var_cache . insert ( local_def ( id) , @variants) ;
0 commit comments