diff --git a/src/jemalloc b/src/jemalloc index 2dba541881fb8..aae04170ccbfe 160000 --- a/src/jemalloc +++ b/src/jemalloc @@ -1 +1 @@ -Subproject commit 2dba541881fb8e35246d653bbe2e7c7088777a4a +Subproject commit aae04170ccbfeea620502106b581c3c216cd132a diff --git a/src/libcollections/treemap.rs b/src/libcollections/treemap.rs index 354edae473fd5..86fea2457e1b7 100644 --- a/src/libcollections/treemap.rs +++ b/src/libcollections/treemap.rs @@ -1084,27 +1084,29 @@ impl Set for TreeSet { } fn is_subset(&self, other: &TreeSet) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - let mut a = x.next(); - let mut b = y.next(); - while a.is_some() { - if b.is_none() { - return false; - } + { + let mut x = self.iter(); + let mut y = other.iter(); + let mut a = x.next(); + let mut b = y.next(); + while a.is_some() { + if b.is_none() { + return false; + } - let a1 = a.unwrap(); - let b1 = b.unwrap(); + let a1 = a.unwrap(); + let b1 = b.unwrap(); - match b1.cmp(a1) { - Less => (), - Greater => return false, - Equal => a = x.next(), - } + match b1.cmp(a1) { + Less => (), + Greater => return false, + Equal => a = x.next(), + } - b = y.next(); + b = y.next(); + } + true } - true } } diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 1cad9a3f8ca22..94a63208ffe72 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -310,8 +310,11 @@ impl RefCell { #[unstable = "waiting for `Clone` to become stable"] impl Clone for RefCell { - fn clone(&self) -> RefCell { - RefCell::new(self.borrow().clone()) + fn clone<'a>(&'a self) -> RefCell { + { + let borrowed: Ref<'a,T> = self.borrow(); + RefCell::new(borrowed.clone()) + } } } diff --git a/src/libcore/finally.rs b/src/libcore/finally.rs index 9b59b410e7cc4..68e8cc701e4e2 100644 --- a/src/libcore/finally.rs +++ b/src/libcore/finally.rs @@ -90,16 +90,22 @@ impl Finally for fn() -> T { * }) * ``` */ -pub fn try_finally(mutate: &mut T, - drop: U, - try_fn: |&mut T, U| -> R, - finally_fn: |&mut T|) - -> R { - let f = Finallyalizer { - mutate: mutate, - dtor: finally_fn, - }; - try_fn(&mut *f.mutate, drop) +pub fn try_finally<'a, + T, + U, + R>( + mutate: &'a mut T, + drop: U, + try_fn: |&mut T, U| -> R, + finally_fn: |&mut T|:'a) + -> R { + { + let f: Finallyalizer<'a,T> = Finallyalizer { + mutate: mutate, + dtor: finally_fn, + }; + try_fn(&mut *f.mutate, drop) + } } struct Finallyalizer<'a,A:'a> { diff --git a/src/libgreen/basic.rs b/src/libgreen/basic.rs index e48786f33745f..2302f9ac40cf4 100644 --- a/src/libgreen/basic.rs +++ b/src/libgreen/basic.rs @@ -61,10 +61,13 @@ impl BasicLoop { fn remote_work(&mut self) { let messages = unsafe { - mem::replace(&mut *self.messages.lock(), Vec::new()) + let lock = &mut *self.messages.lock(); + mem::replace(lock, Vec::new()) }; - for message in messages.move_iter() { - self.message(message); + { + for message in messages.move_iter() { + self.message(message); + } } } diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 6f020184b336d..db98664c26934 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -258,7 +258,10 @@ pub fn build_session_(sopts: config::Options, recursion_limit: Cell::new(64), }; - sess.lint_store.borrow_mut().register_builtin(Some(&sess)); + { + sess.lint_store.borrow_mut().register_builtin(Some(&sess)); + } + sess } diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs index 13a40aba93078..e049db9377098 100644 --- a/src/librustc/front/feature_gate.rs +++ b/src/librustc/front/feature_gate.rs @@ -244,9 +244,8 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { "unsafe_destructor") { self.gate_feature("unsafe_destructor", i.span, - "`#[unsafe_destructor]` allows too \ - many unsafe patterns and may be \ - removed in the future"); + "`#[unsafe_destructor]` does nothing \ + anymore") } } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 53203663bb16e..e4f3008bc789c 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -318,6 +318,9 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region { 't' => { ty::ReStatic } + 'n' => { + ty::ReFunction + } 'e' => { ty::ReStatic } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index cbf558b6b483e..51a4655744860 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -149,6 +149,9 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) { ty::ReScope(nid) => { mywrite!(w, "s{}|", nid); } + ty::ReFunction => { + mywrite!(w, "n"); + } ty::ReStatic => { mywrite!(w, "t"); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 21d0292d2fe3a..c60b4679664d1 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -490,7 +490,7 @@ impl tr for ty::Region { ty::ReScope(id) => { ty::ReScope(dcx.tr_id(id)) } - ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) => { + ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) | ty::ReFunction => { *self } ty::ReFree(ref fr) => { diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index e13717e5abd31..417a5eec63b85 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -163,36 +163,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { // See the SCOPE(LV) function in doc.rs - match cmt.cat { - mc::cat_rvalue(temp_scope) => { - temp_scope - } - mc::cat_upvar(..) | - mc::cat_copied_upvar(_) => { - ty::ReScope(self.item_scope_id) - } - mc::cat_static_item => { - ty::ReStatic - } - mc::cat_local(local_id) | - mc::cat_arg(local_id) => { - ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id)) - } - mc::cat_deref(_, _, mc::UnsafePtr(..)) => { - ty::ReStatic - } - mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) | - mc::cat_deref(_, _, mc::Implicit(_, r)) => { - r - } - mc::cat_downcast(ref cmt) | - mc::cat_deref(ref cmt, _, mc::OwnedPtr) | - mc::cat_deref(ref cmt, _, mc::GcPtr) | - mc::cat_interior(ref cmt, _) | - mc::cat_discr(ref cmt, _) => { - self.scope(cmt) - } - } + mc::scope(self.bccx.tcx, cmt, self.item_scope_id) } fn report_error(&self, code: bckerr_code) { diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index cd003432ef22c..a01e67dd17595 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -275,6 +275,12 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { ty::ReScope(id) => id, ty::ReFree(ref fr) => fr.scope_id, + ty::ReFunction => { + // For purposes of the borrow check, we can consider + // this a loan for the outer function block. + self.item_ub + } + ty::ReStatic => { // If we get here, an error must have been // reported in diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index d6c11caefe84b..51f06c46d907b 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -511,37 +511,41 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> { } } _ => { - let overloaded_call_type = - match self.tcx() - .method_map - .borrow() - .find(&MethodCall::expr(call.id)) { - Some(ref method_callee) => { - OverloadedCallType::from_method_origin( - self.tcx(), - &method_callee.origin) - } - None => { - self.tcx().sess.span_bug( - callee.span, - format!("unexpected callee type {}", - callee_ty.repr(self.tcx())).as_slice()) - } - }; - match overloaded_call_type { - FnMutOverloadedCall => { - self.borrow_expr(callee, - ty::ReScope(call.id), - ty::MutBorrow, - ClosureInvocation); + let overloaded_call_type; + { + let method_map = self.tcx().method_map.borrow(); + overloaded_call_type = match method_map.find( + &MethodCall::expr(call.id)) { + Some(ref method_callee) => { + OverloadedCallType::from_method_origin( + self.tcx(), + &method_callee.origin) + } + None => { + self.tcx().sess.span_bug( + callee.span, + format!("unexpected callee type {}", + callee_ty.repr(self.tcx())) + .as_slice()) + } } - FnOverloadedCall => { - self.borrow_expr(callee, - ty::ReScope(call.id), - ty::ImmBorrow, - ClosureInvocation); + } + { + match overloaded_call_type { + FnMutOverloadedCall => { + self.borrow_expr(callee, + ty::ReScope(call.id), + ty::MutBorrow, + ClosureInvocation); + } + FnOverloadedCall => { + self.borrow_expr(callee, + ty::ReScope(call.id), + ty::ImmBorrow, + ClosureInvocation); + } + FnOnceOverloadedCall => self.consume_expr(callee), } - FnOnceOverloadedCall => self.consume_expr(callee), } } } @@ -933,8 +937,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> { // inferred by regionbk let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id }; - let upvar_borrow = self.tcx().upvar_borrow_map.borrow() - .get_copy(&upvar_id); + let upvar_borrow = { + let upvar_borrow_map = self.tcx().upvar_borrow_map.borrow(); + upvar_borrow_map.get_copy(&upvar_id) + }; self.delegate.borrow(closure_expr.id, closure_expr.span, diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index aeb0c155a3f48..d8208c2d2c4a6 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -67,76 +67,7 @@ pub fn check_crate(tcx: &ty::ctxt) { tcx.sess.abort_if_errors(); } -struct EmptySubstsFolder<'a, 'tcx: 'a> { - tcx: &'a ty::ctxt<'tcx> -} -impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for EmptySubstsFolder<'a, 'tcx> { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { - self.tcx - } - fn fold_substs(&mut self, _: &subst::Substs) -> subst::Substs { - subst::Substs::empty() - } -} - -fn check_struct_safe_for_destructor(cx: &mut Context, - span: Span, - struct_did: DefId) { - let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did); - if !struct_tpt.generics.has_type_params(subst::TypeSpace) - && !struct_tpt.generics.has_region_params(subst::TypeSpace) { - let mut folder = EmptySubstsFolder { tcx: cx.tcx }; - if !ty::type_is_sendable(cx.tcx, struct_tpt.ty.fold_with(&mut folder)) { - span_err!(cx.tcx.sess, span, E0125, - "cannot implement a destructor on a \ - structure or enumeration that does not satisfy Send"); - span_note!(cx.tcx.sess, span, - "use \"#[unsafe_destructor]\" on the implementation \ - to force the compiler to allow this"); - } - } else { - span_err!(cx.tcx.sess, span, E0141, - "cannot implement a destructor on a structure \ - with type parameters"); - span_note!(cx.tcx.sess, span, - "use \"#[unsafe_destructor]\" on the implementation \ - to force the compiler to allow this"); - } -} - -fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_type: &Ty) { - let ast_trait_def = *cx.tcx.def_map.borrow() - .find(&trait_ref.ref_id) - .expect("trait ref not in def map!"); - let trait_def_id = ast_trait_def.def_id(); - - // If this is a destructor, check kinds. - if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) && - !attr::contains_name(it.attrs.as_slice(), "unsafe_destructor") - { - match self_type.node { - TyPath(_, ref bounds, path_node_id) => { - assert!(bounds.is_none()); - let struct_def = cx.tcx.def_map.borrow().get_copy(&path_node_id); - let struct_did = struct_def.def_id(); - check_struct_safe_for_destructor(cx, self_type.span, struct_did); - } - _ => { - cx.tcx.sess.span_bug(self_type.span, - "the self type for the Drop trait impl is not a path"); - } - } - } -} - fn check_item(cx: &mut Context, item: &Item) { - match item.node { - ItemImpl(_, Some(ref trait_ref), ref self_type, _) => { - check_impl_of_trait(cx, item, trait_ref, &**self_type); - } - _ => {} - } - visit::walk_item(cx, item) } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3e42ee9187c42..976127c691ac8 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -69,7 +69,7 @@ use middle::typeck; use util::nodemap::{DefIdMap, NodeMap}; use util::ppaux::{ty_to_string, Repr}; -use syntax::ast::{MutImmutable, MutMutable}; +use syntax::ast::{MutImmutable, MutMutable, NodeId}; use syntax::ast; use syntax::codemap::Span; use syntax::print::pprust; @@ -1417,3 +1417,32 @@ fn element_kind(t: ty::t) -> ElementKind { _ => OtherElement } } + + +/// Returns the maximal region scope for the which the lvalue `cmt` is +/// guaranteed to be valid without any rooting etc, and presuming `cmt` +/// is not mutated. See the `SCOPE(LV)` function in `borrowck/doc.rs`. +pub fn scope(tcx: &ty::ctxt, cmt: &cmt, item_scope_id: NodeId) -> ty::Region { + match cmt.cat { + cat_rvalue(temp_scope) => temp_scope, + cat_upvar(..) | cat_copied_upvar(_) => ty::ReScope(item_scope_id), + + cat_static_item => ty::ReStatic, + + cat_local(local_id) | cat_arg(local_id) => { + ty::ReScope(tcx.region_maps.var_scope(local_id)) + } + + cat_deref(_, _, UnsafePtr(..)) => ty::ReStatic, + + cat_deref(_, _, BorrowedPtr(_, r)) | + cat_deref(_, _, Implicit(_, r)) => r, + + cat_downcast(ref cmt) | + cat_deref(ref cmt, _, OwnedPtr) | + cat_deref(ref cmt, _, GcPtr) | + cat_interior(ref cmt, _) | + cat_discr(ref cmt, _) => scope(tcx, cmt, item_scope_id), + } +} + diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 4f81aac5eb049..c5e36b7898f6f 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -276,9 +276,11 @@ impl RegionMaps { sub_region == super_region || { match (sub_region, super_region) { (ty::ReEmpty, _) | - (_, ty::ReStatic) => { - true - } + (_, ty::ReStatic) => true, + (ty::ReScope(_), ty::ReFunction) => true, + (ty::ReFunction, ty::ReFree(_)) => true, + (ty::ReFunction, ty::ReScope(_)) => false, + (ty::ReFree(_), ty::ReFunction) => false, (ty::ReScope(sub_scope), ty::ReScope(super_scope)) => { self.is_subscope_of(sub_scope, super_scope) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 1a2bda605daba..310f9d8bb6e42 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1319,8 +1319,14 @@ impl<'a> Resolver<'a> { TyPath(ref path, _, _) if path.segments.len() == 1 => { let name = path.segments.last().unwrap().identifier; - let parent_opt = parent.module().children.borrow() - .find_copy(&name.name); + let parent_opt = { + let parent_module = parent.module(); + { + let children = parent_module.children + .borrow(); + children.find_copy(&name.name) + } + }; let new_parent = match parent_opt { // It already exists Some(ref child) if child.get_module_if_available() @@ -1635,9 +1641,18 @@ impl<'a> Resolver<'a> { &*parent.module(), name.name, view_item.span); - parent.module().external_module_children.borrow_mut() - .insert(name.name, external_module.clone()); - self.build_reduced_graph_for_external_crate(external_module); + { + let module = parent.module(); + { + let mut external_module_children = + module.external_module_children.borrow_mut(); + external_module_children.insert( + name.name, + external_module.clone()); + } + } + self.build_reduced_graph_for_external_crate( + external_module); } } } @@ -2148,19 +2163,25 @@ impl<'a> Resolver<'a> { self.current_module = orig_module; self.populate_module_if_necessary(&module_); - for (_, child_node) in module_.children.borrow().iter() { - match child_node.get_module_if_available() { - None => { - // Nothing to do. - } - Some(child_module) => { - self.resolve_imports_for_module_subtree(child_module); + { + let children = module_.children.borrow(); + for (_, child_node) in children.iter() { + match child_node.get_module_if_available() { + None => { + // Nothing to do. + } + Some(child_module) => { + self.resolve_imports_for_module_subtree(child_module); + } } } } - for (_, child_module) in module_.anonymous_children.borrow().iter() { - self.resolve_imports_for_module_subtree(child_module.clone()); + { + let anonymous_children = module_.anonymous_children.borrow(); + for (_, child_module) in anonymous_children.iter() { + self.resolve_imports_for_module_subtree(child_module.clone()); + } } } @@ -2173,32 +2194,38 @@ impl<'a> Resolver<'a> { return; } - let imports = module.imports.borrow(); - let import_count = imports.len(); - while module.resolved_import_count.get() < import_count { - let import_index = module.resolved_import_count.get(); - let import_directive = imports.get(import_index); - match self.resolve_import_for_module(module.clone(), - import_directive) { - Failed(err) => { - let (span, help) = match err { - Some((span, msg)) => (span, format!(". {}", msg)), - None => (import_directive.span, String::new()) - }; - let msg = format!("unresolved import `{}`{}", - self.import_path_to_string( - import_directive.module_path - .as_slice(), - import_directive.subclass), - help); - self.resolve_error(span, msg.as_slice()); + { + let imports = &module.imports; + let imports = imports.borrow(); + let import_count = imports.len(); + while module.resolved_import_count.get() < import_count { + let import_index = module.resolved_import_count.get(); + let import_directive = imports.get(import_index); + match self.resolve_import_for_module(module.clone(), + import_directive) { + Failed(err) => { + let (span, help) = match err { + Some((span, msg)) => (span, format!(". {}", msg)), + None => (import_directive.span, String::new()) + }; + let msg = format!("unresolved import `{}`{}", + self.import_path_to_string( + import_directive.module_path + .as_slice(), + import_directive.subclass), + help); + self.resolve_error(span, msg.as_slice()); + } + Indeterminate => { + // Bail out. We'll come around next time. + break + } + Success(()) => () // Good. Continue. } - Indeterminate => break, // Bail out. We'll come around next time. - Success(()) => () // Good. Continue. - } - module.resolved_import_count - .set(module.resolved_import_count.get() + 1); + module.resolved_import_count + .set(module.resolved_import_count.get() + 1); + } } } @@ -2666,58 +2693,62 @@ impl<'a> Resolver<'a> { assert_eq!(containing_module.glob_count.get(), 0); // Add all resolved imports from the containing module. - let import_resolutions = containing_module.import_resolutions - .borrow(); - for (ident, target_import_resolution) in import_resolutions.iter() { - debug!("(resolving glob import) writing module resolution \ - {:?} into `{}`", - target_import_resolution.type_target.is_none(), - self.module_to_string(module_)); - - if !target_import_resolution.is_public { - debug!("(resolving glob import) nevermind, just kidding"); - continue - } + { + let import_resolutions = containing_module.import_resolutions + .borrow(); + for (ident, target_import_resolution) in + import_resolutions.iter() { + debug!("(resolving glob import) writing module resolution \ + {:?} into `{}`", + target_import_resolution.type_target.is_none(), + self.module_to_string(module_)); + + if !target_import_resolution.is_public { + debug!("(resolving glob import) nevermind, just kidding"); + continue + } - // Here we merge two import resolutions. - let mut import_resolutions = module_.import_resolutions.borrow_mut(); - match import_resolutions.find_mut(ident) { - Some(dest_import_resolution) => { - // Merge the two import resolutions at a finer-grained - // level. + // Here we merge two import resolutions. + let mut import_resolutions = module_.import_resolutions.borrow_mut(); + match import_resolutions.find_mut(ident) { + Some(dest_import_resolution) => { + // Merge the two import resolutions at a finer-grained + // level. - match target_import_resolution.value_target { - None => { - // Continue. - } - Some(ref value_target) => { - dest_import_resolution.value_target = - Some(value_target.clone()); - } - } - match target_import_resolution.type_target { - None => { - // Continue. + match target_import_resolution.value_target { + None => { + // Continue. + } + Some(ref value_target) => { + dest_import_resolution.value_target = + Some(value_target.clone()); + } } - Some(ref type_target) => { - dest_import_resolution.type_target = - Some(type_target.clone()); + match target_import_resolution.type_target { + None => { + // Continue. + } + Some(ref type_target) => { + dest_import_resolution.type_target = + Some(type_target.clone()); + } } + dest_import_resolution.is_public = is_public; + continue; } - dest_import_resolution.is_public = is_public; - continue; + None => {} } - None => {} - } - // Simple: just copy the old import resolution. - let mut new_import_resolution = ImportResolution::new(id, is_public); - new_import_resolution.value_target = - target_import_resolution.value_target.clone(); - new_import_resolution.type_target = - target_import_resolution.type_target.clone(); + // Simple: just copy the old import resolution. + let mut new_import_resolution = + ImportResolution::new(id, is_public); + new_import_resolution.value_target = + target_import_resolution.value_target.clone(); + new_import_resolution.type_target = + target_import_resolution.type_target.clone(); - import_resolutions.insert(*ident, new_import_resolution); + import_resolutions.insert(*ident, new_import_resolution); + } } // Add all children from the containing module. @@ -3236,28 +3267,35 @@ impl<'a> Resolver<'a> { // all its imports in the usual way; this is because chains of // adjacent import statements are processed as though they mutated the // current scope. - match module_.import_resolutions.borrow().find(&name.name) { - None => { - // Not found; continue. - } - Some(import_resolution) => { - match (*import_resolution).target_for_namespace(namespace) { - None => { - // Not found; continue. - debug!("(resolving item in lexical scope) found \ - import resolution, but not in namespace {:?}", - namespace); - } - Some(target) => { - debug!("(resolving item in lexical scope) using \ - import resolution"); - // track used imports and extern crates as well - self.used_imports.insert((import_resolution.id(namespace), namespace)); - match target.target_module.def_id.get() { - Some(DefId{krate: kid, ..}) => { self.used_crates.insert(kid); }, - _ => {} + { + let import_resolutions = module_.import_resolutions.borrow(); + match import_resolutions.find(&name.name) { + None => { + // Not found; continue. + } + Some(import_resolution) => { + match (*import_resolution).target_for_namespace(namespace) { + None => { + // Not found; continue. + debug!("(resolving item in lexical scope) found \ + import resolution, but not in namespace {:?}", + namespace); + } + Some(target) => { + debug!("(resolving item in lexical scope) using \ + import resolution"); + // track used imports and extern crates as well + self.used_imports.insert(( + import_resolution.id(namespace), + namespace)); + match target.target_module.def_id.get() { + Some(DefId{krate: kid, ..}) => { + self.used_crates.insert(kid); + } + _ => {} + } + return Success((target, false)); } - return Success((target, false)); } } } @@ -3265,11 +3303,25 @@ impl<'a> Resolver<'a> { // Search for external modules. if namespace == TypeNS { - match module_.external_module_children.borrow().find_copy(&name.name) { + let name_bindings; + { + let external_module_children = module_.external_module_children + .borrow(); + { + match external_module_children.find_copy(&name.name) { + None => name_bindings = None, + Some(module) => { + name_bindings = Some(Rc::new( + Resolver::create_name_bindings_from_module( + module))); + debug!("lower name bindings succeeded"); + } + } + } + } + match name_bindings { None => {} - Some(module) => { - let name_bindings = - Rc::new(Resolver::create_name_bindings_from_module(module)); + Some(name_bindings) => { debug!("lower name bindings succeeded"); return Success((Target::new(module_, name_bindings, @@ -3493,17 +3545,20 @@ impl<'a> Resolver<'a> { // First, check the direct children of the module. self.populate_module_if_necessary(&module_); - match module_.children.borrow().find(&name) { - Some(name_bindings) - if name_bindings.defined_in_namespace(namespace) => { - debug!("(resolving name in module) found node as child"); - return Success((Target::new(module_.clone(), - name_bindings.clone(), - false), - false)); - } - Some(_) | None => { - // Continue. + { + let children = module_.children.borrow(); + match children.find(&name) { + Some(name_bindings) + if name_bindings.defined_in_namespace(namespace) => { + debug!("(resolving name in module) found node as child"); + return Success((Target::new(module_.clone(), + name_bindings.clone(), + false), + false)); + } + Some(_) | None => { + // Continue. + } } } @@ -3516,49 +3571,66 @@ impl<'a> Resolver<'a> { } // Check the list of resolved imports. - match module_.import_resolutions.borrow().find(&name) { - Some(import_resolution) if allow_private_imports || - import_resolution.is_public => { - - if import_resolution.is_public && - import_resolution.outstanding_references != 0 { - debug!("(resolving name in module) import \ - unresolved; bailing out"); - return Indeterminate; - } - match import_resolution.target_for_namespace(namespace) { - None => { - debug!("(resolving name in module) name found, \ - but not in namespace {:?}", - namespace); + { + let import_resolutions = module_.import_resolutions.borrow(); + match import_resolutions.find(&name) { + Some(import_resolution) if allow_private_imports || + import_resolution.is_public => { + + if import_resolution.is_public && + import_resolution.outstanding_references != 0 { + debug!("(resolving name in module) import \ + unresolved; bailing out"); + return Indeterminate; } - Some(target) => { - debug!("(resolving name in module) resolved to \ - import"); - // track used imports and extern crates as well - self.used_imports.insert((import_resolution.id(namespace), namespace)); - match target.target_module.def_id.get() { - Some(DefId{krate: kid, ..}) => { self.used_crates.insert(kid); }, - _ => {} + match import_resolution.target_for_namespace(namespace) { + None => { + debug!("(resolving name in module) name found, \ + but not in namespace {:?}", + namespace); + } + Some(target) => { + debug!("(resolving name in module) resolved to \ + import"); + // track used imports and extern crates as well + self.used_imports.insert( + (import_resolution.id(namespace), namespace)); + match target.target_module.def_id.get() { + Some(DefId{krate: kid, ..}) => { + self.used_crates.insert(kid); + }, + _ => {} + } + return Success((target, true)); } - return Success((target, true)); } } + Some(..) | None => {} // Continue. } - Some(..) | None => {} // Continue. } // Finally, search through external children. if namespace == TypeNS { - match module_.external_module_children.borrow().find_copy(&name) { + let name_bindings; + { + let external_module_children = + module_.external_module_children.borrow(); + match external_module_children.find_copy(&name) { + None => name_bindings = None, + Some(module) => { + name_bindings = Some(Rc::new( + Resolver::create_name_bindings_from_module( + module))); + } + } + } + match name_bindings { None => {} - Some(module) => { - let name_bindings = - Rc::new(Resolver::create_name_bindings_from_module(module)); + Some(name_bindings) => { return Success((Target::new(module_, name_bindings, false), - false)); + false)) } } } @@ -3571,39 +3643,49 @@ impl<'a> Resolver<'a> { fn report_unresolved_imports(&mut self, module_: Rc) { let index = module_.resolved_import_count.get(); - let imports = module_.imports.borrow(); - let import_count = imports.len(); - if index != import_count { - let sn = self.session - .codemap() - .span_to_snippet(imports.get(index).span) - .unwrap(); - if sn.as_slice().contains("::") { - self.resolve_error(imports.get(index).span, - "unresolved import"); - } else { - let err = format!("unresolved import (maybe you meant `{}::*`?)", - sn.as_slice().slice(0, sn.len())); - self.resolve_error(imports.get(index).span, err.as_slice()); + { + let imports = module_.imports.borrow(); + let import_count = imports.len(); + if index != import_count { + let sn = self.session + .codemap() + .span_to_snippet(imports.get(index).span) + .unwrap(); + if sn.as_slice().contains("::") { + self.resolve_error(imports.get(index).span, + "unresolved import"); + } else { + let err = format!("unresolved import (maybe you meant \ + `{}::*`?)", + sn.as_slice().slice(0, sn.len())); + self.resolve_error(imports.get(index).span, + err.as_slice()); + } } } // Descend into children and anonymous children. self.populate_module_if_necessary(&module_); - for (_, child_node) in module_.children.borrow().iter() { - match child_node.get_module_if_available() { - None => { - // Continue. - } - Some(child_module) => { - self.report_unresolved_imports(child_module); + { + let children = module_.children.borrow(); + for (_, child_node) in children.iter() { + match child_node.get_module_if_available() { + None => { + // Continue. + } + Some(child_module) => { + self.report_unresolved_imports(child_module); + } } } } - for (_, module_) in module_.anonymous_children.borrow().iter() { - self.report_unresolved_imports(module_.clone()); + { + let anonymous_children = module_.anonymous_children.borrow(); + for (_, module_) in anonymous_children.iter() { + self.report_unresolved_imports(module_.clone()); + } } } @@ -3651,19 +3733,25 @@ impl<'a> Resolver<'a> { self.record_exports_for_module(&*module_); self.populate_module_if_necessary(&module_); - for (_, child_name_bindings) in module_.children.borrow().iter() { - match child_name_bindings.get_module_if_available() { - None => { - // Nothing to do. - } - Some(child_module) => { - self.record_exports_for_module_subtree(child_module); + { + let children = module_.children.borrow(); + for (_, child_name_bindings) in children.iter() { + match child_name_bindings.get_module_if_available() { + None => { + // Nothing to do. + } + Some(child_module) => { + self.record_exports_for_module_subtree(child_module); + } } } } - for (_, child_module) in module_.anonymous_children.borrow().iter() { - self.record_exports_for_module_subtree(child_module.clone()); + { + let anonymous_children = module_.anonymous_children.borrow(); + for (_, child_module) in anonymous_children.iter() { + self.record_exports_for_module_subtree(child_module.clone()); + } } } @@ -4001,9 +4089,13 @@ impl<'a> Resolver<'a> { // plain insert (no renaming, types are not currently hygienic....) let name = self.type_self_name; - self_type_rib.bindings.borrow_mut() - .insert(name, DlDef(DefSelfTy(item.id))); - self.type_ribs.borrow_mut().push(self_type_rib); + { + self_type_rib.bindings.borrow_mut() + .insert(name, DlDef(DefSelfTy(item.id))); + } + { + self.type_ribs.borrow_mut().push(self_type_rib); + } // Create a new rib for the trait-wide type parameters. self.with_type_parameter_rib(HasTypeParameters(generics, @@ -4171,17 +4263,25 @@ impl<'a> Resolver<'a> { } fn with_label_rib(&mut self, f: |&mut Resolver|) { - self.label_ribs.borrow_mut().push(Rib::new(NormalRibKind)); + { + self.label_ribs.borrow_mut().push(Rib::new(NormalRibKind)); + } f(self); - self.label_ribs.borrow_mut().pop(); + { + self.label_ribs.borrow_mut().pop(); + } } fn with_constant_rib(&mut self, f: |&mut Resolver|) { - self.value_ribs.borrow_mut().push(Rib::new(ConstantItemRibKind)); - self.type_ribs.borrow_mut().push(Rib::new(ConstantItemRibKind)); + { + self.value_ribs.borrow_mut().push(Rib::new(ConstantItemRibKind)); + self.type_ribs.borrow_mut().push(Rib::new(ConstantItemRibKind)); + } f(self); - self.type_ribs.borrow_mut().pop(); - self.value_ribs.borrow_mut().pop(); + { + self.type_ribs.borrow_mut().pop(); + self.value_ribs.borrow_mut().pop(); + } } fn resolve_function(&mut self, @@ -4190,12 +4290,16 @@ impl<'a> Resolver<'a> { type_parameters: TypeParameters, block: &Block) { // Create a value rib for the function. - let function_value_rib = Rib::new(rib_kind); - self.value_ribs.borrow_mut().push(function_value_rib); + { + let function_value_rib = Rib::new(rib_kind); + self.value_ribs.borrow_mut().push(function_value_rib); + } // Create a label rib for the function. - let function_label_rib = Rib::new(rib_kind); - self.label_ribs.borrow_mut().push(function_label_rib); + { + let function_label_rib = Rib::new(rib_kind); + self.label_ribs.borrow_mut().push(function_label_rib); + } // If this function has type parameters, add them now. self.with_type_parameter_rib(type_parameters, |this| { @@ -4621,7 +4725,9 @@ impl<'a> Resolver<'a> { } fn resolve_arm(&mut self, arm: &Arm) { - self.value_ribs.borrow_mut().push(Rib::new(NormalRibKind)); + { + self.value_ribs.borrow_mut().push(Rib::new(NormalRibKind)); + } let mut bindings_list = HashMap::new(); for pattern in arm.pats.iter() { @@ -4635,21 +4741,28 @@ impl<'a> Resolver<'a> { visit::walk_expr_opt(self, &arm.guard); self.resolve_expr(&*arm.body); - self.value_ribs.borrow_mut().pop(); + { + self.value_ribs.borrow_mut().pop(); + } } fn resolve_block(&mut self, block: &Block) { debug!("(resolving block) entering block"); - self.value_ribs.borrow_mut().push(Rib::new(NormalRibKind)); + { + self.value_ribs.borrow_mut().push(Rib::new(NormalRibKind)); + } // Move down in the graph, if there's an anonymous module rooted here. let orig_module = self.current_module.clone(); - match orig_module.anonymous_children.borrow().find(&block.id) { - None => { /* Nothing to do. */ } - Some(anonymous_module) => { - debug!("(resolving block) found anonymous module, moving \ - down"); - self.current_module = anonymous_module.clone(); + { + let anonymous_children = orig_module.anonymous_children.borrow(); + match anonymous_children.find(&block.id) { + None => { /* Nothing to do. */ } + Some(anonymous_module) => { + debug!("(resolving block) found anonymous module, moving \ + down"); + self.current_module = anonymous_module.clone(); + } } } @@ -4659,7 +4772,9 @@ impl<'a> Resolver<'a> { // Move back up. self.current_module = orig_module; - self.value_ribs.borrow_mut().pop(); + { + self.value_ribs.borrow_mut().pop(); + } debug!("(resolving block) leaving block"); } @@ -5503,14 +5618,16 @@ impl<'a> Resolver<'a> { let mut maybes: Vec = Vec::new(); let mut values: Vec = Vec::new(); - let mut j = this.value_ribs.borrow().len(); - while j != 0 { - j -= 1; + { let value_ribs = this.value_ribs.borrow(); - let bindings = value_ribs.get(j).bindings.borrow(); - for (&k, _) in bindings.iter() { - maybes.push(token::get_name(k)); - values.push(uint::MAX); + let mut j = value_ribs.len(); + while j != 0 { + j -= 1; + let bindings = value_ribs.get(j).bindings.borrow(); + for (&k, _) in bindings.iter() { + maybes.push(token::get_name(k)); + values.push(uint::MAX); + } } } @@ -5598,16 +5715,19 @@ impl<'a> Resolver<'a> { } _ => { let mut method_scope = false; - self.value_ribs.borrow().iter().rev().all(|rib| { - let res = match *rib { - Rib { bindings: _, kind: MethodRibKind(_, _) } => true, - Rib { bindings: _, kind: ItemRibKind } => false, - _ => return true, // Keep advancing - }; - - method_scope = res; - false // Stop advancing - }); + { + let value_ribs = self.value_ribs.borrow(); + value_ribs.iter().rev().all(|rib| { + let res = match *rib { + Rib { bindings: _, kind: MethodRibKind(_, _) } => true, + Rib { bindings: _, kind: ItemRibKind } => false, + _ => return true, // Keep advancing + }; + + method_scope = res; + false // Stop advancing + }); + } if method_scope && token::get_name(self.self_name).get() == wrong_name.as_slice() { @@ -5699,7 +5819,10 @@ impl<'a> Resolver<'a> { ExprForLoop(ref pattern, ref head, ref body, optional_label) => { self.resolve_expr(&**head); - self.value_ribs.borrow_mut().push(Rib::new(NormalRibKind)); + { + let mut value_ribs = self.value_ribs.borrow_mut(); + value_ribs.push(Rib::new(NormalRibKind)); + } self.resolve_pattern(&**pattern, LocalIrrefutableMode, @@ -5735,23 +5858,35 @@ impl<'a> Resolver<'a> { ExprBreak(Some(label)) | ExprAgain(Some(label)) => { let renamed = mtwt::resolve(label); - match self.search_ribs(self.label_ribs.borrow().as_slice(), - renamed, expr.span) { - None => { - self.resolve_error( - expr.span, - format!("use of undeclared label `{}`", - token::get_ident(label)).as_slice()) + let def; + { + let label_ribs = self.label_ribs.borrow(); + def = match self.search_ribs(label_ribs.as_slice(), + renamed, + expr.span) { + None => { + self.resolve_error( + expr.span, + format!("use of undeclared label `{}`", + token::get_ident(label)).as_slice()); + None + } + Some(DlDef(def @ DefLabel(_))) => { + // Since this def is a label, it is never read. + Some(def) + } + Some(_) => { + self.session.span_bug(expr.span, + "label wasn't mapped to a \ + label def!") + } } - Some(DlDef(def @ DefLabel(_))) => { - // Since this def is a label, it is never read. + } + match def { + Some(def) => { self.record_def(expr.id, (def, LastMod(AllPublic))) } - Some(_) => { - self.session.span_bug(expr.span, - "label wasn't mapped to a \ - label def!") - } + None => {} } } @@ -5818,7 +5953,8 @@ impl<'a> Resolver<'a> { { let trait_item_map = self.trait_item_map.borrow(); - for (_, child_names) in search_module.children.borrow().iter() { + let children = search_module.children.borrow(); + for (_, child_names) in children.iter() { let def = match child_names.def_for_namespace(TypeNS) { Some(def) => def, None => continue @@ -6061,27 +6197,32 @@ impl<'a> Resolver<'a> { } debug!("Import resolutions:"); - let import_resolutions = module_.import_resolutions.borrow(); - for (&name, import_resolution) in import_resolutions.iter() { - let value_repr; - match import_resolution.target_for_namespace(ValueNS) { - None => { value_repr = "".to_string(); } - Some(_) => { - value_repr = " value:?".to_string(); - // FIXME #4954 + { + let import_resolutions = module_.import_resolutions.borrow(); + for (&name, import_resolution) in import_resolutions.iter() { + let value_repr; + match import_resolution.target_for_namespace(ValueNS) { + None => { value_repr = "".to_string(); } + Some(_) => { + value_repr = " value:?".to_string(); + // FIXME #4954 + } } - } - let type_repr; - match import_resolution.target_for_namespace(TypeNS) { - None => { type_repr = "".to_string(); } - Some(_) => { - type_repr = " type:?".to_string(); - // FIXME #4954 + let type_repr; + match import_resolution.target_for_namespace(TypeNS) { + None => { type_repr = "".to_string(); } + Some(_) => { + type_repr = " type:?".to_string(); + // FIXME #4954 + } } - } - debug!("* {}:{}{}", token::get_name(name), value_repr, type_repr); + debug!("* {}:{}{}", + token::get_name(name), + value_repr, + type_repr); + } } } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 0716d8dbf27f4..278e2ba97d12d 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -3160,7 +3160,11 @@ pub fn trans_crate<'tcx>(analysis: CrateAnalysis<'tcx>) llcx: shared_ccx.metadata_llcx(), llmod: shared_ccx.metadata_llmod(), }; - let formats = shared_ccx.tcx().dependency_formats.borrow().clone(); + let formats; + { + let dependency_formats = shared_ccx.tcx().dependency_formats.borrow(); + formats = dependency_formats.clone() + } let no_builtins = attr::contains_name(krate.attrs.as_slice(), "no_builtins"); let translation = CrateTranslation { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 21ba2189414c2..02ae90a264ee7 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -1292,7 +1292,9 @@ pub fn create_function_debug_context(cx: &CrateContext, fn_metadata, &mut *fn_debug_context.scope_map.borrow_mut()); - return FunctionDebugContext { repr: FunctionDebugContext(fn_debug_context) }; + return FunctionDebugContext { + repr: FunctionDebugContext(fn_debug_context) + }; fn get_function_signature(cx: &CrateContext, fn_ast_id: ast::NodeId, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d0b94cb3abb8b..2127d8d2ded22 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -676,20 +676,23 @@ pub enum Region { // some enclosing function signature. ReLateBound(/* binder_id */ ast::NodeId, BoundRegion), + /// Static data that has an "infinite" lifetime. Top in the region lattice. + ReStatic, + /// When checking a function body, the types of all arguments and so forth /// that refer to bound region parameters are modified to refer to free /// region parameters. ReFree(FreeRegion), + /// The lifetime of the current function. This is a lifetime that is + /// conceptually shorter than free region variables but longer than the + /// function block. This is needed only when checking destructors for + /// safety. + ReFunction, + /// A concrete region naming some expression within the current function. ReScope(NodeId), - /// Static data that has an "infinite" lifetime. Top in the region lattice. - ReStatic, - - /// A region variable. Should not exist after typeck. - ReInfer(InferRegion), - /// Empty lifetime is for data that is never accessed. /// Bottom in the region lattice. We treat ReEmpty somewhat /// specially; at least right now, we do not generate instances of @@ -698,6 +701,9 @@ pub enum Region { /// The only way to get an instance of ReEmpty is to have a region /// variable with no constraints. ReEmpty, + + /// A region variable. Should not exist after typeck. + ReInfer(InferRegion), } /** @@ -4725,9 +4731,12 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t { fn tcx(&self) -> &ctxt<'tcx> { let TypeNormalizer(c) = *self; c } fn fold_ty(&mut self, t: ty::t) -> ty::t { - match self.tcx().normalized_cache.borrow().find_copy(&t) { - None => {} - Some(u) => return u + { + let normalized_cache = self.tcx().normalized_cache.borrow(); + match normalized_cache.find_copy(&t) { + None => {} + Some(u) => return u + } } let t_norm = ty_fold::super_fold_ty(self, t); @@ -5136,7 +5145,8 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { ReLateBound(..) | ReFree(..) | ReScope(..) | - ReInfer(..) => { + ReInfer(..) | + ReFunction => { tcx.sess.bug("non-static region found when hashing a type") } } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 45ffddf3fe80e..7e0acaaa12edc 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -122,6 +122,7 @@ use middle::def; use middle::def::{DefArg, DefBinding, DefLocal, DefUpvar}; use middle::freevars; use middle::mem_categorization as mc; +use middle::subst::{ErasedRegions, NonerasedRegions}; use middle::ty::{ReScope}; use middle::ty; use middle::typeck::astconv::AstConv; @@ -213,6 +214,9 @@ pub struct Rcx<'a, 'tcx: 'a> { // id of innermost fn or loop repeating_scope: ast::NodeId, + + /// Breadcrumbs used by the destructor checker. + breadcrumbs: Vec, } /// When entering a function, we can derive relationships from the @@ -263,9 +267,12 @@ fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { impl<'a, 'tcx> Rcx<'a, 'tcx> { pub fn new(fcx: &'a FnCtxt<'a, 'tcx>, initial_repeating_scope: ast::NodeId) -> Rcx<'a, 'tcx> { - Rcx { fcx: fcx, - repeating_scope: initial_repeating_scope, - region_param_pairs: Vec::new() } + Rcx { + fcx: fcx, + repeating_scope: initial_repeating_scope, + breadcrumbs: Vec::new(), + region_param_pairs: Vec::new(), + } } pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { @@ -571,6 +578,10 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) { type_of_node_must_outlive( rcx, infer::BindingTypeIsNotValidAtDecl(span), id, var_region); + + let var_scope = tcx.region_maps.var_scope(id); + let typ = rcx.resolve_node_type(id); + check_safety_of_destructor_if_necessary(rcx, typ, span, var_scope); }) } @@ -619,8 +630,26 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { */ _ => {} } + + // If necessary, constrain destructors in the unadjusted form of this + // expression. + let head_cmt = { + let mc = mc::MemCategorizationContext::new(rcx); + ignore_err!(mc.cat_expr_unadjusted(expr)) + }; + check_safety_of_rvalue_destructor_if_necessary(rcx, + head_cmt, + expr.span); } + // If necessary, constrain destructors in this expression. This will be + // the adjusted form if there is an adjustment. + let head_cmt = { + let mc = mc::MemCategorizationContext::new(rcx); + ignore_err!(mc.cat_expr(expr)) + }; + check_safety_of_rvalue_destructor_if_necessary(rcx, head_cmt, expr.span); + match expr.node { ast::ExprCall(ref callee, ref args) => { if has_method_map { @@ -1216,6 +1245,45 @@ pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx, minimum_lifetime, maximum_lifetime) } +fn check_safety_of_destructor_if_necessary(rcx: &mut Rcx, + typ: ty::t, + span: Span, + scope: ast::NodeId) { + iterate_over_potentially_unsafe_regions_in_type( + rcx, + typ, + span, + scope, + false) +} + +fn check_safety_of_rvalue_destructor_if_necessary(rcx: &mut Rcx, + cmt: mc::cmt, + span: Span) { + match cmt.cat { + mc::cat_rvalue(region) => { + match region { + ty::ReScope(rvalue_scope) => { + let typ = rcx.resolve_type(cmt.ty); + check_safety_of_destructor_if_necessary(rcx, + typ, + span, + rvalue_scope); + } + ty::ReStatic => {} + region => { + rcx.tcx() + .sess + .span_bug(span, + format!("unexpected rvalue region in rvalue \ + destructor safety checking: `{}`", + region.repr(rcx.tcx())).as_slice()); + } + } + } + _ => {} + } +} fn constrain_index(rcx: &mut Rcx, index_expr: &ast::Expr, @@ -1918,3 +1986,153 @@ fn param_must_outlive(rcx: &Rcx, region, param_bounds); } + +fn constrain_region_for_destructor_safety(rcx: &mut Rcx, + region: ty::Region, + inner_scope: ast::NodeId, + span: Span) { + // Ignore bound regions. + match region { + ty::ReEarlyBound(..) | ty::ReLateBound(..) => return, + ty::ReFunction | ty::ReFree(_) | ty::ReScope(_) | ty::ReStatic | + ty::ReInfer(_) | ty::ReEmpty => {} + } + + // Get the parent scope. + let parent_inner_region = + match rcx.fcx.tcx().region_maps.opt_encl_scope(inner_scope) { + Some(parent_inner_scope) => ty::ReScope(parent_inner_scope), + None => ty::ReFunction, + }; + + rcx.fcx.mk_subr(infer::SafeDestructor(span), + parent_inner_region, + region); +} + +fn iterate_over_potentially_unsafe_regions_in_type( + rcx: &mut Rcx, + typ: ty::t, + span: Span, + scope: ast::NodeId, + reachable_by_destructor: bool) { + ty::maybe_walk_ty(typ, |typ| { + // Avoid recursing forever. + let type_id = ty::type_id(typ); + if !rcx.breadcrumbs.contains(&type_id) { + rcx.breadcrumbs.push(type_id); + + let keep_going = match ty::get(typ).sty { + ty::ty_struct(structure_id, ref substitutions) => { + let reachable_by_destructor = + reachable_by_destructor || + ty::has_dtor(rcx.fcx.tcx(), structure_id); + + let fields = + ty::lookup_struct_fields(rcx.fcx.tcx(), + structure_id); + for field in fields.iter() { + let field_type = + ty::lookup_field_type(rcx.fcx.tcx(), + structure_id, + field.id, + substitutions); + iterate_over_potentially_unsafe_regions_in_type( + rcx, + field_type, + span, + scope, + reachable_by_destructor) + } + + false + } + ty::ty_enum(enumeration_id, ref substitutions) => { + let reachable_by_destructor = reachable_by_destructor || + ty::has_dtor(rcx.fcx.tcx(), enumeration_id); + + let all_variant_info = + ty::substd_enum_variants(rcx.fcx.tcx(), + enumeration_id, + substitutions); + for variant_info in all_variant_info.iter() { + for argument_type in variant_info.args.iter() { + iterate_over_potentially_unsafe_regions_in_type( + rcx, + *argument_type, + span, + scope, + reachable_by_destructor) + } + } + + false + } + ty::ty_rptr(region, _) => { + if reachable_by_destructor { + constrain_region_for_destructor_safety(rcx, + region, + scope, + span) + } + // Don't recurse, since references do not own their + // contents. + false + } + ty::ty_unboxed_closure(..) => { + true + } + ty::ty_closure(ref closure_type) => { + match closure_type.store { + ty::RegionTraitStore(region, _) => { + if reachable_by_destructor { + constrain_region_for_destructor_safety(rcx, + region, + scope, + span) + } + } + ty::UniqTraitStore => {} + } + // Don't recurse, since closures don't own the types + // appearing in their signature. + false + } + ty::ty_trait(ref trait_type) => { + if reachable_by_destructor { + match trait_type.substs.regions { + NonerasedRegions(ref regions) => { + for region in regions.iter() { + constrain_region_for_destructor_safety( + rcx, + *region, + scope, + span) + } + } + ErasedRegions => {} + } + } + true + } + ty::ty_ptr(_) | ty::ty_box(_) | ty::ty_bare_fn(_) => { + // Don't recurse, since pointers, boxes, and bare + // functions don't own instances of the types appearing + // within them. + false + } + ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | + ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | + ty::ty_uniq(_) | ty::ty_str | ty::ty_vec(..) | ty::ty_tup(_) | + ty::ty_param(_) | ty::ty_infer(_) | ty::ty_open(_) | + ty::ty_err => true, + }; + + rcx.breadcrumbs.pop(); + keep_going + } else { + false + } + }); +} + diff --git a/src/librustc/middle/typeck/coherence/mod.rs b/src/librustc/middle/typeck/coherence/mod.rs index 76c5cab234f37..bd5aa394caeac 100644 --- a/src/librustc/middle/typeck/coherence/mod.rs +++ b/src/librustc/middle/typeck/coherence/mod.rs @@ -424,49 +424,54 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { }; let impl_items = tcx.impl_items.borrow(); - let trait_impls = match tcx.trait_impls.borrow().find_copy(&drop_trait) { + let trait_impls = tcx.trait_impls.borrow(); + let trait_impls = match trait_impls.find_copy(&drop_trait) { None => return, // No types with (new-style) dtors present. Some(found_impls) => found_impls }; - for &impl_did in trait_impls.borrow().iter() { - let items = impl_items.get(&impl_did); - if items.len() < 1 { - // We'll error out later. For now, just don't ICE. - continue; - } - let method_def_id = *items.get(0); - - let self_type = self.get_self_type_for_implementation(impl_did); - match ty::get(self_type.ty).sty { - ty::ty_enum(type_def_id, _) | - ty::ty_struct(type_def_id, _) | - ty::ty_unboxed_closure(type_def_id, _) => { - tcx.destructor_for_type - .borrow_mut() - .insert(type_def_id, method_def_id.def_id()); - tcx.destructors - .borrow_mut() - .insert(method_def_id.def_id()); + { + let trait_impls = trait_impls.borrow(); + for &impl_did in trait_impls.iter() { + let items = impl_items.get(&impl_did); + if items.len() < 1 { + // We'll error out later. For now, just don't ICE. + continue; } - _ => { - // Destructors only work on nominal types. - if impl_did.krate == ast::LOCAL_CRATE { - { - match tcx.map.find(impl_did.node) { - Some(ast_map::NodeItem(item)) => { - span_err!(tcx.sess, item.span, E0120, - "the Drop trait may only be implemented on structures"); - } - _ => { - tcx.sess.bug("didn't find impl in ast \ - map"); + let method_def_id = *items.get(0); + + let self_type = self.get_self_type_for_implementation(impl_did); + match ty::get(self_type.ty).sty { + ty::ty_enum(type_def_id, _) | + ty::ty_struct(type_def_id, _) | + ty::ty_unboxed_closure(type_def_id, _) => { + tcx.destructor_for_type + .borrow_mut() + .insert(type_def_id, method_def_id.def_id()); + tcx.destructors + .borrow_mut() + .insert(method_def_id.def_id()); + } + _ => { + // Destructors only work on nominal types. + if impl_did.krate == ast::LOCAL_CRATE { + { + match tcx.map.find(impl_did.node) { + Some(ast_map::NodeItem(item)) => { + span_err!(tcx.sess, item.span, E0120, + "the Drop trait may only be \ + implemented on structures"); + } + _ => { + tcx.sess.bug("didn't find impl in \ + ast map"); + } } } + } else { + tcx.sess.bug("found external impl of Drop trait \ + on something other than a struct"); } - } else { - tcx.sess.bug("found external impl of Drop trait on \ - something other than a struct"); } } } diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 4f663df58824a..733ef955d7927 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -749,6 +749,22 @@ impl<'a, 'tcx> ErrorReporting for InferCtxt<'a, 'tcx> { sup, ""); } + infer::SafeDestructor(span) => { + self.tcx.sess.span_err( + span, + "unsafe use of destructor: destructor might be called \ + while references are dead"); + note_and_explain_region( + self.tcx, + "superregion: ", + sup, + ""); + note_and_explain_region( + self.tcx, + "subregion: ", + sub, + ""); + } infer::BindingTypeIsNotValidAtDecl(span) => { self.tcx.sess.span_err( span, @@ -1640,6 +1656,12 @@ impl<'a, 'tcx> ErrorReportingHelpers for InferCtxt<'a, 'tcx> { format!("...so that the declared lifetime parameter bounds \ are satisfied").as_slice()); } + infer::SafeDestructor(span) => { + self.tcx.sess.span_note( + span, + "...so that references are valid when the destructor \ + runs") + } } } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index db90593b5b36b..186ea19362bdd 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -225,6 +225,9 @@ pub enum SubregionOrigin { // Managed data cannot contain borrowed pointers. Managed(Span), + + // Region constraint arriving from destructor safety + SafeDestructor(Span), } /// Reasons to create a region inference variable @@ -1046,6 +1049,7 @@ impl SubregionOrigin { AddrOf(a) => a, AutoBorrow(a) => a, Managed(a) => a, + SafeDestructor(a) => a, } } } @@ -1119,6 +1123,7 @@ impl Repr for SubregionOrigin { AddrOf(a) => format!("AddrOf({})", a.repr(tcx)), AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)), Managed(a) => format!("Managed({})", a.repr(tcx)), + SafeDestructor(a) => format!("SafeDestructor({})", a.repr(tcx)), } } } diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 7e61c254a656b..aa2c0fdf64222 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -14,7 +14,8 @@ use middle::ty; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; -use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; +use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, ReFunction}; +use middle::ty::{BrFresh}; use middle::typeck::infer::cres; use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin, TypeTrace}; use middle::typeck::infer; @@ -777,6 +778,18 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { self.lub_free_regions(a_fr, b_fr) } + (ReFree(ref fr), ReFunction) | (ReFunction, ReFree(ref fr)) => { + // Free regions outlive the function region. + ReFree(*fr) + } + + (ReFunction, ReScope(_)) | (ReScope(_), ReFunction) => { + // The function region outlives all scopes. + ReFunction + } + + (ReFunction, ReFunction) => ReFunction, + // For these types, we cannot define any additional // relationship: (ReInfer(ReSkolemized(..)), _) | @@ -874,6 +887,18 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { self.glb_free_regions(a_fr, b_fr) } + (ReFree(_), ReFunction) | (ReFunction, ReFree(_)) => { + // Function regions don't live as long as free regions. + Ok(ReFunction) + } + + (ReFunction, ReScope(s)) | (ReScope(s), ReFunction) => { + // Scope regions don't live as long as function regions. + Ok(ReScope(s)) + } + + (ReFunction, ReFunction) => Ok(ReFunction), + // For these types, we cannot define any additional // relationship: (ReInfer(ReSkolemized(..)), _) | diff --git a/src/librustc/middle/typeck/infer/skolemize.rs b/src/librustc/middle/typeck/infer/skolemize.rs index e1d48407f2e43..87fc6c29c6b07 100644 --- a/src/librustc/middle/typeck/infer/skolemize.rs +++ b/src/librustc/middle/typeck/infer/skolemize.rs @@ -98,6 +98,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> { ty::ReFree(_) | ty::ReScope(_) | ty::ReInfer(_) | + ty::ReFunction | ty::ReEmpty => { // replace all free regions with 'static ty::ReStatic diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 547fbce573bcc..8b96be4b0d50a 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -903,7 +903,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::ReFree(..) | ty::ReScope(..) | ty::ReInfer(..) | - ty::ReEmpty => { + ty::ReFunction | ty::ReEmpty => { // We don't expect to see anything but 'static or bound // regions when visiting member types or method types. self.tcx() diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index be4a1c95e5550..b2781bf39aad7 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -14,8 +14,8 @@ use middle::subst::{VecPerParamSpace,Subst}; use middle::subst; use middle::ty::{BoundRegion, BrAnon, BrNamed}; use middle::ty::{ReEarlyBound, BrFresh, ctxt}; -use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty}; -use middle::ty::{ReSkolemized, ReVar}; +use middle::ty::{ReEmpty, ReFree, ReFunction, ReScope, ReInfer, ReStatic}; +use middle::ty::{ReSkolemized, ReVar, Region}; use middle::ty::{mt, t, ParamTy}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure}; @@ -140,6 +140,8 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) } } + ReFunction => { ("the lifetime of the function".to_string(), None) } + ReStatic => { ("the static lifetime".to_string(), None) } ReEmpty => { ("the empty lifetime".to_string(), None) } @@ -214,6 +216,7 @@ pub fn region_to_string(cx: &ctxt, prefix: &str, space: bool, region: Region) -> bound_region_to_string(cx, prefix, space, br) } ty::ReInfer(ReVar(_)) => prefix.to_string(), + ty::ReFunction => format!("{}'{}", prefix, space_str), ty::ReStatic => format!("{}'static{}", prefix, space_str), ty::ReEmpty => format!("{}'{}", prefix, space_str), } @@ -792,6 +795,10 @@ impl Repr for ty::Region { format!("ReScope({})", id) } + ty::ReFunction => { + "ReStatic".to_string() + } + ty::ReStatic => { "ReStatic".to_string() } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e6fcbbe9b6ff3..056b4136e8d64 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -458,9 +458,26 @@ impl Clean for ast::TyParam { } impl Clean for ty::TypeParameterDef { +<<<<<<< HEAD fn clean(&self, cx: &DocContext) -> TyParam { cx.external_typarams.borrow_mut().as_mut().unwrap() .insert(self.def_id, self.ident.clean(cx)); +======= + fn clean(&self) -> TyParam { + { + let cx = get_cx(); + { + let mut external_typarams = cx.external_typarams.borrow_mut(); + { + let external_typarams = external_typarams.get_mut_ref(); + { + external_typarams.insert(self.def_id, + self.ident.clean()); + } + } + } + } +>>>>>>> librustc: Require lifetimes within the types of values with destructors TyParam { name: self.ident.clean(cx), did: self.def_id, @@ -635,7 +652,8 @@ impl Clean> for ty::Region { ty::ReFree(..) | ty::ReScope(..) | ty::ReInfer(..) | - ty::ReEmpty(..) => None + ty::ReEmpty(..) | + ty::ReFunction => None } } } @@ -1284,7 +1302,23 @@ impl Clean for ty::t { }; let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(), substs); +<<<<<<< HEAD cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind)); +======= + { + let cx = get_cx(); + { + let mut external_paths = cx.external_paths + .borrow_mut(); + { + let external_paths = external_paths.get_mut_ref(); + { + external_paths.insert(did, (fqn, kind)); + } + } + } + } +>>>>>>> librustc: Require lifetimes within the types of values with destructors ResolvedPath { path: path, typarams: None, @@ -2134,7 +2168,15 @@ fn lang_struct(cx: &DocContext, did: Option, let fqn: Vec = fqn.move_iter().map(|i| { i.to_string() }).collect(); - cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeStruct)); + { + let mut external_paths = cx.external_paths.borrow_mut(); + { + let external_paths = external_paths.get_mut_ref(); + { + external_paths.insert(did, (fqn, TypeStruct)); + } + } + } ResolvedPath { typarams: None, did: did, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index ddb4b994ca38e..4551f69e9e5e3 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -157,13 +157,16 @@ pub fn run_core(libs: Vec, cfgs: Vec, externs: Externs, v.clean(&ctxt) }; - let external_paths = ctxt.external_paths.borrow_mut().take(); - *analysis.external_paths.borrow_mut() = external_paths; - let map = ctxt.external_traits.borrow_mut().take(); - *analysis.external_traits.borrow_mut() = map; - let map = ctxt.external_typarams.borrow_mut().take(); - *analysis.external_typarams.borrow_mut() = map; - let map = ctxt.inlined.borrow_mut().take(); - *analysis.inlined.borrow_mut() = map; + { + let external_paths = ctxt.external_paths.borrow_mut().take(); + *analysis.external_paths.borrow_mut() = external_paths; + let map = ctxt.external_traits.borrow_mut().take(); + *analysis.external_traits.borrow_mut() = map; + let map = ctxt.external_typarams.borrow_mut().take(); + *analysis.external_typarams.borrow_mut() = map; + let map = ctxt.inlined.borrow_mut().take(); + *analysis.inlined.borrow_mut() = map; + } + (krate, analysis) } diff --git a/src/librustrt/exclusive.rs b/src/librustrt/exclusive.rs index e5de2d195ebd6..5972012ad508e 100644 --- a/src/librustrt/exclusive.rs +++ b/src/librustrt/exclusive.rs @@ -49,12 +49,14 @@ impl Exclusive { /// This method is unsafe due to many of the same reasons that the /// NativeMutex itself is unsafe. pub unsafe fn lock<'a>(&'a self) -> ExclusiveGuard<'a, T> { - let guard = self.lock.lock(); - let data = &mut *self.data.get(); - - ExclusiveGuard { - _data: data, - _guard: guard, + { + let guard = self.lock.lock(); + let data = &mut *self.data.get(); + + ExclusiveGuard { + _data: data, + _guard: guard, + } } } } diff --git a/src/librustrt/local_data.rs b/src/librustrt/local_data.rs index c71f86bb063b6..465b1cf1092f0 100644 --- a/src/librustrt/local_data.rs +++ b/src/librustrt/local_data.rs @@ -121,20 +121,22 @@ struct TLDValueBox { unsafe fn get_local_map<'a>() -> Option<&'a mut Map> { if !Local::exists(None::) { return None } - let task: *mut Task = Local::unsafe_borrow(); - match &mut (*task).storage { - // If the at_exit function is already set, then we just need to take - // a loan out on the TLD map stored inside - &LocalStorage(Some(ref mut map_ptr)) => { - return Some(map_ptr); - } - // If this is the first time we've accessed TLD, perform similar - // actions to the oldsched way of doing things. - &LocalStorage(ref mut slot) => { - *slot = Some(TreeMap::new()); - match *slot { - Some(ref mut map_ptr) => { return Some(map_ptr) } - None => fail!("unreachable code"), + { + let task: *mut Task = Local::unsafe_borrow(); + match &mut (*task).storage { + // If the at_exit function is already set, then we just need to + // take a loan out on the TLD map stored inside + &LocalStorage(Some(ref mut map_ptr)) => { + return Some(map_ptr); + } + // If this is the first time we've accessed TLD, perform similar + // actions to the oldsched way of doing things. + &LocalStorage(ref mut slot) => { + *slot = Some(TreeMap::new()); + match *slot { + Some(ref mut map_ptr) => { return Some(map_ptr) } + None => fail!("unreachable code"), + } } } } diff --git a/src/librustrt/local_heap.rs b/src/librustrt/local_heap.rs index 273505c416a3c..19b17f3bb0bba 100644 --- a/src/librustrt/local_heap.rs +++ b/src/librustrt/local_heap.rs @@ -296,12 +296,14 @@ pub unsafe fn local_malloc_(drop_glue: fn(*mut u8), size: uint, pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *mut u8 { // FIXME: Unsafe borrow for speed. Lame. - let task: Option<*mut Task> = Local::try_unsafe_borrow(); - match task { - Some(task) => { - (*task).heap.alloc(drop_glue, size, align) as *mut u8 + { + let task: Option<*mut Task> = Local::try_unsafe_borrow(); + match task { + Some(task) => { + (*task).heap.alloc(drop_glue, size, align) as *mut u8 + } + None => rtabort!("local malloc outside of task") } - None => rtabort!("local malloc outside of task") } } @@ -318,12 +320,14 @@ pub unsafe fn local_free_(ptr: *mut u8) { #[inline] pub unsafe fn local_free(ptr: *mut u8) { // FIXME: Unsafe borrow for speed. Lame. - let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow(); - match task_ptr { - Some(task) => { - (*task).heap.free(ptr as *mut Box) + { + let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow(); + match task_ptr { + Some(task) => { + (*task).heap.free(ptr as *mut Box) + } + None => rtabort!("local free outside of task") } - None => rtabort!("local free outside of task") } } diff --git a/src/librustrt/rtio.rs b/src/librustrt/rtio.rs index 1afd88edbc287..e93ea2a1909dc 100644 --- a/src/librustrt/rtio.rs +++ b/src/librustrt/rtio.rs @@ -148,15 +148,20 @@ impl<'a> LocalIo<'a> { // // In order to get around this, we just transmute a copy out of the task // in order to have what is likely a static lifetime (bad). - let mut t: Box = match Local::try_take() { - Some(t) => t, - None => return None, - }; - let ret = t.local_io().map(|t| { - unsafe { mem::transmute_copy(&t) } - }); - Local::put(t); - return ret; + { + let mut t: Box = match Local::try_take() { + Some(t) => t, + None => return None, + }; + let ret: Option>; + unsafe { + ret = t.local_io().map(|t| mem::transmute_copy(&t)); + } + Local::put(t); + unsafe { + return mem::transmute(ret); + } + } } pub fn maybe_raise(f: |io: &mut IoFactory| -> IoResult) diff --git a/src/librustrt/task.rs b/src/librustrt/task.rs index 3d42b91fef17e..e225f5e914f3b 100644 --- a/src/librustrt/task.rs +++ b/src/librustrt/task.rs @@ -234,10 +234,12 @@ impl Task { // After running the closure given return the task back out if it ran // successfully, or clean up the task if it failed. - let task: Box = Local::take(); - match result { - Ok(()) => task, - Err(cause) => { task.cleanup(Err(cause)) } + { + let task: Box = Local::take(); + match result { + Ok(()) => task, + Err(cause) => { task.cleanup(Err(cause)) } + } } } @@ -263,88 +265,90 @@ impl Task { /// done being processed. It is assumed that TLD and the local heap have /// already been destroyed and/or annihilated. fn cleanup(self: Box, result: Result) -> Box { - // The first thing to do when cleaning up is to deallocate our local - // resources, such as TLD and GC data. - // - // FIXME: there are a number of problems with this code - // - // 1. If any TLD object fails destruction, then all of TLD will leak. - // This appears to be a consequence of #14875. - // - // 2. Failing during GC annihilation aborts the runtime #14876. - // - // 3. Setting a TLD key while destroying TLD or while destroying GC will - // abort the runtime #14807. - // - // 4. Invoking GC in GC destructors will abort the runtime #6996. - // - // 5. The order of destruction of TLD and GC matters, but either way is - // susceptible to leaks (see 3/4) #8302. - // - // That being said, there are a few upshots to this code - // - // 1. If TLD destruction fails, heap destruction will be attempted. - // There is a test for this at fail-during-tld-destroy.rs. Sadly the - // other way can't be tested due to point 2 above. Note that we must - // immortalize the heap first because if any deallocations are - // attempted while TLD is being dropped it will attempt to free the - // allocation from the wrong heap (because the current one has been - // replaced). - // - // 2. One failure in destruction is tolerable, so long as the task - // didn't originally fail while it was running. - // - // And with all that in mind, we attempt to clean things up! - let mut task = self.run(|| { - let mut task = Local::borrow(None::); - let tld = { - let &LocalStorage(ref mut optmap) = &mut task.storage; - optmap.take() - }; - let mut heap = mem::replace(&mut task.heap, LocalHeap::new()); - unsafe { heap.immortalize() } - drop(task); - - // First, destroy task-local storage. This may run user dtors. - drop(tld); - - // Destroy remaining boxes. Also may run user dtors. - drop(heap); - }); - - // If the above `run` block failed, then it must be the case that the - // task had previously succeeded. This also means that the code below - // was recursively run via the `run` method invoking this method. In - // this case, we just make sure the world is as we thought, and return. - if task.is_destroyed() { - rtassert!(result.is_ok()) - return task - } + { + // The first thing to do when cleaning up is to deallocate our local + // resources, such as TLD and GC data. + // + // FIXME: there are a number of problems with this code + // + // 1. If any TLD object fails destruction, then all of TLD will leak. + // This appears to be a consequence of #14875. + // + // 2. Failing during GC annihilation aborts the runtime #14876. + // + // 3. Setting a TLD key while destroying TLD or while destroying GC will + // abort the runtime #14807. + // + // 4. Invoking GC in GC destructors will abort the runtime #6996. + // + // 5. The order of destruction of TLD and GC matters, but either way is + // susceptible to leaks (see 3/4) #8302. + // + // That being said, there are a few upshots to this code + // + // 1. If TLD destruction fails, heap destruction will be attempted. + // There is a test for this at fail-during-tld-destroy.rs. Sadly the + // other way can't be tested due to point 2 above. Note that we must + // immortalize the heap first because if any deallocations are + // attempted while TLD is being dropped it will attempt to free the + // allocation from the wrong heap (because the current one has been + // replaced). + // + // 2. One failure in destruction is tolerable, so long as the task + // didn't originally fail while it was running. + // + // And with all that in mind, we attempt to clean things up! + let mut task = self.run(|| { + let mut task = Local::borrow(None::); + let tld = { + let &LocalStorage(ref mut optmap) = &mut task.storage; + optmap.take() + }; + let mut heap = mem::replace(&mut task.heap, LocalHeap::new()); + unsafe { heap.immortalize() } + drop(task); + + // First, destroy task-local storage. This may run user dtors. + drop(tld); + + // Destroy remaining boxes. Also may run user dtors. + drop(heap); + }); + + // If the above `run` block failed, then it must be the case that the + // task had previously succeeded. This also means that the code below + // was recursively run via the `run` method invoking this method. In + // this case, we just make sure the world is as we thought, and return. + if task.is_destroyed() { + rtassert!(result.is_ok()) + return task + } - // After taking care of the data above, we need to transmit the result - // of this task. - let what_to_do = task.death.on_exit.take(); - Local::put(task); + // After taking care of the data above, we need to transmit the result + // of this task. + let what_to_do = task.death.on_exit.take(); + Local::put(task); + + // FIXME: this is running in a seriously constrained context. If this + // allocates GC or allocates TLD then it will likely abort the + // runtime. Similarly, if this fails, this will also likely abort + // the runtime. + // + // This closure is currently limited to a channel send via the + // standard library's task interface, but this needs + // reconsideration to whether it's a reasonable thing to let a + // task to do or not. + match what_to_do { + Some(f) => { f(result) } + None => { drop(result) } + } - // FIXME: this is running in a seriously constrained context. If this - // allocates GC or allocates TLD then it will likely abort the - // runtime. Similarly, if this fails, this will also likely abort - // the runtime. - // - // This closure is currently limited to a channel send via the - // standard library's task interface, but this needs - // reconsideration to whether it's a reasonable thing to let a - // task to do or not. - match what_to_do { - Some(f) => { f(result) } - None => { drop(result) } + // Now that we're done, we remove the task from TLS and flag it for + // destruction. + let mut task: Box = Local::take(); + task.state = Destroyed; + return task; } - - // Now that we're done, we remove the task from TLS and flag it for - // destruction. - let mut task: Box = Local::take(); - task.state = Destroyed; - return task; } /// Queries whether this can be destroyed or not. diff --git a/src/librustrt/unwind.rs b/src/librustrt/unwind.rs index fbbc1a08fd951..3f660a3acbe0f 100644 --- a/src/librustrt/unwind.rs +++ b/src/librustrt/unwind.rs @@ -574,8 +574,8 @@ fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> let (file, line) = *file_line; f(&*msg, file, line); } - } - }; + }; + } // Now that we've run all the necessary unwind callbacks, we actually // perform the unwinding. If we don't have a task, then it's time to die @@ -599,7 +599,7 @@ fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> // requires the task. We need a handle to its unwinder, however, so after // this we unsafely extract it and continue along. Local::put(task); - rust_fail(msg); + rust_fail(msg) } /// Register a callback to be invoked when a task unwinds. diff --git a/src/libsync/comm/sync.rs b/src/libsync/comm/sync.rs index 528a15cf6d765..02e4d5a56a375 100644 --- a/src/libsync/comm/sync.rs +++ b/src/libsync/comm/sync.rs @@ -68,7 +68,7 @@ struct State { /// This is only relevant in the 0-buffer case. This obviously cannot be /// safely constructed, but it's guaranteed to always have a valid pointer /// value. - canceled: Option<&'static mut bool>, + canceled: Option<*mut bool>, } /// Possible flavors of tasks who can be blocked on this channel. @@ -182,7 +182,9 @@ impl Packet { NoneBlocked if state.cap == 0 => { let mut canceled = false; assert!(state.canceled.is_none()); - state.canceled = Some(unsafe { mem::transmute(&mut canceled) }); + state.canceled = Some(unsafe { + mem::transmute::<&mut bool,*mut bool>(&mut canceled) + }); wait(&mut state.blocker, BlockedSender, &self.lock); if canceled {Err(state.buf.dequeue())} else {Ok(())} } @@ -347,7 +349,9 @@ impl Packet { let waiter = match mem::replace(&mut state.blocker, NoneBlocked) { NoneBlocked => None, BlockedSender(task) => { - *state.canceled.take().unwrap() = true; + unsafe { + *state.canceled.take().unwrap() = true; + } Some(task) } BlockedReceiver(..) => unreachable!(), diff --git a/src/libsync/one.rs b/src/libsync/one.rs index 4594345d2a3f6..fbf3bdff2d769 100644 --- a/src/libsync/one.rs +++ b/src/libsync/one.rs @@ -105,13 +105,15 @@ impl Once { // If the count is negative, then someone else finished the job, // otherwise we run the job and record how many people will try to grab // this lock - let guard = self.mutex.lock(); - if self.cnt.load(atomic::SeqCst) > 0 { - f(); - let prev = self.cnt.swap(int::MIN, atomic::SeqCst); - self.lock_cnt.store(prev, atomic::SeqCst); + { + let guard = self.mutex.lock(); + if self.cnt.load(atomic::SeqCst) > 0 { + f(); + let prev = self.cnt.swap(int::MIN, atomic::SeqCst); + self.lock_cnt.store(prev, atomic::SeqCst); + } + drop(guard); } - drop(guard); // Last one out cleans up after everyone else, no leaks! if self.lock_cnt.fetch_add(-1, atomic::SeqCst) == 1 { diff --git a/src/libsync/raw.rs b/src/libsync/raw.rs index b259eb7e579ec..93c40228e2ee9 100644 --- a/src/libsync/raw.rs +++ b/src/libsync/raw.rs @@ -122,9 +122,12 @@ impl Sem { } unsafe fn with(&self, f: |&mut SemInner|) { - let _g = self.lock.lock(); - // This &mut is safe because, due to the lock, we are the only one who can touch the data - f(&mut *self.inner.get()) + { + let _g = self.lock.lock(); + // This &mut is safe because, due to the lock, we are the only one + // who can touch the data + f(&mut *self.inner.get()) + } } pub fn acquire(&self) { @@ -498,12 +501,17 @@ impl RWLock { /// when dropped. Calls to 'read' from other tasks may run concurrently with /// this one. pub fn read<'a>(&'a self) -> RWLockReadGuard<'a> { - let _guard = self.order_lock.access(); - let old_count = self.read_count.fetch_add(1, atomic::Acquire); - if old_count == 0 { - self.access_lock.acquire(); + { + let order_lock = &self.order_lock; + let _guard = order_lock.access(); + let old_count = self.read_count.fetch_add(1, atomic::Acquire); + if old_count == 0 { + self.access_lock.acquire(); + } + RWLockReadGuard { + lock: self, + } } - RWLockReadGuard { lock: self } } /// Acquire a write-lock, returning an RAII guard that will unlock the lock @@ -527,8 +535,10 @@ impl RWLock { /// drop(read); /// ``` pub fn write<'a>(&'a self) -> RWLockWriteGuard<'a> { - let _g = self.order_lock.access(); - self.access_lock.acquire(); + { + let _g = self.order_lock.access(); + self.access_lock.acquire(); + } // It's important to thread our order lock into the condvar, so that // when a cond.wait() wakes up, it uses it while reacquiring the diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 2f30108c27bd1..b764577a9cf78 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -513,14 +513,17 @@ impl CodeMap { let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos); let line = a + 1u; // Line numbers start at 1 let chpos = self.bytepos_to_file_charpos(pos); - let linebpos = *f.lines.borrow().get(a); - let linechpos = self.bytepos_to_file_charpos(linebpos); - debug!("byte pos {} is on the line at byte pos {}", - pos, linebpos); - debug!("char pos {} is on the line at char pos {}", - chpos, linechpos); - debug!("byte is on line: {}", line); - assert!(chpos >= linechpos); + let linechpos; + { + let linebpos = *f.lines.borrow().get(a); + linechpos = self.bytepos_to_file_charpos(linebpos); + debug!("byte pos {} is on the line at byte pos {}", + pos, linebpos); + debug!("char pos {} is on the line at char pos {}", + chpos, linechpos); + debug!("byte is on line: {}", line); + assert!(chpos >= linechpos); + } Loc { file: f, line: line, diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index 2c94db5296750..e9fcba6c4d0c8 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -168,7 +168,10 @@ fn with_resolve_table_mut(op: |&mut ResolveTable| -> T) -> T { None => { let ts = Rc::new(RefCell::new(HashMap::new())); resolve_table_key.replace(Some(ts.clone())); - op(&mut *ts.borrow_mut()) + { + let mut tsb = ts.borrow_mut(); + op(&mut *tsb) + } } } } @@ -257,9 +260,12 @@ fn marksof_internal(ctxt: SyntaxContext, /// FAILS when outside is not a mark. pub fn outer_mark(ctxt: SyntaxContext) -> Mrk { with_sctable(|sctable| { - match *sctable.table.borrow().get(ctxt as uint) { - Mark(mrk, _) => mrk, - _ => fail!("can't retrieve outer mark when outside is not a mark") + { + let table = sctable.table.borrow(); + match *table.get(ctxt as uint) { + Mark(mrk, _) => mrk, + _ => fail!("can't retrieve outer mark when outside is not a mark") + } } }) } diff --git a/src/test/compile-fail/destructor-restrictions.rs b/src/test/compile-fail/destructor-restrictions.rs new file mode 100644 index 0000000000000..02887d18a681b --- /dev/null +++ b/src/test/compile-fail/destructor-restrictions.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests the new destructor semantics. + +use std::cell::RefCell; + +fn main() { + let b = { + let a = box RefCell::new(4i); + *a.borrow() + 1i //~ ERROR `*a` does not live long enough + }; + println!("{}", b); +}