@@ -15,6 +15,9 @@ use middle::def;
15
15
use middle:: ty;
16
16
use middle:: typeck:: MethodCall ;
17
17
use util:: ppaux;
18
+ use util:: nodemap:: NodeSet ;
19
+ use euv = middle:: expr_use_visitor;
20
+ use mc = middle:: mem_categorization;
18
21
19
22
use syntax:: ast;
20
23
use syntax:: ast_util:: PostExpansionMethod ;
@@ -40,10 +43,18 @@ fn type_is_unsafe_function(ty: ty::t) -> bool {
40
43
struct EffectCheckVisitor < ' a > {
41
44
tcx : & ' a ty:: ctxt ,
42
45
46
+ mutably_accessed_statics : & ' a mut NodeSet ,
47
+
43
48
/// Whether we're in an unsafe context.
44
49
unsafe_context : UnsafeContext ,
45
50
}
46
51
52
+ struct FunctionVisitor < ' a , ' b > ( euv:: ExprUseVisitor < ' a , ' b , ty:: ctxt > ) ;
53
+
54
+ struct StaticMutChecker < ' a > {
55
+ mutably_accessed_statics : NodeSet ,
56
+ }
57
+
47
58
impl < ' a > EffectCheckVisitor < ' a > {
48
59
fn require_unsafe ( & mut self , span : Span , description : & str ) {
49
60
match self . unsafe_context {
@@ -142,6 +153,10 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> {
142
153
}
143
154
144
155
fn visit_expr ( & mut self , expr : & ast:: Expr , _: ( ) ) {
156
+ if self . mutably_accessed_statics . remove ( & expr. id ) {
157
+ self . require_unsafe ( expr. span , "mutable use of static" )
158
+ }
159
+
145
160
match expr. node {
146
161
ast:: ExprMethodCall ( _, _, _) => {
147
162
let method_call = MethodCall :: expr ( expr. id ) ;
@@ -185,7 +200,12 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> {
185
200
ast:: ExprPath ( ..) => {
186
201
match ty:: resolve_expr ( self . tcx , expr) {
187
202
def:: DefStatic ( _, true ) => {
188
- self . require_unsafe ( expr. span , "use of mutable static" )
203
+ let ty = ty:: node_id_to_type ( self . tcx , expr. id ) ;
204
+ let contents = ty:: type_contents ( self . tcx , ty) ;
205
+ if !contents. is_sharable ( self . tcx ) {
206
+ self . require_unsafe ( expr. span ,
207
+ "use of non-Share static mut" )
208
+ }
189
209
}
190
210
_ => { }
191
211
}
@@ -197,11 +217,98 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> {
197
217
}
198
218
}
199
219
220
+ impl < ' a , ' b > Visitor < ( ) > for FunctionVisitor < ' a , ' b > {
221
+ fn visit_fn ( & mut self , fk : & visit:: FnKind , fd : & ast:: FnDecl ,
222
+ b : & ast:: Block , s : Span , _: ast:: NodeId , _: ( ) ) {
223
+ {
224
+ let FunctionVisitor ( ref mut inner) = * self ;
225
+ inner. walk_fn ( fd, b) ;
226
+ }
227
+ visit:: walk_fn ( self , fk, fd, b, s, ( ) ) ;
228
+ }
229
+ }
230
+
231
+ impl < ' a > StaticMutChecker < ' a > {
232
+ fn is_static_mut ( & self , mut cur : & mc:: cmt ) -> bool {
233
+ loop {
234
+ match cur. cat {
235
+ mc:: cat_static_item => {
236
+ return match cur. mutbl {
237
+ mc:: McImmutable => return false ,
238
+ _ => true
239
+ }
240
+ }
241
+ mc:: cat_deref( ref cmt, _, _) |
242
+ mc:: cat_discr( ref cmt, _) |
243
+ mc:: cat_downcast( ref cmt) |
244
+ mc:: cat_interior( ref cmt, _) => cur = cmt,
245
+
246
+ mc:: cat_rvalue( ..) |
247
+ mc:: cat_copied_upvar( ..) |
248
+ mc:: cat_upvar( ..) |
249
+ mc:: cat_local( ..) |
250
+ mc:: cat_arg( ..) => return false
251
+ }
252
+ }
253
+ }
254
+ }
255
+
256
+ impl < ' a > euv:: Delegate for StaticMutChecker < ' a > {
257
+ fn borrow ( & mut self ,
258
+ borrow_id : ast:: NodeId ,
259
+ _borrow_span : Span ,
260
+ cmt : mc:: cmt ,
261
+ _loan_region : ty:: Region ,
262
+ bk : ty:: BorrowKind ,
263
+ _loan_cause : euv:: LoanCause ) {
264
+ if !self . is_static_mut ( & cmt) {
265
+ return
266
+ }
267
+ match bk {
268
+ ty:: ImmBorrow => { }
269
+ ty:: UniqueImmBorrow | ty:: MutBorrow => {
270
+ self . mutably_accessed_statics . insert ( borrow_id) ;
271
+ }
272
+ }
273
+ }
274
+
275
+ fn mutate ( & mut self ,
276
+ assignment_id : ast:: NodeId ,
277
+ _assignment_span : Span ,
278
+ assignee_cmt : mc:: cmt ,
279
+ _mode : euv:: MutateMode ) {
280
+ if !self . is_static_mut ( & assignee_cmt) {
281
+ return
282
+ }
283
+ self . mutably_accessed_statics . insert ( assignment_id) ;
284
+ }
285
+
286
+ fn consume ( & mut self ,
287
+ _consume_id : ast:: NodeId ,
288
+ _consume_span : Span ,
289
+ _cmt : mc:: cmt ,
290
+ _mode : euv:: ConsumeMode ) { }
291
+ fn consume_pat ( & mut self ,
292
+ _consume_pat : & ast:: Pat ,
293
+ _cmt : mc:: cmt ,
294
+ _mode : euv:: ConsumeMode ) { }
295
+ fn decl_without_init ( & mut self , _id : ast:: NodeId , _span : Span ) { }
296
+ }
297
+
200
298
pub fn check_crate ( tcx : & ty:: ctxt , krate : & ast:: Crate ) {
299
+ let mut delegate = StaticMutChecker {
300
+ mutably_accessed_statics : NodeSet :: new ( ) ,
301
+ } ;
302
+ {
303
+ let visitor = euv:: ExprUseVisitor :: new ( & mut delegate, tcx) ;
304
+ visit:: walk_crate ( & mut FunctionVisitor ( visitor) , krate, ( ) ) ;
305
+ }
306
+
201
307
let mut visitor = EffectCheckVisitor {
202
308
tcx : tcx,
203
309
unsafe_context : SafeContext ,
310
+ mutably_accessed_statics : & mut delegate. mutably_accessed_statics ,
204
311
} ;
205
-
206
312
visit:: walk_crate ( & mut visitor, krate, ( ) ) ;
313
+ assert ! ( visitor. mutably_accessed_statics. len( ) == 0 ) ;
207
314
}
0 commit comments