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