@@ -22,6 +22,7 @@ use core::str;
2222use core:: vec;
2323use std:: oldmap:: HashMap ;
2424use syntax:: ast:: * ;
25+ use syntax:: attr:: attrs_contains_name;
2526use syntax:: codemap:: { span, spanned} ;
2627use syntax:: print:: pprust:: expr_to_str;
2728use syntax:: { visit, ast_util} ;
@@ -55,6 +56,8 @@ use syntax::{visit, ast_util};
5556// primitives in the stdlib are explicitly annotated to only take sendable
5657// types.
5758
59+ use core:: hashmap:: linear:: LinearSet ;
60+
5861pub const try_adding: & ' static str = "Try adding a move" ;
5962
6063pub type rval_map = HashMap < node_id , ( ) > ;
@@ -63,7 +66,7 @@ pub struct Context {
6366 tcx : ty:: ctxt ,
6467 method_map : typeck:: method_map ,
6568 last_use_map : liveness:: last_use_map ,
66- current_item : node_id
69+ current_item : node_id ,
6770}
6871
6972pub fn check_crate ( tcx : ty:: ctxt ,
@@ -74,16 +77,15 @@ pub fn check_crate(tcx: ty::ctxt,
7477 tcx : tcx,
7578 method_map : method_map,
7679 last_use_map : last_use_map,
77- current_item : -1
80+ current_item : -1 ,
7881 } ;
7982 let visit = visit:: mk_vt ( @visit:: Visitor {
8083 visit_arm : check_arm,
8184 visit_expr : check_expr,
8285 visit_fn : check_fn,
8386 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,
8789 .. * visit:: default_visitor ( )
8890 } ) ;
8991 visit:: visit_crate ( * crate , ctx, visit) ;
@@ -92,6 +94,93 @@ pub fn check_crate(tcx: ty::ctxt,
9294
9395type check_fn = @fn ( Context , @freevar_entry ) ;
9496
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+
95184// Yields the appropriate function to check the kind of closed over
96185// variables. `id` is the node_id for some expression that creates the
97186// closure.
0 commit comments