@@ -11,7 +11,7 @@ use rustc_index::vec::Idx;
11
11
use rustc_middle:: mir:: interpret:: { sign_extend, truncate} ;
12
12
use rustc_middle:: ty:: layout:: { IntegerExt , SizeSkeleton } ;
13
13
use rustc_middle:: ty:: subst:: SubstsRef ;
14
- use rustc_middle:: ty:: { self , AdtKind , Ty , TyCtxt , TypeFoldable } ;
14
+ use rustc_middle:: ty:: { self , AdtKind , Ty , TypeFoldable } ;
15
15
use rustc_span:: source_map;
16
16
use rustc_span:: symbol:: sym;
17
17
use rustc_span:: { Span , DUMMY_SP } ;
@@ -550,25 +550,26 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
550
550
_ => false ,
551
551
}
552
552
}
553
- /// Given a potentially non-null type `ty`, return its default, nullable type.
554
- fn get_nullable_type < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
555
- match ty. kind {
553
+ /// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type.
554
+ /// If the type passed in was not scalar, returns None.
555
+ fn get_nullable_type < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> Option < Ty < ' tcx > > {
556
+ let tcx = cx. tcx ;
557
+ Some ( match ty. kind {
556
558
ty:: Adt ( field_def, field_substs) => {
557
- let field_variants = & field_def. variants ;
558
- // We hit this case for #[repr(transparent)] structs with a single
559
- // field.
560
- debug_assert ! (
561
- field_variants. len( ) == 1 && field_variants[ VariantIdx :: new( 0 ) ] . fields. len( ) == 1 ,
562
- "inner ty not a newtype struct"
563
- ) ;
564
- debug_assert ! ( field_def. repr. transparent( ) , "inner ty not transparent" ) ;
565
- // As it's easy to get this wrong, it's worth noting that
566
- // `inner_field_ty` is not the same as `field_ty`: Given Option<S>,
567
- // where S is a transparent newtype of some type T, `field_ty`
568
- // gives us S, while `inner_field_ty` is T.
569
- let inner_field_ty =
570
- field_def. variants [ VariantIdx :: new ( 0 ) ] . fields [ 0 ] . ty ( tcx, field_substs) ;
571
- get_nullable_type ( tcx, inner_field_ty)
559
+ let inner_field_ty = {
560
+ let mut first_non_zst_ty = field_def. all_fields ( ) . filter_map ( |f| {
561
+ let field_ty =
562
+ tcx. normalize_erasing_regions ( cx. param_env , f. ty ( tcx, field_substs) ) ;
563
+ if !field_ty. is_zst ( tcx, f. did ) { Some ( field_ty) } else { None }
564
+ } ) ;
565
+ debug_assert_eq ! (
566
+ first_non_zst_ty. clone( ) . count( ) ,
567
+ 1 ,
568
+ "Wrong number of fields for transparent type"
569
+ ) ;
570
+ first_non_zst_ty. next ( ) . expect ( "No non-zst fields in transparent type." )
571
+ } ;
572
+ return get_nullable_type ( cx, inner_field_ty) ;
572
573
}
573
574
ty:: Int ( ty) => tcx. mk_mach_int ( ty) ,
574
575
ty:: Uint ( ty) => tcx. mk_mach_uint ( ty) ,
@@ -585,9 +586,13 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
585
586
// We should only ever reach this case if ty_is_known_nonnull is extended
586
587
// to other types.
587
588
ref unhandled => {
588
- unreachable ! ( "Unhandled scalar kind: {:?} while checking {:?}" , unhandled, ty)
589
+ debug ! (
590
+ "get_nullable_type: Unhandled scalar kind: {:?} while checking {:?}" ,
591
+ unhandled, ty
592
+ ) ;
593
+ return None ;
589
594
}
590
- }
595
+ } )
591
596
}
592
597
593
598
/// Check if this `ty` can be safely exported based on the "nullable pointer optimization".
@@ -633,9 +638,9 @@ crate fn repr_nullable_ptr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option
633
638
let field_ty_abi = & cx. layout_of ( field_ty) . unwrap ( ) . abi ;
634
639
if let Abi :: Scalar ( field_ty_scalar) = field_ty_abi {
635
640
match ( field_ty_scalar. valid_range . start ( ) , field_ty_scalar. valid_range . end ( ) ) {
636
- ( 0 , _) => bug ! ( "Non-null optimisation extended to a non-zero value." ) ,
641
+ ( 0 , _) => unreachable ! ( "Non-null optimisation extended to a non-zero value." ) ,
637
642
( 1 , _) => {
638
- return Some ( get_nullable_type ( cx. tcx , field_ty) ) ;
643
+ return Some ( get_nullable_type ( cx, field_ty) . unwrap ( ) ) ;
639
644
}
640
645
( start, end) => unreachable ! ( "Unhandled start and end range: ({}, {})" , start, end) ,
641
646
} ;
0 commit comments