@@ -36,31 +36,39 @@ struct Replacer<'a, 'tcx> {
36
36
}
37
37
38
38
/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
39
- fn maybe_zst ( ty : Ty < ' _ > ) -> bool {
39
+ ///
40
+ /// `Some(true)` is definitely ZST; `Some(false)` is definitely *not* ZST.
41
+ ///
42
+ /// `None` may or may not be, and must check `layout_of` to be sure.
43
+ fn trivially_zst < ' tcx > ( ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> Option < bool > {
40
44
match ty. kind ( ) {
41
- // maybe ZST (could be more precise)
42
- ty:: Adt ( ..)
43
- | ty:: Array ( ..)
44
- | ty:: Closure ( ..)
45
- | ty:: CoroutineClosure ( ..)
46
- | ty:: Tuple ( ..)
47
- | ty:: Alias ( ty:: Opaque , ..) => true ,
48
45
// definitely ZST
49
- ty:: FnDef ( ..) | ty:: Never => true ,
50
- // unreachable or can't be ZST
51
- _ => false ,
46
+ ty:: FnDef ( ..) | ty:: Never => Some ( true ) ,
47
+ ty:: Tuple ( fields) if fields. is_empty ( ) => Some ( true ) ,
48
+ ty:: Array ( _ty, len) if let Some ( 0 ) = len. try_to_target_usize ( tcx) => Some ( true ) ,
49
+ // clearly not ZST
50
+ ty:: Bool
51
+ | ty:: Char
52
+ | ty:: Int ( ..)
53
+ | ty:: Uint ( ..)
54
+ | ty:: Float ( ..)
55
+ | ty:: RawPtr ( ..)
56
+ | ty:: Ref ( ..)
57
+ | ty:: FnPtr ( ..) => Some ( false ) ,
58
+ // check `layout_of` to see (including unreachable things we won't actually see)
59
+ _ => None ,
52
60
}
53
61
}
54
62
55
63
impl < ' tcx > Replacer < ' _ , ' tcx > {
56
64
fn known_to_be_zst ( & self , ty : Ty < ' tcx > ) -> bool {
57
- if !maybe_zst ( ty) {
58
- return false ;
65
+ if let Some ( is_zst) = trivially_zst ( ty, self . tcx ) {
66
+ is_zst
67
+ } else {
68
+ self . tcx
69
+ . layout_of ( self . typing_env . as_query_input ( ty) )
70
+ . is_ok_and ( |layout| layout. is_zst ( ) )
59
71
}
60
- let Ok ( layout) = self . tcx . layout_of ( self . typing_env . as_query_input ( ty) ) else {
61
- return false ;
62
- } ;
63
- layout. is_zst ( )
64
72
}
65
73
66
74
fn make_zst ( & self , ty : Ty < ' tcx > ) -> ConstOperand < ' tcx > {
0 commit comments