1
1
use std:: fmt:: Debug ;
2
- use std:: iter;
2
+ use std:: ops:: ControlFlow ;
3
+ use std:: { cmp, iter} ;
3
4
4
5
use hir:: def_id:: DefId ;
5
6
use rustc_hir as hir;
@@ -13,12 +14,14 @@ use rustc_middle::ty::layout::{
13
14
} ;
14
15
use rustc_middle:: ty:: print:: with_no_trimmed_paths;
15
16
use rustc_middle:: ty:: {
16
- self , AdtDef , CoroutineArgsExt , EarlyBinder , GenericArgsRef , Ty , TyCtxt , TypeVisitableExt ,
17
+ self , AdtDef , CoroutineArgsExt , EarlyBinder , GenericArgsRef , ParamEnv , Ty , TyCtxt ,
18
+ TypeVisitableExt ,
17
19
} ;
18
20
use rustc_session:: { DataTypeKind , FieldInfo , FieldKind , SizeKind , VariantInfo } ;
19
21
use rustc_span:: sym;
20
22
use rustc_span:: symbol:: Symbol ;
21
23
use rustc_target:: abi:: * ;
24
+ use rustc_type_ir:: DynKind ;
22
25
use tracing:: { debug, instrument, trace} ;
23
26
24
27
use crate :: errors:: {
@@ -155,7 +158,7 @@ fn layout_of_uncached<'tcx>(
155
158
} ;
156
159
debug_assert ! ( !ty. has_non_region_infer( ) ) ;
157
160
158
- Ok ( match * ty. kind ( ) {
161
+ let layout = match * ty. kind ( ) {
159
162
ty:: Pat ( ty, pat) => {
160
163
let layout = cx. layout_of ( ty) ?. layout ;
161
164
let mut layout = LayoutS :: clone ( & layout. 0 ) ;
@@ -192,7 +195,6 @@ fn layout_of_uncached<'tcx>(
192
195
}
193
196
}
194
197
}
195
-
196
198
// Basic scalars.
197
199
ty:: Bool => tcx. mk_layout ( LayoutS :: scalar ( cx, Scalar :: Initialized {
198
200
value : Int ( I8 , false ) ,
@@ -263,10 +265,32 @@ fn layout_of_uncached<'tcx>(
263
265
return Ok ( tcx. mk_layout ( LayoutS :: scalar ( cx, data_ptr) ) ) ;
264
266
}
265
267
266
- let Abi :: Scalar ( metadata) = metadata_layout. abi else {
268
+ let Abi :: Scalar ( mut metadata) = metadata_layout. abi else {
267
269
return Err ( error ( cx, LayoutError :: Unknown ( pointee) ) ) ;
268
270
} ;
269
271
272
+ if !ty. is_unsafe_ptr ( ) && metadata_ty == tcx. types . usize {
273
+ let tail = tcx. struct_tail_for_codegen ( pointee, param_env) ;
274
+ // // eprintln!("usize-meta {:?} {}", pointee, pointee_zst);
275
+ match tail. kind ( ) {
276
+ ty:: Slice ( element) => match ty_is_non_zst ( * element, param_env, tcx) {
277
+ NonZst :: True => {
278
+ metadata. valid_range_mut ( ) . end =
279
+ dl. ptr_sized_integer ( ) . signed_max ( ) as u128
280
+ }
281
+ NonZst :: Unknown => return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ,
282
+ _ => { }
283
+ } ,
284
+ ty:: Str => {
285
+ metadata. valid_range_mut ( ) . end =
286
+ dl. ptr_sized_integer ( ) . signed_max ( ) as u128 ;
287
+ }
288
+ _ => {
289
+ eprint ! ( "unexpected tail {:?}" , tail) ;
290
+ }
291
+ }
292
+ }
293
+
270
294
metadata
271
295
} else {
272
296
let unsized_part = tcx. struct_tail_for_codegen ( pointee, param_env) ;
@@ -275,7 +299,28 @@ fn layout_of_uncached<'tcx>(
275
299
ty:: Foreign ( ..) => {
276
300
return Ok ( tcx. mk_layout ( LayoutS :: scalar ( cx, data_ptr) ) ) ;
277
301
}
278
- ty:: Slice ( _) | ty:: Str => scalar_unit ( Int ( dl. ptr_sized_integer ( ) , false ) ) ,
302
+ ty:: Slice ( element) => {
303
+ let mut metadata = scalar_unit ( Int ( dl. ptr_sized_integer ( ) , false ) ) ;
304
+ if !ty. is_unsafe_ptr ( ) {
305
+ match ty_is_non_zst ( * element, param_env, tcx) {
306
+ NonZst :: True => {
307
+ metadata. valid_range_mut ( ) . end =
308
+ dl. ptr_sized_integer ( ) . signed_max ( ) as u128
309
+ }
310
+ NonZst :: Unknown => return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ,
311
+ _ => { }
312
+ }
313
+ }
314
+ metadata
315
+ }
316
+ ty:: Str => {
317
+ let mut metadata = scalar_unit ( Int ( dl. ptr_sized_integer ( ) , false ) ) ;
318
+ if !ty. is_unsafe_ptr ( ) {
319
+ metadata. valid_range_mut ( ) . end =
320
+ dl. ptr_sized_integer ( ) . signed_max ( ) as u128 ;
321
+ }
322
+ metadata
323
+ }
279
324
ty:: Dynamic ( ..) => {
280
325
let mut vtable = scalar_unit ( Pointer ( AddressSpace :: DATA ) ) ;
281
326
vtable. valid_range_mut ( ) . start = 1 ;
@@ -667,7 +712,157 @@ fn layout_of_uncached<'tcx>(
667
712
ty:: Placeholder ( ..) | ty:: Param ( _) => {
668
713
return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ;
669
714
}
670
- } )
715
+ } ;
716
+
717
+ #[ cfg( debug_assertions) ]
718
+ if layout. is_sized ( ) && !layout. abi . is_uninhabited ( ) {
719
+ match ( ty_is_non_zst ( ty, param_env, tcx) , layout. is_zst ( ) ) {
720
+ ( NonZst :: Unknown , _) => {
721
+ bug ! ( "ZSTness should not be unknown at this point {:?} {:?}" , ty, layout)
722
+ }
723
+ ( n @ ( NonZst :: False | NonZst :: Uninhabited ) , false ) => {
724
+ bug ! ( "{:?} is not a ZST but ty_is_non_zst() thinks it is NonZst::{:?}" , ty, n)
725
+ }
726
+ ( NonZst :: True , true ) => bug ! ( "{:?} is a ZST but ty_is_non_zst() thinks it isn't" , ty) ,
727
+ _ => { }
728
+ }
729
+ }
730
+
731
+ Ok ( layout)
732
+ }
733
+
734
+ fn ty_is_non_zst < ' tcx > ( ty : Ty < ' tcx > , param_env : ParamEnv < ' tcx > , tcx : TyCtxt < ' tcx > ) -> NonZst {
735
+ fn fold_fields < ' tcx > (
736
+ mut it : impl Iterator < Item = Ty < ' tcx > > ,
737
+ param_env : ParamEnv < ' tcx > ,
738
+ tcx : TyCtxt < ' tcx > ,
739
+ ) -> NonZst {
740
+ let ( ControlFlow :: Break ( res) | ControlFlow :: Continue ( res) ) =
741
+ it. try_fold ( NonZst :: False , |acc, ty| {
742
+ if acc == NonZst :: True {
743
+ return ControlFlow :: Break ( acc) ;
744
+ }
745
+
746
+ ControlFlow :: Continue ( cmp:: max ( acc, ty_is_non_zst ( ty, param_env, tcx) ) )
747
+ } ) ;
748
+
749
+ res
750
+ }
751
+
752
+ match ty. kind ( ) {
753
+ ty:: Infer ( ty:: IntVar ( _) | ty:: FloatVar ( _) )
754
+ | ty:: Uint ( _)
755
+ | ty:: Int ( _)
756
+ | ty:: Bool
757
+ | ty:: Float ( _)
758
+ | ty:: FnPtr ( _, _)
759
+ | ty:: RawPtr ( ..)
760
+ | ty:: Dynamic ( _, _, DynKind :: DynStar )
761
+ | ty:: Char
762
+ | ty:: Ref ( ..) => NonZst :: True ,
763
+
764
+ ty:: Pat ( ty, _) => ty_is_non_zst ( * ty, param_env, tcx) ,
765
+ ty:: Closure ( _, args) => fold_fields ( args. as_closure ( ) . upvar_tys ( ) . iter ( ) , param_env, tcx) ,
766
+ ty:: Coroutine ( _, _) => NonZst :: True ,
767
+ ty:: CoroutineClosure ( _, args) => {
768
+ fold_fields ( args. as_coroutine_closure ( ) . upvar_tys ( ) . iter ( ) , param_env, tcx)
769
+ }
770
+ ty:: Array ( ty, len) => {
771
+ let len = if len. has_aliases ( ) {
772
+ tcx. normalize_erasing_regions ( param_env, * len)
773
+ } else {
774
+ * len
775
+ } ;
776
+
777
+ if let Some ( len) = len. try_to_target_usize ( tcx) {
778
+ if len == 0 {
779
+ return NonZst :: False ;
780
+ }
781
+ let element_zst = ty_is_non_zst ( * ty, param_env, tcx) ;
782
+ if element_zst != NonZst :: Unknown {
783
+ return element_zst;
784
+ }
785
+ }
786
+ NonZst :: Unknown
787
+ }
788
+ ty:: Tuple ( tys) => fold_fields ( tys. iter ( ) , param_env, tcx) ,
789
+ ty:: Adt ( def, args) => {
790
+ if ty. is_enum ( ) {
791
+ // repr(C) enums can never be ZSTs or uninhabited.
792
+ // They must have at least one variant and even if the variant has a payload that is uninhabited,
793
+ // the tag is still there.
794
+ if def. repr ( ) . c ( ) {
795
+ return NonZst :: True ;
796
+ }
797
+
798
+ if def. variants ( ) . len ( ) == 0 {
799
+ return NonZst :: Uninhabited ;
800
+ }
801
+ // An enum is !ZST if
802
+ // * it has a repr(int) and at least one non-uninhabited variant
803
+ // * it has at least one variant with a !ZST payload
804
+ // * it has multiple variants that are not uninhabited
805
+
806
+ let min_empty_variants = if def. repr ( ) . inhibit_enum_layout_opt ( ) { 1 } else { 2 } ;
807
+
808
+ // first check without recursing
809
+ let simple_variants = def. variants ( ) . iter ( ) . filter ( |v| v. fields . len ( ) == 0 ) . count ( ) ;
810
+ if simple_variants >= min_empty_variants {
811
+ return NonZst :: True ;
812
+ }
813
+
814
+ let mut inhabited_zst_variants = 0 ;
815
+ let mut unknown = false ;
816
+
817
+ for variant in def. variants ( ) . iter ( ) . filter ( |v| v. fields . len ( ) != 0 ) {
818
+ let variant_sized =
819
+ fold_fields ( variant. fields . iter ( ) . map ( |f| f. ty ( tcx, args) ) , param_env, tcx) ;
820
+
821
+ match variant_sized {
822
+ // enum E { A(!, u32) } counts as !ZST for our purposes
823
+ NonZst :: True => return NonZst :: True ,
824
+ NonZst :: False => inhabited_zst_variants += 1 ,
825
+ NonZst :: Unknown => unknown = true ,
826
+ NonZst :: Uninhabited => { }
827
+ }
828
+ }
829
+
830
+ if simple_variants + inhabited_zst_variants >= min_empty_variants {
831
+ return NonZst :: True ;
832
+ }
833
+ if unknown {
834
+ return NonZst :: Unknown ;
835
+ }
836
+ if simple_variants + inhabited_zst_variants == 0 {
837
+ return NonZst :: Uninhabited ;
838
+ }
839
+
840
+ NonZst :: False
841
+ } else {
842
+ fold_fields ( def. all_fields ( ) . map ( |f| f. ty ( tcx, args) ) , param_env, tcx)
843
+ }
844
+ }
845
+ ty:: FnDef ( ..) => NonZst :: False ,
846
+ ty:: Never => NonZst :: Uninhabited ,
847
+ ty:: Param ( ..) => NonZst :: Unknown ,
848
+ ty:: Str => NonZst :: True ,
849
+ // treat unsized types as potentially-ZST
850
+ ty:: Dynamic ( ..) | ty:: Slice ( ..) => NonZst :: False ,
851
+ ty:: Alias ( ..) => match tcx. try_normalize_erasing_regions ( param_env, ty) {
852
+ Ok ( ty) if !matches ! ( ty. kind( ) , ty:: Alias ( ..) ) => ty_is_non_zst ( ty, param_env, tcx) ,
853
+ _ => NonZst :: Unknown ,
854
+ } ,
855
+ ty:: Error ( _) => NonZst :: Unknown ,
856
+ _ => bug ! ( "is_non_zst not implemented for this kind {:?}" , ty) ,
857
+ }
858
+ }
859
+
860
+ #[ derive( Clone , Copy , PartialEq , Eq , Debug , PartialOrd , Ord ) ]
861
+ enum NonZst {
862
+ False ,
863
+ Uninhabited ,
864
+ Unknown ,
865
+ True ,
671
866
}
672
867
673
868
/// Overlap eligibility and variant assignment for each CoroutineSavedLocal.
0 commit comments