@@ -241,25 +241,28 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
241
241
242
242
// For the moment, we can only apply these
243
243
// optimizations to safe pointers.
244
- match cases[ discr] . find_ptr ( cx) {
245
- Some ( ref df) if df. len ( ) == 1 && st. fields . len ( ) == 1 => {
244
+ match cases[ discr] . find_forbidden_value ( cx) {
245
+ Some ( ( ref df, forbidden_value) )
246
+ if df. len ( ) == 1 && st. fields . len ( ) == 1 => {
246
247
let payload_ty = st. fields [ 0 ] ;
247
248
return RawForbiddenValue {
248
249
payload_discr : Disr :: from ( discr) ,
249
250
payload_ty : payload_ty,
250
- forbidden_value : C_null ( type_of :: sizing_type_of ( cx , payload_ty ) ) ,
251
+ forbidden_value : forbidden_value ,
251
252
unit_fields : cases[ 1 - discr] . tys . clone ( )
252
253
} ;
253
254
}
254
- Some ( mut discrfield) => {
255
- discrfield. push ( 0 ) ;
256
- discrfield. reverse ( ) ;
257
- return StructWrappedNullablePointer {
258
- nndiscr : Disr :: from ( discr) ,
259
- nonnull : st,
260
- discrfield : discrfield,
261
- nullfields : cases[ 1 - discr] . tys . clone ( )
262
- } ;
255
+ Some ( ( mut discrfield, forbidden) ) => {
256
+ if is_null ( forbidden) {
257
+ discrfield. push ( 0 ) ;
258
+ discrfield. reverse ( ) ;
259
+ return StructWrappedNullablePointer {
260
+ nndiscr : Disr :: from ( discr) ,
261
+ nonnull : st,
262
+ discrfield : discrfield,
263
+ nullfields : cases[ 1 - discr] . tys . clone ( )
264
+ } ;
265
+ }
263
266
}
264
267
None => { }
265
268
}
@@ -365,61 +368,73 @@ struct Case<'tcx> {
365
368
/// This represents the (GEP) indices to follow to get to the discriminant field
366
369
pub type DiscrField = Vec < usize > ;
367
370
368
- fn find_discr_field_candidate < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
371
+ fn find_discr_field_candidate < ' a , ' tcx > ( cx : & CrateContext < ' a , ' tcx > ,
372
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
369
373
ty : Ty < ' tcx > ,
370
374
mut path : DiscrField )
371
- -> Option < DiscrField > {
375
+ -> Option < ( DiscrField , ValueRef ) > {
372
376
match ty. sty {
373
- // Fat &T/&mut T/Box<T> i.e. T is [T], str, or Trait
377
+ // Fat &T/&mut T/Box<T> i.e. T is [T], str, or Trait; null is forbidden
374
378
ty:: TyRef ( _, ty:: TypeAndMut { ty, .. } ) | ty:: TyBox ( ty) if !type_is_sized ( tcx, ty) => {
375
379
path. push ( FAT_PTR_ADDR ) ;
376
- Some ( path)
380
+ Some ( ( path, C_null ( type_of :: sizing_type_of ( cx , ty ) ) ) )
377
381
} ,
378
382
379
- // Regular thin pointer: &T/&mut T/Box<T>
380
- ty:: TyRef ( ..) | ty:: TyBox ( ..) => Some ( path) ,
383
+ // Regular thin pointer: &T/&mut T/Box<T>; null is forbidden
384
+ ty:: TyRef ( ..) | ty:: TyBox ( ..) => Some ( ( path, C_null ( type_of:: sizing_type_of ( cx, ty) ) ) ) ,
385
+
386
+ // Function pointer: `fn() -> i32`; null is forbidden
387
+ ty:: TyFnPtr ( _) => Some ( ( path, C_null ( type_of:: sizing_type_of ( cx, ty) ) ) ) ,
381
388
382
- // Function pointer: `fn() -> i32`
383
- ty:: TyFnPtr ( _) => Some ( path) ,
389
+ // Is this a char or a bool? If so, std::uXX:MAX is forbidden.
390
+ ty:: TyChar => Some ( ( path,
391
+ C_integral ( type_of:: sizing_type_of ( cx, ty) ,
392
+ std:: u32:: MAX as u64 , false ) ) ) ,
393
+ ty:: TyBool => Some ( ( path,
394
+ C_integral ( type_of:: sizing_type_of ( cx, ty) ,
395
+ std:: u8:: MAX as u64 , false ) ) ) ,
384
396
385
397
// Is this the NonZero lang item wrapping a pointer or integer type?
398
+ // If so, null is forbidden.
386
399
ty:: TyStruct ( def, substs) if Some ( def. did ) == tcx. lang_items . non_zero ( ) => {
387
400
let nonzero_fields = & def. struct_variant ( ) . fields ;
388
401
assert_eq ! ( nonzero_fields. len( ) , 1 ) ;
389
402
let field_ty = monomorphize:: field_ty ( tcx, substs, & nonzero_fields[ 0 ] ) ;
390
403
match field_ty. sty {
391
404
ty:: TyRawPtr ( ty:: TypeAndMut { ty, .. } ) if !type_is_sized ( tcx, ty) => {
392
405
path. extend_from_slice ( & [ 0 , FAT_PTR_ADDR ] ) ;
393
- Some ( path)
406
+ Some ( ( path, C_null ( Type :: i8p ( cx ) ) ) )
394
407
} ,
395
408
ty:: TyRawPtr ( ..) | ty:: TyInt ( ..) | ty:: TyUint ( ..) => {
396
409
path. push ( 0 ) ;
397
- Some ( path)
410
+ Some ( ( path, C_null ( type_of :: sizing_type_of ( cx , field_ty ) ) ) )
398
411
} ,
399
412
_ => None
400
413
}
401
414
} ,
402
415
403
- // Perhaps one of the fields of this struct is non-zero
416
+ // Perhaps one of the fields of this struct has a forbidden value.
404
417
// let's recurse and find out
405
418
ty:: TyStruct ( def, substs) => {
406
419
for ( j, field) in def. struct_variant ( ) . fields . iter ( ) . enumerate ( ) {
407
420
let field_ty = monomorphize:: field_ty ( tcx, substs, field) ;
408
- if let Some ( mut fpath) = find_discr_field_candidate ( tcx, field_ty, path. clone ( ) ) {
421
+ if let Some ( ( mut fpath, forbidden) ) =
422
+ find_discr_field_candidate ( cx, field_ty, path. clone ( ) ) {
409
423
fpath. push ( j) ;
410
- return Some ( fpath) ;
424
+ return Some ( ( fpath, forbidden ) ) ;
411
425
}
412
426
}
413
427
None
414
428
} ,
415
429
416
- // Perhaps one of the upvars of this struct is non-zero
430
+ // Perhaps one of the upvars of this struct has a forbidden value.
417
431
// Let's recurse and find out!
418
432
ty:: TyClosure ( _, ref substs) => {
419
433
for ( j, & ty) in substs. upvar_tys . iter ( ) . enumerate ( ) {
420
- if let Some ( mut fpath) = find_discr_field_candidate ( tcx, ty, path. clone ( ) ) {
434
+ if let Some ( ( mut fpath, forbidden) ) =
435
+ find_discr_field_candidate ( cx, ty, path. clone ( ) ) {
421
436
fpath. push ( j) ;
422
- return Some ( fpath) ;
437
+ return Some ( ( fpath, forbidden ) ) ;
423
438
}
424
439
}
425
440
None
@@ -428,26 +443,27 @@ fn find_discr_field_candidate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
428
443
// Can we use one of the fields in this tuple?
429
444
ty:: TyTuple ( ref tys) => {
430
445
for ( j, & ty) in tys. iter ( ) . enumerate ( ) {
431
- if let Some ( mut fpath) = find_discr_field_candidate ( tcx, ty, path. clone ( ) ) {
446
+ if let Some ( ( mut fpath, forbidden) ) =
447
+ find_discr_field_candidate ( cx, ty, path. clone ( ) ) {
432
448
fpath. push ( j) ;
433
- return Some ( fpath) ;
449
+ return Some ( ( fpath, forbidden ) ) ;
434
450
}
435
451
}
436
452
None
437
453
} ,
438
454
439
- // Is this a fixed-size array of something non-zero
455
+ // Is this a fixed-size array of something with a forbidden value
440
456
// with at least one element?
441
457
ty:: TyArray ( ety, d) if d > 0 => {
442
- if let Some ( mut vpath) = find_discr_field_candidate ( tcx , ety, path) {
458
+ if let Some ( ( mut vpath, forbidden ) ) = find_discr_field_candidate ( cx , ety, path) {
443
459
vpath. push ( 0 ) ;
444
- Some ( vpath)
460
+ Some ( ( vpath, forbidden ) )
445
461
} else {
446
462
None
447
463
}
448
464
} ,
449
465
450
- // Anything else is not a pointer
466
+ // Anything else doesn't have a known-to-be-safe forbidden value.
451
467
_ => None
452
468
}
453
469
}
@@ -457,13 +473,22 @@ impl<'tcx> Case<'tcx> {
457
473
mk_struct ( cx, & self . tys , false , scapegoat) . size == 0
458
474
}
459
475
460
- /// Find a safe pointer that may be used to discriminate in a
476
+ /// Find a forbidden value that may be used to discriminate in a
461
477
/// RawForbiddenValue or StructWrappedNullablePointer.
462
- fn find_ptr < ' a > ( & self , cx : & CrateContext < ' a , ' tcx > ) -> Option < DiscrField > {
478
+ ///
479
+ /// Example: In `Option<&T>`, since `&T` has a forbidden value 0,
480
+ /// this method will return the path to `&T`, with a value of 0.
481
+ ///
482
+ /// Example: In `Option<(u64, char)>`, since `char` has a
483
+ /// forbidden value 2^32 - 1, this method will return the path to
484
+ /// the `char` field in the tuple, with a value of 2^32 - 1.
485
+ fn find_forbidden_value < ' a > ( & self , cx : & CrateContext < ' a , ' tcx > ) ->
486
+ Option < ( DiscrField , ValueRef ) > {
463
487
for ( i, & ty) in self . tys . iter ( ) . enumerate ( ) {
464
- if let Some ( mut path) = find_discr_field_candidate ( cx. tcx ( ) , ty, vec ! [ ] ) {
488
+ if let Some ( ( mut path, forbidden) ) =
489
+ find_discr_field_candidate ( cx, ty, vec ! [ ] ) {
465
490
path. push ( i) ;
466
- return Some ( path) ;
491
+ return Some ( ( path, forbidden ) ) ;
467
492
}
468
493
}
469
494
None
@@ -973,7 +998,8 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
973
998
bcx. pointercast ( val. value , ty. ptr_to ( ) )
974
999
}
975
1000
RawForbiddenValue { payload_discr, payload_ty, .. } => {
976
- assert_eq ! ( ix, 0 ) ; // By definition, the payload of RawForbiddenValue has a single field.
1001
+ // By definition, the payload of RawForbiddenValue has a single field.
1002
+ assert_eq ! ( ix, 0 ) ;
977
1003
assert_eq ! ( discr, payload_discr) ;
978
1004
let ty = type_of:: type_of ( bcx. ccx ( ) , payload_ty) ;
979
1005
if bcx. is_unreachable ( ) { return C_undef ( ty. ptr_to ( ) ) ; }
0 commit comments