11use std:: fmt:: Debug ;
2- use std:: iter;
2+ use std:: ops:: ControlFlow ;
3+ use std:: { cmp, iter} ;
34
45use hir:: def_id:: DefId ;
56use rustc_abi:: Integer :: { I8 , I32 } ;
@@ -18,12 +19,14 @@ use rustc_middle::ty::layout::{
1819} ;
1920use rustc_middle:: ty:: print:: with_no_trimmed_paths;
2021use rustc_middle:: ty:: {
21- self , AdtDef , CoroutineArgsExt , EarlyBinder , GenericArgsRef , Ty , TyCtxt , TypeVisitableExt ,
22+ self , AdtDef , CoroutineArgsExt , EarlyBinder , GenericArgsRef , ParamEnv , Ty , TyCtxt ,
23+ TypeVisitableExt ,
2224} ;
2325use rustc_session:: { DataTypeKind , FieldInfo , FieldKind , SizeKind , VariantInfo } ;
2426use rustc_span:: sym;
2527use rustc_span:: symbol:: Symbol ;
2628use rustc_target:: abi:: { FIRST_VARIANT , FieldIdx , Layout , VariantIdx } ;
29+ use rustc_type_ir:: DynKind ;
2730use tracing:: { debug, instrument, trace} ;
2831use { rustc_abi as abi, rustc_hir as hir} ;
2932
@@ -161,7 +164,7 @@ fn layout_of_uncached<'tcx>(
161164 } ;
162165 debug_assert ! ( !ty. has_non_region_infer( ) ) ;
163166
164- Ok ( match * ty. kind ( ) {
167+ let layout = match * ty. kind ( ) {
165168 ty:: Pat ( ty, pat) => {
166169 let layout = cx. layout_of ( ty) ?. layout ;
167170 let mut layout = LayoutS :: clone ( & layout. 0 ) ;
@@ -198,7 +201,6 @@ fn layout_of_uncached<'tcx>(
198201 }
199202 }
200203 }
201-
202204 // Basic scalars.
203205 ty:: Bool => tcx. mk_layout ( LayoutS :: scalar ( cx, Scalar :: Initialized {
204206 value : Int ( I8 , false ) ,
@@ -269,10 +271,32 @@ fn layout_of_uncached<'tcx>(
269271 return Ok ( tcx. mk_layout ( LayoutS :: scalar ( cx, data_ptr) ) ) ;
270272 }
271273
272- let Abi :: Scalar ( metadata) = metadata_layout. abi else {
274+ let Abi :: Scalar ( mut metadata) = metadata_layout. abi else {
273275 return Err ( error ( cx, LayoutError :: Unknown ( pointee) ) ) ;
274276 } ;
275277
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+
276300 metadata
277301 } else {
278302 let unsized_part = tcx. struct_tail_for_codegen ( pointee, param_env) ;
@@ -281,7 +305,28 @@ fn layout_of_uncached<'tcx>(
281305 ty:: Foreign ( ..) => {
282306 return Ok ( tcx. mk_layout ( LayoutS :: scalar ( cx, data_ptr) ) ) ;
283307 }
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+ }
285330 ty:: Dynamic ( ..) => {
286331 let mut vtable = scalar_unit ( Pointer ( AddressSpace :: DATA ) ) ;
287332 vtable. valid_range_mut ( ) . start = 1 ;
@@ -673,7 +718,157 @@ fn layout_of_uncached<'tcx>(
673718 ty:: Placeholder ( ..) | ty:: Param ( _) => {
674719 return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ;
675720 }
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 ,
677872}
678873
679874/// Overlap eligibility and variant assignment for each CoroutineSavedLocal.
0 commit comments