Skip to content

Commit 1b9a16c

Browse files
committed
librustc: Require lifetimes within the types of values with destructors
to have strictly greater lifetime than the values themselves. Additionally, remove `#[unsafe_destructor]` in favor of these new restrictions. This broke a fair amount of code that had to do with `RefCell`s. We will probably need to do some work to improve the resulting ergonomics. Most code that broke looked like: match foo.bar.borrow().baz { ... } use_foo(&mut foo); Change this code to: { let bar = foo.bar.borrow(); match bar.baz { ... } } use_foo(&mut foo); This fixes an important memory safety hole relating to destructors, represented by issue rust-lang#8861. [breaking-change]
1 parent 828e075 commit 1b9a16c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1160
-645
lines changed

src/libcollections/treemap.rs

+19-17
Original file line numberDiff line numberDiff line change
@@ -1084,27 +1084,29 @@ impl<T: Ord> Set<T> for TreeSet<T> {
10841084
}
10851085

10861086
fn is_subset(&self, other: &TreeSet<T>) -> bool {
1087-
let mut x = self.iter();
1088-
let mut y = other.iter();
1089-
let mut a = x.next();
1090-
let mut b = y.next();
1091-
while a.is_some() {
1092-
if b.is_none() {
1093-
return false;
1094-
}
1087+
{
1088+
let mut x = self.iter();
1089+
let mut y = other.iter();
1090+
let mut a = x.next();
1091+
let mut b = y.next();
1092+
while a.is_some() {
1093+
if b.is_none() {
1094+
return false;
1095+
}
10951096

1096-
let a1 = a.unwrap();
1097-
let b1 = b.unwrap();
1097+
let a1 = a.unwrap();
1098+
let b1 = b.unwrap();
10981099

1099-
match b1.cmp(a1) {
1100-
Less => (),
1101-
Greater => return false,
1102-
Equal => a = x.next(),
1103-
}
1100+
match b1.cmp(a1) {
1101+
Less => (),
1102+
Greater => return false,
1103+
Equal => a = x.next(),
1104+
}
11041105

1105-
b = y.next();
1106+
b = y.next();
1107+
}
1108+
true
11061109
}
1107-
true
11081110
}
11091111
}
11101112

src/libcore/cell.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,11 @@ impl<T> RefCell<T> {
310310

311311
#[unstable = "waiting for `Clone` to become stable"]
312312
impl<T: Clone> Clone for RefCell<T> {
313-
fn clone(&self) -> RefCell<T> {
314-
RefCell::new(self.borrow().clone())
313+
fn clone<'a>(&'a self) -> RefCell<T> {
314+
{
315+
let borrowed: Ref<'a,T> = self.borrow();
316+
RefCell::new(borrowed.clone())
317+
}
315318
}
316319
}
317320

src/libcore/finally.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,22 @@ impl<T> Finally<T> for fn() -> T {
9090
* })
9191
* ```
9292
*/
93-
pub fn try_finally<T,U,R>(mutate: &mut T,
94-
drop: U,
95-
try_fn: |&mut T, U| -> R,
96-
finally_fn: |&mut T|)
97-
-> R {
98-
let f = Finallyalizer {
99-
mutate: mutate,
100-
dtor: finally_fn,
101-
};
102-
try_fn(&mut *f.mutate, drop)
93+
pub fn try_finally<'a,
94+
T,
95+
U,
96+
R>(
97+
mutate: &'a mut T,
98+
drop: U,
99+
try_fn: |&mut T, U| -> R,
100+
finally_fn: |&mut T|:'a)
101+
-> R {
102+
{
103+
let f: Finallyalizer<'a,T> = Finallyalizer {
104+
mutate: mutate,
105+
dtor: finally_fn,
106+
};
107+
try_fn(&mut *f.mutate, drop)
108+
}
103109
}
104110

105111
struct Finallyalizer<'a,A:'a> {

src/libgreen/basic.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,13 @@ impl BasicLoop {
6161

6262
fn remote_work(&mut self) {
6363
let messages = unsafe {
64-
mem::replace(&mut *self.messages.lock(), Vec::new())
64+
let lock = &mut *self.messages.lock();
65+
mem::replace(lock, Vec::new())
6566
};
66-
for message in messages.move_iter() {
67-
self.message(message);
67+
{
68+
for message in messages.move_iter() {
69+
self.message(message);
70+
}
6871
}
6972
}
7073

src/librustc/driver/session.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,10 @@ pub fn build_session_(sopts: config::Options,
258258
recursion_limit: Cell::new(64),
259259
};
260260

261-
sess.lint_store.borrow_mut().register_builtin(Some(&sess));
261+
{
262+
sess.lint_store.borrow_mut().register_builtin(Some(&sess));
263+
}
264+
262265
sess
263266
}
264267

src/librustc/front/feature_gate.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,8 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
244244
"unsafe_destructor") {
245245
self.gate_feature("unsafe_destructor",
246246
i.span,
247-
"`#[unsafe_destructor]` allows too \
248-
many unsafe patterns and may be \
249-
removed in the future");
247+
"`#[unsafe_destructor]` does nothing \
248+
anymore")
250249
}
251250
}
252251

src/librustc/metadata/tydecode.rs

+3
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region {
318318
't' => {
319319
ty::ReStatic
320320
}
321+
'n' => {
322+
ty::ReFunction
323+
}
321324
'e' => {
322325
ty::ReStatic
323326
}

src/librustc/metadata/tyencode.rs

+3
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
149149
ty::ReScope(nid) => {
150150
mywrite!(w, "s{}|", nid);
151151
}
152+
ty::ReFunction => {
153+
mywrite!(w, "n");
154+
}
152155
ty::ReStatic => {
153156
mywrite!(w, "t");
154157
}

src/librustc/middle/astencode.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ impl tr for ty::Region {
490490
ty::ReScope(id) => {
491491
ty::ReScope(dcx.tr_id(id))
492492
}
493-
ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) => {
493+
ty::ReEmpty | ty::ReStatic | ty::ReInfer(..) | ty::ReFunction => {
494494
*self
495495
}
496496
ty::ReFree(ref fr) => {

src/librustc/middle/borrowck/gather_loans/lifetime.rs

+1-30
Original file line numberDiff line numberDiff line change
@@ -163,36 +163,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
163163
164164
// See the SCOPE(LV) function in doc.rs
165165

166-
match cmt.cat {
167-
mc::cat_rvalue(temp_scope) => {
168-
temp_scope
169-
}
170-
mc::cat_upvar(..) |
171-
mc::cat_copied_upvar(_) => {
172-
ty::ReScope(self.item_scope_id)
173-
}
174-
mc::cat_static_item => {
175-
ty::ReStatic
176-
}
177-
mc::cat_local(local_id) |
178-
mc::cat_arg(local_id) => {
179-
ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id))
180-
}
181-
mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
182-
ty::ReStatic
183-
}
184-
mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) |
185-
mc::cat_deref(_, _, mc::Implicit(_, r)) => {
186-
r
187-
}
188-
mc::cat_downcast(ref cmt) |
189-
mc::cat_deref(ref cmt, _, mc::OwnedPtr) |
190-
mc::cat_deref(ref cmt, _, mc::GcPtr) |
191-
mc::cat_interior(ref cmt, _) |
192-
mc::cat_discr(ref cmt, _) => {
193-
self.scope(cmt)
194-
}
195-
}
166+
mc::scope(self.bccx.tcx, cmt, self.item_scope_id)
196167
}
197168

198169
fn report_error(&self, code: bckerr_code) {

src/librustc/middle/borrowck/gather_loans/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,12 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
275275
ty::ReScope(id) => id,
276276
ty::ReFree(ref fr) => fr.scope_id,
277277

278+
ty::ReFunction => {
279+
// For purposes of the borrow check, we can consider
280+
// this a loan for the outer function block.
281+
self.item_ub
282+
}
283+
278284
ty::ReStatic => {
279285
// If we get here, an error must have been
280286
// reported in

src/librustc/middle/expr_use_visitor.rs

+37-31
Original file line numberDiff line numberDiff line change
@@ -511,37 +511,41 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
511511
}
512512
}
513513
_ => {
514-
let overloaded_call_type =
515-
match self.tcx()
516-
.method_map
517-
.borrow()
518-
.find(&MethodCall::expr(call.id)) {
519-
Some(ref method_callee) => {
520-
OverloadedCallType::from_method_origin(
521-
self.tcx(),
522-
&method_callee.origin)
523-
}
524-
None => {
525-
self.tcx().sess.span_bug(
526-
callee.span,
527-
format!("unexpected callee type {}",
528-
callee_ty.repr(self.tcx())).as_slice())
529-
}
530-
};
531-
match overloaded_call_type {
532-
FnMutOverloadedCall => {
533-
self.borrow_expr(callee,
534-
ty::ReScope(call.id),
535-
ty::MutBorrow,
536-
ClosureInvocation);
514+
let overloaded_call_type;
515+
{
516+
let method_map = self.tcx().method_map.borrow();
517+
overloaded_call_type = match method_map.find(
518+
&MethodCall::expr(call.id)) {
519+
Some(ref method_callee) => {
520+
OverloadedCallType::from_method_origin(
521+
self.tcx(),
522+
&method_callee.origin)
523+
}
524+
None => {
525+
self.tcx().sess.span_bug(
526+
callee.span,
527+
format!("unexpected callee type {}",
528+
callee_ty.repr(self.tcx()))
529+
.as_slice())
530+
}
537531
}
538-
FnOverloadedCall => {
539-
self.borrow_expr(callee,
540-
ty::ReScope(call.id),
541-
ty::ImmBorrow,
542-
ClosureInvocation);
532+
}
533+
{
534+
match overloaded_call_type {
535+
FnMutOverloadedCall => {
536+
self.borrow_expr(callee,
537+
ty::ReScope(call.id),
538+
ty::MutBorrow,
539+
ClosureInvocation);
540+
}
541+
FnOverloadedCall => {
542+
self.borrow_expr(callee,
543+
ty::ReScope(call.id),
544+
ty::ImmBorrow,
545+
ClosureInvocation);
546+
}
547+
FnOnceOverloadedCall => self.consume_expr(callee),
543548
}
544-
FnOnceOverloadedCall => self.consume_expr(callee),
545549
}
546550
}
547551
}
@@ -933,8 +937,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
933937
// inferred by regionbk
934938
let upvar_id = ty::UpvarId { var_id: id_var,
935939
closure_expr_id: closure_expr.id };
936-
let upvar_borrow = self.tcx().upvar_borrow_map.borrow()
937-
.get_copy(&upvar_id);
940+
let upvar_borrow = {
941+
let upvar_borrow_map = self.tcx().upvar_borrow_map.borrow();
942+
upvar_borrow_map.get_copy(&upvar_id)
943+
};
938944

939945
self.delegate.borrow(closure_expr.id,
940946
closure_expr.span,

src/librustc/middle/kind.rs

-69
Original file line numberDiff line numberDiff line change
@@ -67,76 +67,7 @@ pub fn check_crate(tcx: &ty::ctxt) {
6767
tcx.sess.abort_if_errors();
6868
}
6969

70-
struct EmptySubstsFolder<'a, 'tcx: 'a> {
71-
tcx: &'a ty::ctxt<'tcx>
72-
}
73-
impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for EmptySubstsFolder<'a, 'tcx> {
74-
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
75-
self.tcx
76-
}
77-
fn fold_substs(&mut self, _: &subst::Substs) -> subst::Substs {
78-
subst::Substs::empty()
79-
}
80-
}
81-
82-
fn check_struct_safe_for_destructor(cx: &mut Context,
83-
span: Span,
84-
struct_did: DefId) {
85-
let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
86-
if !struct_tpt.generics.has_type_params(subst::TypeSpace)
87-
&& !struct_tpt.generics.has_region_params(subst::TypeSpace) {
88-
let mut folder = EmptySubstsFolder { tcx: cx.tcx };
89-
if !ty::type_is_sendable(cx.tcx, struct_tpt.ty.fold_with(&mut folder)) {
90-
span_err!(cx.tcx.sess, span, E0125,
91-
"cannot implement a destructor on a \
92-
structure or enumeration that does not satisfy Send");
93-
span_note!(cx.tcx.sess, span,
94-
"use \"#[unsafe_destructor]\" on the implementation \
95-
to force the compiler to allow this");
96-
}
97-
} else {
98-
span_err!(cx.tcx.sess, span, E0141,
99-
"cannot implement a destructor on a structure \
100-
with type parameters");
101-
span_note!(cx.tcx.sess, span,
102-
"use \"#[unsafe_destructor]\" on the implementation \
103-
to force the compiler to allow this");
104-
}
105-
}
106-
107-
fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_type: &Ty) {
108-
let ast_trait_def = *cx.tcx.def_map.borrow()
109-
.find(&trait_ref.ref_id)
110-
.expect("trait ref not in def map!");
111-
let trait_def_id = ast_trait_def.def_id();
112-
113-
// If this is a destructor, check kinds.
114-
if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) &&
115-
!attr::contains_name(it.attrs.as_slice(), "unsafe_destructor")
116-
{
117-
match self_type.node {
118-
TyPath(_, ref bounds, path_node_id) => {
119-
assert!(bounds.is_none());
120-
let struct_def = cx.tcx.def_map.borrow().get_copy(&path_node_id);
121-
let struct_did = struct_def.def_id();
122-
check_struct_safe_for_destructor(cx, self_type.span, struct_did);
123-
}
124-
_ => {
125-
cx.tcx.sess.span_bug(self_type.span,
126-
"the self type for the Drop trait impl is not a path");
127-
}
128-
}
129-
}
130-
}
131-
13270
fn check_item(cx: &mut Context, item: &Item) {
133-
match item.node {
134-
ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
135-
check_impl_of_trait(cx, item, trait_ref, &**self_type);
136-
}
137-
_ => {}
138-
}
139-
14071
visit::walk_item(cx, item)
14172
}
14273

0 commit comments

Comments
 (0)