11
11
//! Enforces the Rust effect system. Currently there is just one effect,
12
12
/// `unsafe`.
13
13
14
+ use middle:: ty:: { ty_bare_fn, ty_closure, ty_ptr} ;
14
15
use middle:: ty;
15
16
use middle:: typeck:: method_map;
16
17
use util:: ppaux;
17
18
19
+ use syntax:: ast:: { UnDeref , ExprCall , ExprInlineAsm , ExprMethodCall } ;
20
+ use syntax:: ast:: { ExprUnary , unsafe_fn, ExprPath } ;
18
21
use syntax:: ast;
19
22
use syntax:: codemap:: Span ;
23
+ use syntax:: visit:: { fk_item_fn, fk_method} ;
20
24
use syntax:: visit;
21
- use syntax:: visit:: Visitor ;
25
+ use syntax:: visit:: { Visitor , fn_kind} ;
26
+ use syntax:: ast:: { fn_decl, Block , NodeId , Expr } ;
22
27
23
28
#[ deriving( Eq ) ]
24
29
enum UnsafeContext {
@@ -27,26 +32,29 @@ enum UnsafeContext {
27
32
UnsafeBlock ( ast:: NodeId ) ,
28
33
}
29
34
35
+ struct Context {
36
+ /// The method map.
37
+ method_map : method_map ,
38
+ /// Whether we're in an unsafe context.
39
+ unsafe_context : UnsafeContext ,
40
+ }
41
+
30
42
fn type_is_unsafe_function ( ty : ty:: t ) -> bool {
31
43
match ty:: get ( ty) . sty {
32
- ty :: ty_bare_fn( ref f) => f. purity == ast :: unsafe_fn,
33
- ty :: ty_closure( ref f) => f. purity == ast :: unsafe_fn,
44
+ ty_bare_fn( ref f) => f. purity == unsafe_fn,
45
+ ty_closure( ref f) => f. purity == unsafe_fn,
34
46
_ => false ,
35
47
}
36
48
}
37
49
38
50
struct EffectCheckVisitor {
39
51
tcx : ty:: ctxt ,
40
-
41
- /// The method map.
42
- method_map : method_map ,
43
- /// Whether we're in an unsafe context.
44
- unsafe_context : UnsafeContext ,
52
+ context : @mut Context ,
45
53
}
46
54
47
55
impl EffectCheckVisitor {
48
56
fn require_unsafe ( & mut self , span : Span , description : & str ) {
49
- match self . unsafe_context {
57
+ match self . context . unsafe_context {
50
58
SafeContext => {
51
59
// Report an error.
52
60
self . tcx . sess . span_err ( span,
@@ -61,125 +69,113 @@ impl EffectCheckVisitor {
61
69
UnsafeFn => { }
62
70
}
63
71
}
64
-
65
- fn check_str_index ( & mut self , e : @ast:: Expr ) {
66
- let base_type = match e. node {
67
- ast:: ExprIndex ( _, base, _) => ty:: node_id_to_type ( self . tcx , base. id ) ,
68
- _ => return
69
- } ;
70
- debug2 ! ( "effect: checking index with base type {}" ,
71
- ppaux:: ty_to_str( self . tcx, base_type) ) ;
72
- match ty:: get ( base_type) . sty {
73
- ty:: ty_estr( * ) => {
74
- self . tcx . sess . span_err ( e. span ,
75
- "modification of string types is not allowed" ) ;
76
- }
77
- _ => { }
78
- }
79
- }
80
72
}
81
73
82
74
impl Visitor < ( ) > for EffectCheckVisitor {
83
- fn visit_fn ( & mut self , fn_kind : & visit:: fn_kind , fn_decl : & ast:: fn_decl ,
84
- block : & ast:: Block , span : Span , node_id : ast:: NodeId , _: ( ) ) {
85
-
86
- let ( is_item_fn, is_unsafe_fn) = match * fn_kind {
87
- visit:: fk_item_fn( _, _, purity, _) =>
88
- ( true , purity == ast:: unsafe_fn) ,
89
- visit:: fk_method( _, _, method) =>
90
- ( true , method. purity == ast:: unsafe_fn) ,
91
- _ => ( false , false ) ,
92
- } ;
93
-
94
- let old_unsafe_context = self . unsafe_context ;
95
- if is_unsafe_fn {
96
- self . unsafe_context = UnsafeFn
97
- } else if is_item_fn {
98
- self . unsafe_context = SafeContext
99
- }
75
+ fn visit_fn ( & mut self , fn_kind : & fn_kind , fn_decl : & fn_decl ,
76
+ block : & Block , span : Span , node_id : NodeId , _: ( ) ) {
77
+
78
+ let ( is_item_fn, is_unsafe_fn) = match * fn_kind {
79
+ fk_item_fn( _, _, purity, _) => ( true , purity == unsafe_fn) ,
80
+ fk_method( _, _, method) => ( true , method. purity == unsafe_fn) ,
81
+ _ => ( false , false ) ,
82
+ } ;
83
+
84
+ let old_unsafe_context = self . context . unsafe_context ;
85
+ if is_unsafe_fn {
86
+ self . context . unsafe_context = UnsafeFn
87
+ } else if is_item_fn {
88
+ self . context . unsafe_context = SafeContext
89
+ }
100
90
101
- visit:: walk_fn ( self , fn_kind, fn_decl, block, span, node_id, ( ) ) ;
91
+ visit:: walk_fn ( self ,
92
+ fn_kind,
93
+ fn_decl,
94
+ block,
95
+ span,
96
+ node_id,
97
+ ( ) ) ;
102
98
103
- self . unsafe_context = old_unsafe_context
99
+ self . context . unsafe_context = old_unsafe_context
104
100
}
105
101
106
- fn visit_block ( & mut self , block : & ast:: Block , _: ( ) ) {
107
- let old_unsafe_context = self . unsafe_context ;
108
- let is_unsafe = match block. rules {
109
- ast:: UnsafeBlock ( * ) => true , ast:: DefaultBlock => false
110
- } ;
111
- if is_unsafe && self . unsafe_context == SafeContext {
112
- self . unsafe_context = UnsafeBlock ( block. id )
113
- }
102
+ fn visit_block ( & mut self , block : & Block , _: ( ) ) {
103
+
104
+ let old_unsafe_context = self . context . unsafe_context ;
105
+ let is_unsafe = match block. rules {
106
+ ast:: UnsafeBlock ( * ) => true , ast:: DefaultBlock => false
107
+ } ;
108
+ if is_unsafe && self . context . unsafe_context == SafeContext {
109
+ self . context . unsafe_context = UnsafeBlock ( block. id )
110
+ }
114
111
115
- visit:: walk_block ( self , block, ( ) ) ;
112
+ visit:: walk_block ( self , block, ( ) ) ;
116
113
117
- self . unsafe_context = old_unsafe_context
114
+ self . context . unsafe_context = old_unsafe_context
118
115
}
119
116
120
- fn visit_expr ( & mut self , expr : @ast:: Expr , _: ( ) ) {
121
- match expr. node {
122
- ast:: ExprMethodCall ( callee_id, _, _, _, _, _) => {
123
- let base_type = ty:: node_id_to_type ( self . tcx , callee_id) ;
124
- debug2 ! ( "effect: method call case, base type is {}" ,
125
- ppaux:: ty_to_str( self . tcx, base_type) ) ;
126
- if type_is_unsafe_function ( base_type) {
127
- self . require_unsafe ( expr. span ,
128
- "invocation of unsafe method" )
117
+ fn visit_expr ( & mut self , expr : @Expr , _: ( ) ) {
118
+
119
+ match expr. node {
120
+ ExprMethodCall ( callee_id, _, _, _, _, _) => {
121
+ let base_type = ty:: node_id_to_type ( self . tcx , callee_id) ;
122
+ debug2 ! ( "effect: method call case, base type is {}" ,
123
+ ppaux:: ty_to_str( self . tcx, base_type) ) ;
124
+ if type_is_unsafe_function ( base_type) {
125
+ self . require_unsafe ( expr. span ,
126
+ "invocation of unsafe method" )
127
+ }
129
128
}
130
- }
131
- ast :: ExprCall ( base , _ , _ ) => {
132
- let base_type = ty :: node_id_to_type ( self . tcx , base. id ) ;
133
- debug2 ! ( "effect: call case, base type is {}" ,
134
- ppaux :: ty_to_str ( self . tcx , base_type) ) ;
135
- if type_is_unsafe_function ( base_type ) {
136
- self . require_unsafe ( expr . span , "call to unsafe function" )
129
+ ExprCall ( base , _ , _ ) => {
130
+ let base_type = ty :: node_id_to_type ( self . tcx , base . id ) ;
131
+ debug2 ! ( "effect: call case , base type is {}" ,
132
+ ppaux :: ty_to_str ( self . tcx , base_type ) ) ;
133
+ if type_is_unsafe_function ( base_type) {
134
+ self . require_unsafe ( expr . span , "call to unsafe function" )
135
+ }
137
136
}
138
- }
139
- ast:: ExprUnary ( _, ast:: UnDeref , base) => {
140
- let base_type = ty:: node_id_to_type ( self . tcx , base. id ) ;
141
- debug2 ! ( "effect: unary case, base type is {}" ,
142
- ppaux:: ty_to_str( self . tcx, base_type) ) ;
143
- match ty:: get ( base_type) . sty {
144
- ty:: ty_ptr( _) => {
145
- self . require_unsafe ( expr. span ,
146
- "dereference of unsafe pointer" )
137
+ ExprUnary ( _, UnDeref , base) => {
138
+ let base_type = ty:: node_id_to_type ( self . tcx , base. id ) ;
139
+ debug2 ! ( "effect: unary case, base type is {}" ,
140
+ ppaux:: ty_to_str( self . tcx, base_type) ) ;
141
+ match ty:: get ( base_type) . sty {
142
+ ty_ptr( _) => {
143
+ self . require_unsafe ( expr. span ,
144
+ "dereference of unsafe pointer" )
145
+ }
146
+ _ => { }
147
147
}
148
- _ => { }
149
148
}
150
- }
151
- ast:: ExprAssign ( base, _) | ast:: ExprAssignOp ( _, _, base, _) => {
152
- self . check_str_index ( base) ;
153
- }
154
- ast:: ExprAddrOf ( ast:: MutMutable , base) => {
155
- self . check_str_index ( base) ;
156
- }
157
- ast:: ExprInlineAsm ( * ) => {
158
- self . require_unsafe ( expr. span , "use of inline assembly" )
159
- }
160
- ast:: ExprPath ( * ) => {
161
- match ty:: resolve_expr ( self . tcx , expr) {
162
- ast:: DefStatic ( _, true ) => {
163
- self . require_unsafe ( expr. span , "use of mutable static" )
149
+ ExprInlineAsm ( * ) => {
150
+ self . require_unsafe ( expr. span , "use of inline assembly" )
151
+ }
152
+ ExprPath ( * ) => {
153
+ match ty:: resolve_expr ( self . tcx , expr) {
154
+ ast:: DefStatic ( _, true ) => {
155
+ self . require_unsafe ( expr. span , "use of mutable static" )
156
+ }
157
+ _ => { }
164
158
}
165
- _ => { }
166
159
}
160
+ _ => { }
167
161
}
168
- _ => { }
169
- }
170
162
171
- visit:: walk_expr ( self , expr, ( ) ) ;
163
+ visit:: walk_expr ( self , expr, ( ) ) ;
172
164
}
173
165
}
174
166
175
167
pub fn check_crate ( tcx : ty:: ctxt ,
176
168
method_map : method_map ,
177
169
crate : & ast:: Crate ) {
178
- let mut visitor = EffectCheckVisitor {
179
- tcx : tcx,
170
+ let context = @mut Context {
180
171
method_map : method_map,
181
172
unsafe_context : SafeContext ,
182
173
} ;
183
174
175
+ let mut visitor = EffectCheckVisitor {
176
+ tcx : tcx,
177
+ context : context,
178
+ } ;
179
+
184
180
visit:: walk_crate ( & mut visitor, crate , ( ) ) ;
185
181
}
0 commit comments