@@ -349,25 +349,28 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
349349
350350 // For the moment, we can only apply these
351351 // 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 => {
354355 let payload_ty = st. fields [ 0 ] ;
355356 return RawForbiddenValue {
356357 payload_discr : Disr :: from ( discr) ,
357358 payload_ty : payload_ty,
358- forbidden_value : C_null ( type_of :: sizing_type_of ( cx , payload_ty ) ) ,
359+ forbidden_value : forbidden_value ,
359360 unit_fields : cases[ 1 - discr] . tys . clone ( )
360361 } ;
361362 }
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+ }
371374 }
372375 None => { }
373376 }
@@ -466,60 +469,73 @@ struct Case<'tcx> {
466469/// This represents the (GEP) indices to follow to get to the discriminant field
467470pub type DiscrField = Vec < usize > ;
468471
469- fn find_discr_field_candidate < ' tcx > ( tcx : & ty :: ctxt < ' tcx > ,
472+ fn find_discr_field_candidate < ' a , ' tcx > ( cx : & CrateContext < ' a , ' tcx > ,
470473 ty : Ty < ' tcx > ,
471- mut path : DiscrField ) -> Option < DiscrField > {
474+ mut path : DiscrField ) -> Option < ( DiscrField , ValueRef ) > {
475+ let ref tcx = cx. tcx ( ) ;
472476 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 ) ) ) ,
484497
485498 // Is this the NonZero lang item wrapping a pointer or integer type?
499+ // If so, null is forbidden.
486500 ty:: TyStruct ( def, substs) if Some ( def. did ) == tcx. lang_items . non_zero ( ) => {
487501 let nonzero_fields = & def. struct_variant ( ) . fields ;
488502 assert_eq ! ( nonzero_fields. len( ) , 1 ) ;
489503 let field_ty = monomorphize:: field_ty ( tcx, substs, & nonzero_fields[ 0 ] ) ;
490504 match field_ty. sty {
491505 ty:: TyRawPtr ( ty:: TypeAndMut { ty, .. } ) if !type_is_sized ( tcx, ty) => {
492506 path. extend_from_slice ( & [ 0 , FAT_PTR_ADDR ] ) ;
493- Some ( path)
507+ Some ( ( path, C_null ( Type :: i8p ( cx ) ) ) )
494508 } ,
495509 ty:: TyRawPtr ( ..) | ty:: TyInt ( ..) | ty:: TyUint ( ..) => {
496510 path. push ( 0 ) ;
497- Some ( path)
511+ Some ( ( path, C_null ( type_of :: sizing_type_of ( cx , field_ty ) ) ) )
498512 } ,
499513 _ => None
500514 }
501515 } ,
502516
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.
504518 // let's recurse and find out
505519 ty:: TyStruct ( def, substs) => {
506520 for ( j, field) in def. struct_variant ( ) . fields . iter ( ) . enumerate ( ) {
507521 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 ( ) ) {
509524 fpath. push ( j) ;
510- return Some ( fpath) ;
525+ return Some ( ( fpath, forbidden ) ) ;
511526 }
512527 }
513528 None
514529 } ,
515530
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.
517532 // Let's recurse and find out!
518533 ty:: TyClosure ( _, ref substs) => {
519534 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 ( ) ) {
521537 fpath. push ( j) ;
522- return Some ( fpath) ;
538+ return Some ( ( fpath, forbidden ) ) ;
523539 }
524540 }
525541 None
@@ -528,26 +544,27 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>,
528544 // Can we use one of the fields in this tuple?
529545 ty:: TyTuple ( ref tys) => {
530546 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 ( ) ) {
532549 fpath. push ( j) ;
533- return Some ( fpath) ;
550+ return Some ( ( fpath, forbidden ) ) ;
534551 }
535552 }
536553 None
537554 } ,
538555
539- // Is this a fixed-size array of something non-zero
556+ // Is this a fixed-size array of something with a forbidden value
540557 // with at least one element?
541558 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) {
543560 vpath. push ( 0 ) ;
544- Some ( vpath)
561+ Some ( ( vpath, forbidden ) )
545562 } else {
546563 None
547564 }
548565 } ,
549566
550- // Anything else is not a pointer
567+ // Anything else doesn't have a known-to-be-safe forbidden value.
551568 _ => None
552569 }
553570}
@@ -557,13 +574,22 @@ impl<'tcx> Case<'tcx> {
557574 mk_struct ( cx, & self . tys , false , scapegoat) . size == 0
558575 }
559576
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
561578 /// 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 ) > {
563588 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 ! [ ] ) {
565591 path. push ( i) ;
566- return Some ( path) ;
592+ return Some ( ( path, forbidden ) ) ;
567593 }
568594 }
569595 None
@@ -1129,7 +1155,8 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
11291155 PointerCast ( bcx, val. value , ty. ptr_to ( ) )
11301156 }
11311157 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 ) ;
11331160 assert_eq ! ( discr, payload_discr) ;
11341161 let ty = type_of:: type_of ( bcx. ccx ( ) , payload_ty) ;
11351162 PointerCast ( bcx, val. value , ty. ptr_to ( ) )
0 commit comments