@@ -22,6 +22,7 @@ use core::str;
22
22
use core:: vec;
23
23
use std:: oldmap:: HashMap ;
24
24
use syntax:: ast:: * ;
25
+ use syntax:: attr:: attrs_contains_name;
25
26
use syntax:: codemap:: { span, spanned} ;
26
27
use syntax:: print:: pprust:: expr_to_str;
27
28
use syntax:: { visit, ast_util} ;
@@ -55,6 +56,8 @@ use syntax::{visit, ast_util};
55
56
// primitives in the stdlib are explicitly annotated to only take sendable
56
57
// types.
57
58
59
+ use core:: hashmap:: linear:: LinearSet ;
60
+
58
61
pub const try_adding: & ' static str = "Try adding a move" ;
59
62
60
63
pub type rval_map = HashMap < node_id , ( ) > ;
@@ -63,7 +66,7 @@ pub struct Context {
63
66
tcx : ty:: ctxt ,
64
67
method_map : typeck:: method_map ,
65
68
last_use_map : liveness:: last_use_map ,
66
- current_item : node_id
69
+ current_item : node_id ,
67
70
}
68
71
69
72
pub fn check_crate ( tcx : ty:: ctxt ,
@@ -74,16 +77,15 @@ pub fn check_crate(tcx: ty::ctxt,
74
77
tcx : tcx,
75
78
method_map : method_map,
76
79
last_use_map : last_use_map,
77
- current_item : -1
80
+ current_item : -1 ,
78
81
} ;
79
82
let visit = visit:: mk_vt ( @visit:: Visitor {
80
83
visit_arm : check_arm,
81
84
visit_expr : check_expr,
82
85
visit_fn : check_fn,
83
86
visit_ty : check_ty,
84
- visit_item : |i, cx, v| {
85
- visit:: visit_item ( i, Context { current_item : i. id , .. cx } , v) ;
86
- } ,
87
+ visit_item : check_item,
88
+ visit_block : check_block,
87
89
.. * visit:: default_visitor ( )
88
90
} ) ;
89
91
visit:: visit_crate ( * crate , ctx, visit) ;
@@ -92,6 +94,93 @@ pub fn check_crate(tcx: ty::ctxt,
92
94
93
95
type check_fn = @fn ( Context , @freevar_entry ) ;
94
96
97
+ fn check_struct_safe_for_destructor ( cx : Context ,
98
+ span : span ,
99
+ struct_did : def_id ) {
100
+ let struct_tpt = ty:: lookup_item_type ( cx. tcx , struct_did) ;
101
+ if struct_tpt. bounds . len ( ) == 0 {
102
+ let struct_ty = ty:: mk_struct ( cx. tcx , struct_did, ty:: substs {
103
+ self_r : None ,
104
+ self_ty : None ,
105
+ tps : ~[ ]
106
+ } ) ;
107
+ if !ty:: type_is_owned ( cx. tcx , struct_ty) {
108
+ cx. tcx . sess . span_err ( span,
109
+ ~"cannot implement a destructor on a struct \
110
+ that is not Owned ") ;
111
+ cx. tcx . sess . span_note ( span,
112
+ ~"use \"#[ unsafe_destructor] \" on the \
113
+ implementation to force the compiler to \
114
+ allow this") ;
115
+ }
116
+ } else {
117
+ cx. tcx . sess . span_err ( span,
118
+ ~"cannot implement a destructor on a struct \
119
+ with type parameters") ;
120
+ cx. tcx . sess . span_note ( span,
121
+ ~"use \"#[ unsafe_destructor] \" on the \
122
+ implementation to force the compiler to \
123
+ allow this") ;
124
+ }
125
+ }
126
+
127
+ fn check_block ( block : & blk , cx : Context , visitor : visit:: vt < Context > ) {
128
+ visit:: visit_block ( block, cx, visitor) ;
129
+ }
130
+
131
+ fn check_item ( item : @item, cx : Context , visitor : visit:: vt < Context > ) {
132
+ // If this is a destructor, check kinds.
133
+ if !attrs_contains_name ( item. attrs , "unsafe_destructor" ) {
134
+ match item. node {
135
+ item_impl( _, Some ( trait_ref) , self_type, _) => {
136
+ match cx. tcx . def_map . find ( & trait_ref. ref_id ) {
137
+ None => cx. tcx . sess . bug ( ~"trait ref not in def map!"),
138
+ Some(trait_def) => {
139
+ let trait_def_id = ast_util::def_id_of_def(trait_def);
140
+ if cx.tcx.lang_items.drop_trait() == trait_def_id {
141
+ // Yes, it's a destructor.
142
+ match self_type.node {
143
+ ty_path(_, path_node_id) => {
144
+ let struct_def = cx.tcx.def_map.get(
145
+ &path_node_id);
146
+ let struct_did =
147
+ ast_util::def_id_of_def(struct_def);
148
+ check_struct_safe_for_destructor(
149
+ cx,
150
+ self_type.span,
151
+ struct_did);
152
+ }
153
+ _ => {
154
+ cx.tcx.sess.span_bug(self_type.span,
155
+ ~"the self type for \
156
+ the Drop trait \
157
+ impl is not a \
158
+ path" ) ;
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ }
165
+ item_struct ( struct_def, _) => {
166
+ match struct_def. dtor {
167
+ None => { }
168
+ Some ( ref dtor) => {
169
+ let struct_did = def_id { crate : 0 , node : item. id } ;
170
+ check_struct_safe_for_destructor ( cx,
171
+ dtor. span ,
172
+ struct_did) ;
173
+ }
174
+ }
175
+ }
176
+ _ => { }
177
+ }
178
+ }
179
+
180
+ let cx = Context { current_item : item. id , ..cx } ;
181
+ visit:: visit_item ( item, cx, visitor) ;
182
+ }
183
+
95
184
// Yields the appropriate function to check the kind of closed over
96
185
// variables. `id` is the node_id for some expression that creates the
97
186
// closure.
0 commit comments