55use core:: ops:: ControlFlow ;
66use itertools:: Itertools ;
77use rustc_ast:: ast:: Mutability ;
8- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
8+ use rustc_data_structures:: fx:: FxHashSet ;
99use rustc_hir as hir;
1010use rustc_hir:: def:: { CtorKind , CtorOf , DefKind , Res } ;
1111use rustc_hir:: def_id:: DefId ;
@@ -16,7 +16,7 @@ use rustc_lint::LateContext;
1616use rustc_middle:: mir:: interpret:: Scalar ;
1717use rustc_middle:: mir:: ConstValue ;
1818use rustc_middle:: traits:: EvaluationResult ;
19- use rustc_middle:: ty:: layout:: ValidityRequirement ;
19+ use rustc_middle:: ty:: layout:: { LayoutOf , ValidityRequirement } ;
2020use rustc_middle:: ty:: {
2121 self , AdtDef , AliasTy , AssocKind , Binder , BoundRegion , FnSig , GenericArg , GenericArgKind , GenericArgsRef ,
2222 GenericParamDefKind , IntTy , List , ParamEnv , Region , RegionKind , ToPredicate , TraitRef , Ty , TyCtxt ,
@@ -361,50 +361,6 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
361361 }
362362}
363363
364- // FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize
365- // this function can be removed once the `normalize` method does not panic when normalization does
366- // not succeed
367- /// Checks if `Ty` is normalizable. This function is useful
368- /// to avoid crashes on `layout_of`.
369- pub fn is_normalizable < ' tcx > ( cx : & LateContext < ' tcx > , param_env : ParamEnv < ' tcx > , ty : Ty < ' tcx > ) -> bool {
370- is_normalizable_helper ( cx, param_env, ty, & mut FxHashMap :: default ( ) )
371- }
372-
373- fn is_normalizable_helper < ' tcx > (
374- cx : & LateContext < ' tcx > ,
375- param_env : ParamEnv < ' tcx > ,
376- ty : Ty < ' tcx > ,
377- cache : & mut FxHashMap < Ty < ' tcx > , bool > ,
378- ) -> bool {
379- if let Some ( & cached_result) = cache. get ( & ty) {
380- return cached_result;
381- }
382- // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
383- cache. insert ( ty, false ) ;
384- let infcx = cx. tcx . infer_ctxt ( ) . build ( ) ;
385- let cause = ObligationCause :: dummy ( ) ;
386- let result = if infcx. at ( & cause, param_env) . query_normalize ( ty) . is_ok ( ) {
387- match ty. kind ( ) {
388- ty:: Adt ( def, args) => def. variants ( ) . iter ( ) . all ( |variant| {
389- variant
390- . fields
391- . iter ( )
392- . all ( |field| is_normalizable_helper ( cx, param_env, field. ty ( cx. tcx , args) , cache) )
393- } ) ,
394- _ => ty. walk ( ) . all ( |generic_arg| match generic_arg. unpack ( ) {
395- GenericArgKind :: Type ( inner_ty) if inner_ty != ty => {
396- is_normalizable_helper ( cx, param_env, inner_ty, cache)
397- } ,
398- _ => true , // if inner_ty == ty, we've already checked it
399- } ) ,
400- }
401- } else {
402- false
403- } ;
404- cache. insert ( ty, result) ;
405- result
406- }
407-
408364/// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any
409365/// integer or floating-point number type). For checking aggregation of primitive types (e.g.
410366/// tuples and slices of primitive type) see `is_recursively_primitive_type`
@@ -1013,10 +969,6 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
1013969/// Comes up with an "at least" guesstimate for the type's size, not taking into
1014970/// account the layout of type parameters.
1015971pub fn approx_ty_size < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> u64 {
1016- use rustc_middle:: ty:: layout:: LayoutOf ;
1017- if !is_normalizable ( cx, cx. param_env , ty) {
1018- return 0 ;
1019- }
1020972 match ( cx. layout_of ( ty) . map ( |layout| layout. size . bytes ( ) ) , ty. kind ( ) ) {
1021973 ( Ok ( size) , _) => size,
1022974 ( Err ( _) , ty:: Tuple ( list) ) => list. iter ( ) . map ( |t| approx_ty_size ( cx, t) ) . sum ( ) ,
@@ -1290,3 +1242,113 @@ pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>
12901242pub fn is_manually_drop ( ty : Ty < ' _ > ) -> bool {
12911243 ty. ty_adt_def ( ) . map_or ( false , AdtDef :: is_manually_drop)
12921244}
1245+
1246+ #[ derive( Clone , Copy ) ]
1247+ pub enum Sizedness {
1248+ /// The type is uninhabited. (e.g. `!`)
1249+ Uninhabited ,
1250+ /// The type is zero-sized.
1251+ Zero ,
1252+ /// The type has some other size or an unknown size.
1253+ Other ,
1254+ }
1255+ impl Sizedness {
1256+ pub fn is_zero ( self ) -> bool {
1257+ matches ! ( self , Self :: Zero )
1258+ }
1259+
1260+ pub fn is_uninhabited ( self ) -> bool {
1261+ matches ! ( self , Self :: Uninhabited )
1262+ }
1263+ }
1264+
1265+ /// Calculates the sizedness of a type.
1266+ pub fn sizedness_of < ' tcx > ( tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > , ty : Ty < ' tcx > ) -> Sizedness {
1267+ fn for_list < ' tcx > (
1268+ tcx : TyCtxt < ' tcx > ,
1269+ param_env : ParamEnv < ' tcx > ,
1270+ tys : impl IntoIterator < Item = Ty < ' tcx > > ,
1271+ ) -> Sizedness {
1272+ let mut res = Sizedness :: Zero ;
1273+ for ty in tys {
1274+ match sizedness_of ( tcx, param_env, ty) {
1275+ Sizedness :: Uninhabited => return Sizedness :: Uninhabited ,
1276+ Sizedness :: Other => res = Sizedness :: Other ,
1277+ Sizedness :: Zero => { } ,
1278+ }
1279+ }
1280+ res
1281+ }
1282+
1283+ match * ty. kind ( ) {
1284+ ty:: FnDef ( ..) => Sizedness :: Zero ,
1285+ ty:: Tuple ( tys) => for_list ( tcx, param_env, tys) ,
1286+ ty:: Array ( _, len) if len. try_eval_target_usize ( tcx, param_env) . is_some_and ( |x| x == 0 ) => Sizedness :: Zero ,
1287+ ty:: Array ( ty, _) => sizedness_of ( tcx, param_env, ty) ,
1288+ ty:: Adt ( adt, args) => {
1289+ let mut iter = adt
1290+ . variants ( )
1291+ . iter ( )
1292+ . map ( |v| for_list ( tcx, param_env, v. fields . iter ( ) . map ( |f| f. ty ( tcx, args) ) ) )
1293+ . filter ( |x| !x. is_uninhabited ( ) ) ;
1294+ match iter. next ( ) {
1295+ None => Sizedness :: Uninhabited ,
1296+ Some ( Sizedness :: Other ) => Sizedness :: Other ,
1297+ Some ( _) => {
1298+ if iter. next ( ) . is_some ( ) {
1299+ Sizedness :: Other
1300+ } else {
1301+ Sizedness :: Zero
1302+ }
1303+ } ,
1304+ }
1305+ } ,
1306+ ty:: Closure ( _, args) => for_list ( tcx, param_env, args. as_closure ( ) . upvar_tys ( ) . iter ( ) ) ,
1307+ ty:: Coroutine ( id, args) => {
1308+ if for_list ( tcx, param_env, args. as_coroutine ( ) . upvar_tys ( ) . iter ( ) ) . is_uninhabited ( ) {
1309+ Sizedness :: Uninhabited
1310+ } else {
1311+ Sizedness :: Other
1312+ }
1313+ } ,
1314+ ty:: CoroutineClosure ( _, args) => {
1315+ if for_list ( tcx, param_env, args. as_coroutine_closure ( ) . upvar_tys ( ) . iter ( ) ) . is_uninhabited ( ) {
1316+ Sizedness :: Uninhabited
1317+ } else {
1318+ Sizedness :: Other
1319+ }
1320+ } ,
1321+ ty:: CoroutineWitness ( _, args) => for_list ( tcx, param_env, args. iter ( ) . filter_map ( GenericArg :: as_type) ) ,
1322+ ty:: Alias ( ..) => {
1323+ if let Ok ( normalized) = tcx
1324+ . infer_ctxt ( )
1325+ . build ( )
1326+ . at ( & ObligationCause :: dummy ( ) , param_env)
1327+ . query_normalize ( ty)
1328+ && normalized. value != ty
1329+ {
1330+ sizedness_of ( tcx, param_env, normalized. value )
1331+ } else {
1332+ Sizedness :: Other
1333+ }
1334+ } ,
1335+ ty:: Never => Sizedness :: Uninhabited ,
1336+ ty:: Bool
1337+ | ty:: Char
1338+ | ty:: Int ( _)
1339+ | ty:: Uint ( _)
1340+ | ty:: Float ( _)
1341+ | ty:: RawPtr ( ..)
1342+ | ty:: Ref ( ..)
1343+ | ty:: FnPtr ( ..)
1344+ | ty:: Param ( _)
1345+ | ty:: Bound ( ..)
1346+ | ty:: Placeholder ( _)
1347+ | ty:: Infer ( _)
1348+ | ty:: Error ( _)
1349+ | ty:: Dynamic ( ..)
1350+ | ty:: Slice ( ..)
1351+ | ty:: Str
1352+ | ty:: Foreign ( _) => Sizedness :: Other ,
1353+ }
1354+ }
0 commit comments