@@ -349,25 +349,28 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
349
349
350
350
// For the moment, we can only apply these
351
351
// optimizations to safe pointers.
352
- match cases[ discr] . find_ptr ( cx) {
353
- Some ( ref df) if df. len ( ) == 1 && st. fields . len ( ) == 1 => {
352
+ match cases[ discr] . find_forbidden_value ( cx) {
353
+ Some ( ( ref df, forbidden_value) )
354
+ if df. len ( ) == 1 && st. fields . len ( ) == 1 => {
354
355
let payload_ty = st. fields [ 0 ] ;
355
356
return RawForbiddenValue {
356
357
payload_discr : Disr :: from ( discr) ,
357
358
payload_ty : payload_ty,
358
- forbidden_value : C_null ( type_of :: sizing_type_of ( cx , payload_ty ) ) ,
359
+ forbidden_value : forbidden_value ,
359
360
unit_fields : cases[ 1 - discr] . tys . clone ( )
360
361
} ;
361
362
}
362
- Some ( mut discrfield) => {
363
- discrfield. push ( 0 ) ;
364
- discrfield. reverse ( ) ;
365
- return StructWrappedNullablePointer {
366
- nndiscr : Disr :: from ( discr) ,
367
- nonnull : st,
368
- discrfield : discrfield,
369
- nullfields : cases[ 1 - discr] . tys . clone ( )
370
- } ;
363
+ Some ( ( mut discrfield, forbidden) ) => {
364
+ if is_null ( forbidden) {
365
+ discrfield. push ( 0 ) ;
366
+ discrfield. reverse ( ) ;
367
+ return StructWrappedNullablePointer {
368
+ nndiscr : Disr :: from ( discr) ,
369
+ nonnull : st,
370
+ discrfield : discrfield,
371
+ nullfields : cases[ 1 - discr] . tys . clone ( )
372
+ } ;
373
+ }
371
374
}
372
375
None => { }
373
376
}
@@ -466,60 +469,73 @@ struct Case<'tcx> {
466
469
/// This represents the (GEP) indices to follow to get to the discriminant field
467
470
pub type DiscrField = Vec < usize > ;
468
471
469
- fn find_discr_field_candidate < ' tcx > ( tcx : & ty :: ctxt < ' tcx > ,
472
+ fn find_discr_field_candidate < ' a , ' tcx > ( cx : & CrateContext < ' a , ' tcx > ,
470
473
ty : Ty < ' tcx > ,
471
- mut path : DiscrField ) -> Option < DiscrField > {
474
+ mut path : DiscrField ) -> Option < ( DiscrField , ValueRef ) > {
475
+ let ref tcx = cx. tcx ( ) ;
472
476
match ty. sty {
473
- // Fat &T/&mut T/Box<T> i.e. T is [T], str, or Trait
474
- ty:: TyRef ( _, ty:: TypeAndMut { ty, .. } ) | ty:: TyBox ( ty) if !type_is_sized ( tcx, ty) => {
475
- path. push ( FAT_PTR_ADDR ) ;
476
- Some ( path)
477
- } ,
478
-
479
- // Regular thin pointer: &T/&mut T/Box<T>
480
- ty:: TyRef ( ..) | ty:: TyBox ( ..) => Some ( path) ,
481
-
482
- // Functions are just pointers
483
- ty:: TyBareFn ( ..) => Some ( path) ,
477
+ // Fat &T/&mut T/Box<T> i.e. T is [T], str, or Trait: null is forbidden
478
+ ty:: TyRef ( _, ty:: TypeAndMut { ty : ty2, .. } ) | ty:: TyBox ( ty2)
479
+ if !type_is_sized ( tcx, ty2) => {
480
+ path. push ( FAT_PTR_ADDR ) ;
481
+ Some ( ( path, C_null ( type_of:: sizing_type_of ( cx, ty) ) ) )
482
+ } ,
483
+
484
+ // Regular thin pointer: &T/&mut T/Box<T>: null is forbidden
485
+ ty:: TyRef ( ..) | ty:: TyBox ( ..) => Some ( ( path, C_null ( type_of:: sizing_type_of ( cx, ty) ) ) ) ,
486
+
487
+ // Functions are just pointers: null is forbidden
488
+ ty:: TyBareFn ( ..) => Some ( ( path, C_null ( type_of:: sizing_type_of ( cx, ty) ) ) ) ,
489
+
490
+ // Is this a char or a bool? If so, std::uXX:MAX is forbidden.
491
+ ty:: TyChar => Some ( ( path,
492
+ C_integral ( type_of:: sizing_type_of ( cx, ty) ,
493
+ std:: u32:: MAX as u64 , false ) ) ) ,
494
+ ty:: TyBool => Some ( ( path,
495
+ C_integral ( type_of:: sizing_type_of ( cx, ty) ,
496
+ std:: u8:: MAX as u64 , false ) ) ) ,
484
497
485
498
// Is this the NonZero lang item wrapping a pointer or integer type?
499
+ // If so, null is forbidden.
486
500
ty:: TyStruct ( def, substs) if Some ( def. did ) == tcx. lang_items . non_zero ( ) => {
487
501
let nonzero_fields = & def. struct_variant ( ) . fields ;
488
502
assert_eq ! ( nonzero_fields. len( ) , 1 ) ;
489
503
let field_ty = monomorphize:: field_ty ( tcx, substs, & nonzero_fields[ 0 ] ) ;
490
504
match field_ty. sty {
491
505
ty:: TyRawPtr ( ty:: TypeAndMut { ty, .. } ) if !type_is_sized ( tcx, ty) => {
492
506
path. extend_from_slice ( & [ 0 , FAT_PTR_ADDR ] ) ;
493
- Some ( path)
507
+ Some ( ( path, C_null ( Type :: i8p ( cx ) ) ) )
494
508
} ,
495
509
ty:: TyRawPtr ( ..) | ty:: TyInt ( ..) | ty:: TyUint ( ..) => {
496
510
path. push ( 0 ) ;
497
- Some ( path)
511
+ Some ( ( path, C_null ( type_of :: sizing_type_of ( cx , field_ty ) ) ) )
498
512
} ,
499
513
_ => None
500
514
}
501
515
} ,
502
516
503
- // Perhaps one of the fields of this struct is non-zero
517
+ // Perhaps one of the fields of this struct has a forbidden value.
504
518
// let's recurse and find out
505
519
ty:: TyStruct ( def, substs) => {
506
520
for ( j, field) in def. struct_variant ( ) . fields . iter ( ) . enumerate ( ) {
507
521
let field_ty = monomorphize:: field_ty ( tcx, substs, field) ;
508
- if let Some ( mut fpath) = find_discr_field_candidate ( tcx, field_ty, path. clone ( ) ) {
522
+ if let Some ( ( mut fpath, forbidden) ) =
523
+ find_discr_field_candidate ( cx, field_ty, path. clone ( ) ) {
509
524
fpath. push ( j) ;
510
- return Some ( fpath) ;
525
+ return Some ( ( fpath, forbidden ) ) ;
511
526
}
512
527
}
513
528
None
514
529
} ,
515
530
516
- // Perhaps one of the upvars of this struct is non-zero
531
+ // Perhaps one of the upvars of this struct has a forbidden value.
517
532
// Let's recurse and find out!
518
533
ty:: TyClosure ( _, ref substs) => {
519
534
for ( j, & ty) in substs. upvar_tys . iter ( ) . enumerate ( ) {
520
- if let Some ( mut fpath) = find_discr_field_candidate ( tcx, ty, path. clone ( ) ) {
535
+ if let Some ( ( mut fpath, forbidden) ) =
536
+ find_discr_field_candidate ( cx, ty, path. clone ( ) ) {
521
537
fpath. push ( j) ;
522
- return Some ( fpath) ;
538
+ return Some ( ( fpath, forbidden ) ) ;
523
539
}
524
540
}
525
541
None
@@ -528,26 +544,27 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>,
528
544
// Can we use one of the fields in this tuple?
529
545
ty:: TyTuple ( ref tys) => {
530
546
for ( j, & ty) in tys. iter ( ) . enumerate ( ) {
531
- if let Some ( mut fpath) = find_discr_field_candidate ( tcx, ty, path. clone ( ) ) {
547
+ if let Some ( ( mut fpath, forbidden) ) =
548
+ find_discr_field_candidate ( cx, ty, path. clone ( ) ) {
532
549
fpath. push ( j) ;
533
- return Some ( fpath) ;
550
+ return Some ( ( fpath, forbidden ) ) ;
534
551
}
535
552
}
536
553
None
537
554
} ,
538
555
539
- // Is this a fixed-size array of something non-zero
556
+ // Is this a fixed-size array of something with a forbidden value
540
557
// with at least one element?
541
558
ty:: TyArray ( ety, d) if d > 0 => {
542
- if let Some ( mut vpath) = find_discr_field_candidate ( tcx , ety, path) {
559
+ if let Some ( ( mut vpath, forbidden ) ) = find_discr_field_candidate ( cx , ety, path) {
543
560
vpath. push ( 0 ) ;
544
- Some ( vpath)
561
+ Some ( ( vpath, forbidden ) )
545
562
} else {
546
563
None
547
564
}
548
565
} ,
549
566
550
- // Anything else is not a pointer
567
+ // Anything else doesn't have a known-to-be-safe forbidden value.
551
568
_ => None
552
569
}
553
570
}
@@ -557,13 +574,22 @@ impl<'tcx> Case<'tcx> {
557
574
mk_struct ( cx, & self . tys , false , scapegoat) . size == 0
558
575
}
559
576
560
- /// Find a safe pointer that may be used to discriminate in a
577
+ /// Find a forbidden value that may be used to discriminate in a
561
578
/// RawForbiddenValue or StructWrappedNullablePointer.
562
- fn find_ptr < ' a > ( & self , cx : & CrateContext < ' a , ' tcx > ) -> Option < DiscrField > {
579
+ ///
580
+ /// Example: In `Option<&T>`, since `&T` has a forbidden value 0,
581
+ /// this method will return the path to `&T`, with a value of 0.
582
+ ///
583
+ /// Example: In `Option<(u64, char)>`, since `char` has a
584
+ /// forbidden value 2^32 - 1, this method will return the path to
585
+ /// the `char` field in the tuple, with a value of 2^32 - 1.
586
+ fn find_forbidden_value < ' a > ( & self , cx : & CrateContext < ' a , ' tcx > ) ->
587
+ Option < ( DiscrField , ValueRef ) > {
563
588
for ( i, & ty) in self . tys . iter ( ) . enumerate ( ) {
564
- if let Some ( mut path) = find_discr_field_candidate ( cx. tcx ( ) , ty, vec ! [ ] ) {
589
+ if let Some ( ( mut path, forbidden) ) =
590
+ find_discr_field_candidate ( cx, ty, vec ! [ ] ) {
565
591
path. push ( i) ;
566
- return Some ( path) ;
592
+ return Some ( ( path, forbidden ) ) ;
567
593
}
568
594
}
569
595
None
@@ -1129,7 +1155,8 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
1129
1155
PointerCast ( bcx, val. value , ty. ptr_to ( ) )
1130
1156
}
1131
1157
RawForbiddenValue { payload_discr, payload_ty, .. } => {
1132
- assert_eq ! ( ix, 0 ) ; // By definition, the payload of RawForbiddenValue has a single field.
1158
+ // By definition, the payload of RawForbiddenValue has a single field.
1159
+ assert_eq ! ( ix, 0 ) ;
1133
1160
assert_eq ! ( discr, payload_discr) ;
1134
1161
let ty = type_of:: type_of ( bcx. ccx ( ) , payload_ty) ;
1135
1162
PointerCast ( bcx, val. value , ty. ptr_to ( ) )
0 commit comments