@@ -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};
@@ -556,25 +556,26 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
556
556
_ => false,
557
557
}
558
558
}
559
- /// Given a potentially non-null type `ty`, return its default, nullable type.
560
- fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
561
- match ty.kind {
559
+ /// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type.
560
+ /// If the type passed in was not scalar, returns None.
561
+ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
562
+ let tcx = cx.tcx;
563
+ Some(match ty.kind {
562
564
ty::Adt(field_def, field_substs) => {
563
- let field_variants = &field_def.variants;
564
- // We hit this case for #[repr(transparent)] structs with a single
565
- // field.
566
- debug_assert!(
567
- field_variants.len() == 1 && field_variants[VariantIdx::new(0)].fields.len() == 1,
568
- "inner ty not a newtype struct"
569
- );
570
- debug_assert!(field_def.repr.transparent(), "inner ty not transparent");
571
- // As it's easy to get this wrong, it's worth noting that
572
- // `inner_field_ty` is not the same as `field_ty`: Given Option<S>,
573
- // where S is a transparent newtype of some type T, `field_ty`
574
- // gives us S, while `inner_field_ty` is T.
575
- let inner_field_ty =
576
- field_def.variants[VariantIdx::new(0)].fields[0].ty(tcx, field_substs);
577
- get_nullable_type(tcx, inner_field_ty)
565
+ let inner_field_ty = {
566
+ let first_non_zst_ty =
567
+ field_def.variants.iter().filter_map(|v| v.transparent_newtype_field(tcx));
568
+ debug_assert_eq!(
569
+ first_non_zst_ty.clone().count(),
570
+ 1,
571
+ "Wrong number of fields for transparent type"
572
+ );
573
+ first_non_zst_ty
574
+ .last()
575
+ .expect("No non-zst fields in transparent type.")
576
+ .ty(tcx, field_substs)
577
+ };
578
+ return get_nullable_type(cx, inner_field_ty);
578
579
}
579
580
ty::Int(ty) => tcx.mk_mach_int(ty),
580
581
ty::Uint(ty) => tcx.mk_mach_uint(ty),
@@ -591,9 +592,13 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
591
592
// We should only ever reach this case if ty_is_known_nonnull is extended
592
593
// to other types.
593
594
ref unhandled => {
594
- unreachable!("Unhandled scalar kind: {:?} while checking {:?}", unhandled, ty)
595
+ debug!(
596
+ "get_nullable_type: Unhandled scalar kind: {:?} while checking {:?}",
597
+ unhandled, ty
598
+ );
599
+ return None;
595
600
}
596
- }
601
+ })
597
602
}
598
603
599
604
/// Check if this enum can be safely exported based on the "nullable pointer optimization". If it
@@ -643,9 +648,9 @@ crate fn repr_nullable_ptr<'tcx>(
643
648
let field_ty_abi = &cx.layout_of(field_ty).unwrap().abi;
644
649
if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
645
650
match (field_ty_scalar.valid_range.start(), field_ty_scalar.valid_range.end()) {
646
- (0, _) => bug !("Non-null optimisation extended to a non-zero value."),
651
+ (0, _) => unreachable !("Non-null optimisation extended to a non-zero value."),
647
652
(1, _) => {
648
- return Some(get_nullable_type(cx.tcx , field_ty));
653
+ return Some(get_nullable_type(cx, field_ty).unwrap( ));
649
654
}
650
655
(start, end) => unreachable!("Unhandled start and end range: ({}, {})", start, end),
651
656
};
0 commit comments