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} ;
15
14
use middle:: ty;
16
15
use middle:: typeck:: method_map;
17
16
use util:: ppaux;
18
17
19
- use syntax:: ast:: { UnDeref , ExprCall , ExprInlineAsm , ExprMethodCall } ;
20
- use syntax:: ast:: { ExprUnary , unsafe_fn, ExprPath } ;
21
18
use syntax:: ast;
22
19
use syntax:: codemap:: Span ;
23
- use syntax:: visit:: { fk_item_fn, fk_method} ;
24
20
use syntax:: visit;
25
- use syntax:: visit:: { Visitor , fn_kind} ;
26
- use syntax:: ast:: { fn_decl, Block , NodeId , Expr } ;
21
+ use syntax:: visit:: Visitor ;
27
22
28
23
#[ deriving( Eq ) ]
29
24
enum UnsafeContext {
@@ -32,29 +27,26 @@ enum UnsafeContext {
32
27
UnsafeBlock ( ast:: NodeId ) ,
33
28
}
34
29
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
-
42
30
fn type_is_unsafe_function ( ty : ty:: t ) -> bool {
43
31
match ty:: get ( ty) . sty {
44
- ty_bare_fn( ref f) => f. purity == unsafe_fn,
45
- ty_closure( ref f) => f. purity == unsafe_fn,
32
+ ty :: ty_bare_fn( ref f) => f. purity == ast :: unsafe_fn,
33
+ ty :: ty_closure( ref f) => f. purity == ast :: unsafe_fn,
46
34
_ => false ,
47
35
}
48
36
}
49
37
50
38
struct EffectCheckVisitor {
51
39
tcx : ty:: ctxt ,
52
- context : @mut Context ,
40
+
41
+ /// The method map.
42
+ method_map : method_map ,
43
+ /// Whether we're in an unsafe context.
44
+ unsafe_context : UnsafeContext ,
53
45
}
54
46
55
47
impl EffectCheckVisitor {
56
48
fn require_unsafe ( & mut self , span : Span , description : & str ) {
57
- match self . context . unsafe_context {
49
+ match self . unsafe_context {
58
50
SafeContext => {
59
51
// Report an error.
60
52
self . tcx . sess . span_err ( span,
@@ -69,112 +61,124 @@ impl EffectCheckVisitor {
69
61
UnsafeFn => { }
70
62
}
71
63
}
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
+ }
72
80
}
73
81
74
82
impl Visitor < ( ) > for EffectCheckVisitor {
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
- }
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
+ }
90
100
91
- visit:: walk_fn ( self ,
92
- fn_kind,
93
- fn_decl,
94
- block,
95
- span,
96
- node_id,
97
- ( ) ) ;
101
+ visit:: walk_fn ( self , fn_kind, fn_decl, block, span, node_id, ( ) ) ;
98
102
99
- self . context . unsafe_context = old_unsafe_context
103
+ self . unsafe_context = old_unsafe_context
100
104
}
101
105
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
- }
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
+ }
111
114
112
- visit:: walk_block ( self , block, ( ) ) ;
115
+ visit:: walk_block ( self , block, ( ) ) ;
113
116
114
- self . context . unsafe_context = old_unsafe_context
117
+ self . unsafe_context = old_unsafe_context
115
118
}
116
119
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
- }
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" )
128
129
}
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
- }
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" )
136
137
}
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
- _ => { }
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" )
147
147
}
148
+ _ => { }
148
149
}
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
- _ => { }
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" )
158
164
}
165
+ _ => { }
159
166
}
160
- _ => { }
161
167
}
168
+ _ => { }
169
+ }
162
170
163
- visit:: walk_expr ( self , expr, ( ) ) ;
171
+ visit:: walk_expr ( self , expr, ( ) ) ;
164
172
}
165
173
}
166
174
167
175
pub fn check_crate ( tcx : ty:: ctxt ,
168
176
method_map : method_map ,
169
177
crate : & ast:: Crate ) {
170
- let context = @mut Context {
171
- method_map : method_map,
172
- unsafe_context : SafeContext ,
173
- } ;
174
-
175
178
let mut visitor = EffectCheckVisitor {
176
179
tcx : tcx,
177
- context : context,
180
+ method_map : method_map,
181
+ unsafe_context : SafeContext ,
178
182
} ;
179
183
180
184
visit:: walk_crate ( & mut visitor, crate , ( ) ) ;
0 commit comments