3
3
use rustc_errors:: struct_span_err;
4
4
use rustc_hir:: lang_items;
5
5
use rustc_hir:: { def_id:: DefId , HirId } ;
6
- use rustc_index:: bit_set:: BitSet ;
7
6
use rustc_infer:: infer:: TyCtxtInferExt ;
8
7
use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
9
8
use rustc_middle:: mir:: * ;
@@ -28,70 +27,100 @@ use crate::dataflow::{self, Analysis};
28
27
// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
29
28
// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
30
29
// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
31
- pub type IndirectlyMutableResults < ' mir , ' tcx > =
30
+ type IndirectlyMutableResults < ' mir , ' tcx > =
32
31
dataflow:: ResultsCursor < ' mir , ' tcx , MaybeMutBorrowedLocals < ' mir , ' tcx > > ;
33
32
34
- struct QualifCursor < ' a , ' mir , ' tcx , Q : Qualif > {
35
- cursor : dataflow:: ResultsCursor < ' mir , ' tcx , FlowSensitiveAnalysis < ' a , ' mir , ' tcx , Q > > ,
36
- in_any_value_of_ty : BitSet < Local > ,
37
- }
38
-
39
- impl < Q : Qualif > QualifCursor < ' a , ' mir , ' tcx , Q > {
40
- pub fn new ( q : Q , ccx : & ' a ConstCx < ' mir , ' tcx > ) -> Self {
41
- let cursor = FlowSensitiveAnalysis :: new ( q, ccx)
42
- . into_engine ( ccx. tcx , ccx. body , ccx. def_id )
43
- . iterate_to_fixpoint ( )
44
- . into_results_cursor ( ccx. body ) ;
45
-
46
- let mut in_any_value_of_ty = BitSet :: new_empty ( ccx. body . local_decls . len ( ) ) ;
47
- for ( local, decl) in ccx. body . local_decls . iter_enumerated ( ) {
48
- if Q :: in_any_value_of_ty ( ccx, decl. ty ) {
49
- in_any_value_of_ty. insert ( local) ;
50
- }
51
- }
33
+ type QualifResults < ' mir , ' tcx , Q > =
34
+ dataflow:: ResultsCursor < ' mir , ' tcx , FlowSensitiveAnalysis < ' mir , ' mir , ' tcx , Q > > ;
52
35
53
- QualifCursor { cursor, in_any_value_of_ty }
54
- }
36
+ #[ derive( Default ) ]
37
+ pub struct Qualifs < ' mir , ' tcx > {
38
+ has_mut_interior : Option < QualifResults < ' mir , ' tcx , HasMutInterior > > ,
39
+ needs_drop : Option < QualifResults < ' mir , ' tcx , NeedsDrop > > ,
40
+ indirectly_mutable : Option < IndirectlyMutableResults < ' mir , ' tcx > > ,
55
41
}
56
42
57
- pub struct Qualifs < ' a , ' mir , ' tcx > {
58
- has_mut_interior : QualifCursor < ' a , ' mir , ' tcx , HasMutInterior > ,
59
- needs_drop : QualifCursor < ' a , ' mir , ' tcx , NeedsDrop > ,
60
- indirectly_mutable : IndirectlyMutableResults < ' mir , ' tcx > ,
61
- }
62
-
63
- impl Qualifs < ' a , ' mir , ' tcx > {
64
- fn indirectly_mutable ( & mut self , local : Local , location : Location ) -> bool {
65
- self . indirectly_mutable . seek_before ( location) ;
66
- self . indirectly_mutable . get ( ) . contains ( local)
43
+ impl Qualifs < ' mir , ' tcx > {
44
+ fn indirectly_mutable (
45
+ & mut self ,
46
+ ccx : & ' mir ConstCx < ' mir , ' tcx > ,
47
+ local : Local ,
48
+ location : Location ,
49
+ ) -> bool {
50
+ let indirectly_mutable = self . indirectly_mutable . get_or_insert_with ( || {
51
+ let ConstCx { tcx, body, def_id, param_env, .. } = * ccx;
52
+
53
+ // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
54
+ // allowed in a const.
55
+ //
56
+ // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
57
+ // without breaking stable code?
58
+ MaybeMutBorrowedLocals :: mut_borrows_only ( tcx, & body, param_env)
59
+ . unsound_ignore_borrow_on_drop ( )
60
+ . into_engine ( tcx, & body, def_id)
61
+ . iterate_to_fixpoint ( )
62
+ . into_results_cursor ( & body)
63
+ } ) ;
64
+
65
+ indirectly_mutable. seek_before ( location) ;
66
+ indirectly_mutable. get ( ) . contains ( local)
67
67
}
68
68
69
69
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
70
70
///
71
71
/// Only updates the cursor if absolutely necessary
72
- fn needs_drop ( & mut self , local : Local , location : Location ) -> bool {
73
- if !self . needs_drop . in_any_value_of_ty . contains ( local) {
72
+ fn needs_drop (
73
+ & mut self ,
74
+ ccx : & ' mir ConstCx < ' mir , ' tcx > ,
75
+ local : Local ,
76
+ location : Location ,
77
+ ) -> bool {
78
+ let ty = ccx. body . local_decls [ local] . ty ;
79
+ if !NeedsDrop :: in_any_value_of_ty ( ccx, ty) {
74
80
return false ;
75
81
}
76
82
77
- self . needs_drop . cursor . seek_before ( location) ;
78
- self . needs_drop . cursor . get ( ) . contains ( local) || self . indirectly_mutable ( local, location)
83
+ let needs_drop = self . needs_drop . get_or_insert_with ( || {
84
+ let ConstCx { tcx, body, def_id, .. } = * ccx;
85
+
86
+ FlowSensitiveAnalysis :: new ( NeedsDrop , ccx)
87
+ . into_engine ( tcx, & body, def_id)
88
+ . iterate_to_fixpoint ( )
89
+ . into_results_cursor ( & body)
90
+ } ) ;
91
+
92
+ needs_drop. seek_before ( location) ;
93
+ needs_drop. get ( ) . contains ( local) || self . indirectly_mutable ( ccx, local, location)
79
94
}
80
95
81
96
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
82
97
///
83
98
/// Only updates the cursor if absolutely necessary.
84
- fn has_mut_interior ( & mut self , local : Local , location : Location ) -> bool {
85
- if !self . has_mut_interior . in_any_value_of_ty . contains ( local) {
99
+ fn has_mut_interior (
100
+ & mut self ,
101
+ ccx : & ' mir ConstCx < ' mir , ' tcx > ,
102
+ local : Local ,
103
+ location : Location ,
104
+ ) -> bool {
105
+ let ty = ccx. body . local_decls [ local] . ty ;
106
+ if !HasMutInterior :: in_any_value_of_ty ( ccx, ty) {
86
107
return false ;
87
108
}
88
109
89
- self . has_mut_interior . cursor . seek_before ( location) ;
90
- self . has_mut_interior . cursor . get ( ) . contains ( local)
91
- || self . indirectly_mutable ( local, location)
110
+ let has_mut_interior = self . has_mut_interior . get_or_insert_with ( || {
111
+ let ConstCx { tcx, body, def_id, .. } = * ccx;
112
+
113
+ FlowSensitiveAnalysis :: new ( HasMutInterior , ccx)
114
+ . into_engine ( tcx, & body, def_id)
115
+ . iterate_to_fixpoint ( )
116
+ . into_results_cursor ( & body)
117
+ } ) ;
118
+
119
+ has_mut_interior. seek_before ( location) ;
120
+ has_mut_interior. get ( ) . contains ( local) || self . indirectly_mutable ( ccx, local, location)
92
121
}
93
122
94
- fn in_return_place ( & mut self , ccx : & ConstCx < ' _ , ' tcx > ) -> ConstQualifs {
123
+ fn in_return_place ( & mut self , ccx : & ' mir ConstCx < ' mir , ' tcx > ) -> ConstQualifs {
95
124
// Find the `Return` terminator if one exists.
96
125
//
97
126
// If no `Return` terminator exists, this MIR is divergent. Just return the conservative
@@ -114,49 +143,31 @@ impl Qualifs<'a, 'mir, 'tcx> {
114
143
let return_loc = ccx. body . terminator_loc ( return_block) ;
115
144
116
145
ConstQualifs {
117
- needs_drop : self . needs_drop ( RETURN_PLACE , return_loc) ,
118
- has_mut_interior : self . has_mut_interior ( RETURN_PLACE , return_loc) ,
146
+ needs_drop : self . needs_drop ( ccx , RETURN_PLACE , return_loc) ,
147
+ has_mut_interior : self . has_mut_interior ( ccx , RETURN_PLACE , return_loc) ,
119
148
}
120
149
}
121
150
}
122
151
123
- pub struct Validator < ' a , ' mir , ' tcx > {
124
- ccx : & ' a ConstCx < ' mir , ' tcx > ,
125
- qualifs : Qualifs < ' a , ' mir , ' tcx > ,
152
+ pub struct Validator < ' mir , ' tcx > {
153
+ ccx : & ' mir ConstCx < ' mir , ' tcx > ,
154
+ qualifs : Qualifs < ' mir , ' tcx > ,
126
155
127
156
/// The span of the current statement.
128
157
span : Span ,
129
158
}
130
159
131
- impl Deref for Validator < ' _ , ' mir , ' tcx > {
160
+ impl Deref for Validator < ' mir , ' tcx > {
132
161
type Target = ConstCx < ' mir , ' tcx > ;
133
162
134
163
fn deref ( & self ) -> & Self :: Target {
135
164
& self . ccx
136
165
}
137
166
}
138
167
139
- impl Validator < ' a , ' mir , ' tcx > {
140
- pub fn new ( ccx : & ' a ConstCx < ' mir , ' tcx > ) -> Self {
141
- let ConstCx { tcx, body, def_id, param_env, .. } = * ccx;
142
-
143
- let needs_drop = QualifCursor :: new ( NeedsDrop , ccx) ;
144
- let has_mut_interior = QualifCursor :: new ( HasMutInterior , ccx) ;
145
-
146
- // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
147
- // allowed in a const.
148
- //
149
- // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
150
- // without breaking stable code?
151
- let indirectly_mutable = MaybeMutBorrowedLocals :: mut_borrows_only ( tcx, body, param_env)
152
- . unsound_ignore_borrow_on_drop ( )
153
- . into_engine ( tcx, body, def_id)
154
- . iterate_to_fixpoint ( )
155
- . into_results_cursor ( body) ;
156
-
157
- let qualifs = Qualifs { needs_drop, has_mut_interior, indirectly_mutable } ;
158
-
159
- Validator { span : ccx. body . span , ccx, qualifs }
168
+ impl Validator < ' mir , ' tcx > {
169
+ pub fn new ( ccx : & ' mir ConstCx < ' mir , ' tcx > ) -> Self {
170
+ Validator { span : ccx. body . span , ccx, qualifs : Default :: default ( ) }
160
171
}
161
172
162
173
pub fn check_body ( & mut self ) {
@@ -239,7 +250,7 @@ impl Validator<'a, 'mir, 'tcx> {
239
250
}
240
251
}
241
252
242
- impl Visitor < ' tcx > for Validator < ' _ , ' mir , ' tcx > {
253
+ impl Visitor < ' tcx > for Validator < ' mir , ' tcx > {
243
254
fn visit_basic_block_data ( & mut self , bb : BasicBlock , block : & BasicBlockData < ' tcx > ) {
244
255
trace ! ( "visit_basic_block_data: bb={:?} is_cleanup={:?}" , bb, block. is_cleanup) ;
245
256
@@ -345,7 +356,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
345
356
| Rvalue :: AddressOf ( Mutability :: Not , ref place) => {
346
357
let borrowed_place_has_mut_interior = qualifs:: in_place :: < HasMutInterior , _ > (
347
358
& self . ccx ,
348
- & mut |local| self . qualifs . has_mut_interior ( local, location) ,
359
+ & mut |local| self . qualifs . has_mut_interior ( self . ccx , local, location) ,
349
360
place. as_ref ( ) ,
350
361
) ;
351
362
@@ -571,7 +582,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
571
582
let needs_drop = if let Some ( local) = dropped_place. as_local ( ) {
572
583
// Use the span where the local was declared as the span of the drop error.
573
584
err_span = self . body . local_decls [ local] . source_info . span ;
574
- self . qualifs . needs_drop ( local, location)
585
+ self . qualifs . needs_drop ( self . ccx , local, location)
575
586
} else {
576
587
true
577
588
} ;
0 commit comments