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