Skip to content

Commit 6beb376

Browse files
committed
auto merge of #13686 : alexcrichton/rust/issue-12224, r=nikomatsakis
This alters the borrow checker's requirements on invoking closures from requiring an immutable borrow to requiring a unique immutable borrow. This means that it is illegal to invoke a closure through a `&` pointer because there is no guarantee that is not aliased. This does not mean that a closure is required to be in a mutable location, but rather a location which can be proven to be unique (often through a mutable pointer). For example, the following code is unsound and is no longer allowed: type Fn<'a> = ||:'a; fn call(f: |Fn|) { f(|| { f(|| {}) }); } fn main() { call(|a| { a(); }); } There is no replacement for this pattern. For all closures which are stored in structures, it was previously allowed to invoke the closure through `&self` but it now requires invocation through `&mut self`. The standard library has a good number of violations of this new rule, but the fixes will be separated into multiple breaking change commits. Closes #12224
2 parents b5dd3f0 + 823c7ee commit 6beb376

38 files changed

+360
-194
lines changed

src/libcollections/bitv.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ impl<'a> RandomAccessIterator<bool> for Bits<'a> {
632632
}
633633

634634
#[inline]
635-
fn idx(&self, index: uint) -> Option<bool> {
635+
fn idx(&mut self, index: uint) -> Option<bool> {
636636
if index >= self.indexable() {
637637
None
638638
} else {

src/libcollections/ringbuf.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
272272
fn indexable(&self) -> uint { self.rindex - self.index }
273273

274274
#[inline]
275-
fn idx(&self, j: uint) -> Option<&'a T> {
275+
fn idx(&mut self, j: uint) -> Option<&'a T> {
276276
if j >= self.indexable() {
277277
None
278278
} else {

src/libnum/bigint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ impl ToStrRadix for BigUint {
672672
s.push_str("0".repeat(l - ss.len()));
673673
s.push_str(ss);
674674
}
675-
s.as_slice().trim_left_chars(&'0').to_owned()
675+
s.as_slice().trim_left_chars('0').to_owned()
676676
}
677677
}
678678
}

src/librustc/front/config.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub fn strip_items(krate: ast::Crate,
4747
ctxt.fold_crate(krate)
4848
}
4949

50-
fn filter_view_item<'r>(cx: &Context, view_item: &'r ast::ViewItem)
50+
fn filter_view_item<'r>(cx: &mut Context, view_item: &'r ast::ViewItem)
5151
-> Option<&'r ast::ViewItem> {
5252
if view_item_in_cfg(cx, view_item) {
5353
Some(view_item)
@@ -72,7 +72,7 @@ fn fold_mod(cx: &mut Context, m: &ast::Mod) -> ast::Mod {
7272
}
7373
}
7474

75-
fn filter_foreign_item(cx: &Context, item: @ast::ForeignItem)
75+
fn filter_foreign_item(cx: &mut Context, item: @ast::ForeignItem)
7676
-> Option<@ast::ForeignItem> {
7777
if foreign_item_in_cfg(cx, item) {
7878
Some(item)
@@ -144,7 +144,7 @@ fn fold_item_underscore(cx: &mut Context, item: &ast::Item_) -> ast::Item_ {
144144
fold::noop_fold_item_underscore(&item, cx)
145145
}
146146

147-
fn fold_struct(cx: &Context, def: &ast::StructDef) -> @ast::StructDef {
147+
fn fold_struct(cx: &mut Context, def: &ast::StructDef) -> @ast::StructDef {
148148
let mut fields = def.fields.iter().map(|c| c.clone()).filter(|m| {
149149
(cx.in_cfg)(m.node.attrs.as_slice())
150150
});
@@ -156,7 +156,7 @@ fn fold_struct(cx: &Context, def: &ast::StructDef) -> @ast::StructDef {
156156
}
157157
}
158158

159-
fn retain_stmt(cx: &Context, stmt: @ast::Stmt) -> bool {
159+
fn retain_stmt(cx: &mut Context, stmt: @ast::Stmt) -> bool {
160160
match stmt.node {
161161
ast::StmtDecl(decl, _) => {
162162
match decl.node {
@@ -189,23 +189,23 @@ fn fold_block(cx: &mut Context, b: ast::P<ast::Block>) -> ast::P<ast::Block> {
189189
})
190190
}
191191

192-
fn item_in_cfg(cx: &Context, item: &ast::Item) -> bool {
192+
fn item_in_cfg(cx: &mut Context, item: &ast::Item) -> bool {
193193
return (cx.in_cfg)(item.attrs.as_slice());
194194
}
195195

196-
fn foreign_item_in_cfg(cx: &Context, item: &ast::ForeignItem) -> bool {
196+
fn foreign_item_in_cfg(cx: &mut Context, item: &ast::ForeignItem) -> bool {
197197
return (cx.in_cfg)(item.attrs.as_slice());
198198
}
199199

200-
fn view_item_in_cfg(cx: &Context, item: &ast::ViewItem) -> bool {
200+
fn view_item_in_cfg(cx: &mut Context, item: &ast::ViewItem) -> bool {
201201
return (cx.in_cfg)(item.attrs.as_slice());
202202
}
203203

204-
fn method_in_cfg(cx: &Context, meth: &ast::Method) -> bool {
204+
fn method_in_cfg(cx: &mut Context, meth: &ast::Method) -> bool {
205205
return (cx.in_cfg)(meth.attrs.as_slice());
206206
}
207207

208-
fn trait_method_in_cfg(cx: &Context, meth: &ast::TraitMethod) -> bool {
208+
fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitMethod) -> bool {
209209
match *meth {
210210
ast::Required(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
211211
ast::Provided(meth) => (cx.in_cfg)(meth.attrs.as_slice())

src/librustc/metadata/encoder.rs

+33-25
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub struct EncodeContext<'a> {
8484
pub non_inlineable_statics: &'a RefCell<NodeSet>,
8585
pub link_meta: &'a LinkMeta,
8686
pub cstore: &'a cstore::CStore,
87-
pub encode_inlined_item: EncodeInlinedItem<'a>,
87+
pub encode_inlined_item: RefCell<EncodeInlinedItem<'a>>,
8888
pub type_abbrevs: tyencode::abbrev_map,
8989
}
9090

@@ -765,8 +765,8 @@ fn encode_info_for_method(ecx: &EncodeContext,
765765
if num_params > 0u ||
766766
is_default_impl ||
767767
should_inline(ast_method.attrs.as_slice()) {
768-
(ecx.encode_inlined_item)(
769-
ecx, ebml_w, IIMethodRef(local_def(parent_id), false, ast_method));
768+
encode_inlined_item(ecx, ebml_w,
769+
IIMethodRef(local_def(parent_id), false, ast_method));
770770
} else {
771771
encode_symbol(ecx, ebml_w, m.def_id.node);
772772
}
@@ -775,6 +775,14 @@ fn encode_info_for_method(ecx: &EncodeContext,
775775
ebml_w.end_tag();
776776
}
777777

778+
fn encode_inlined_item(ecx: &EncodeContext,
779+
ebml_w: &mut Encoder,
780+
ii: InlinedItemRef) {
781+
let mut eii = ecx.encode_inlined_item.borrow_mut();
782+
let eii: &mut EncodeInlinedItem = &mut *eii;
783+
(*eii)(ecx, ebml_w, ii)
784+
}
785+
778786
fn style_fn_family(s: FnStyle) -> char {
779787
match s {
780788
UnsafeFn => 'u',
@@ -880,7 +888,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
880888
let inlineable = !ecx.non_inlineable_statics.borrow().contains(&item.id);
881889

882890
if inlineable {
883-
(ecx.encode_inlined_item)(ecx, ebml_w, IIItemRef(item));
891+
encode_inlined_item(ecx, ebml_w, IIItemRef(item));
884892
}
885893
encode_visibility(ebml_w, vis);
886894
ebml_w.end_tag();
@@ -896,7 +904,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
896904
encode_path(ebml_w, path);
897905
encode_attributes(ebml_w, item.attrs.as_slice());
898906
if tps_len > 0u || should_inline(item.attrs.as_slice()) {
899-
(ecx.encode_inlined_item)(ecx, ebml_w, IIItemRef(item));
907+
encode_inlined_item(ecx, ebml_w, IIItemRef(item));
900908
} else {
901909
encode_symbol(ecx, ebml_w, item.id);
902910
}
@@ -954,7 +962,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
954962
for v in (*enum_definition).variants.iter() {
955963
encode_variant_id(ebml_w, local_def(v.node.id));
956964
}
957-
(ecx.encode_inlined_item)(ecx, ebml_w, IIItemRef(item));
965+
encode_inlined_item(ecx, ebml_w, IIItemRef(item));
958966
encode_path(ebml_w, path);
959967

960968
// Encode inherent implementations for this enumeration.
@@ -1002,7 +1010,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
10021010
needs to know*/
10031011
encode_struct_fields(ebml_w, fields.as_slice(), def_id);
10041012

1005-
(ecx.encode_inlined_item)(ecx, ebml_w, IIItemRef(item));
1013+
encode_inlined_item(ecx, ebml_w, IIItemRef(item));
10061014

10071015
// Encode inherent implementations for this structure.
10081016
encode_inherent_implementations(ecx, ebml_w, def_id);
@@ -1175,8 +1183,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
11751183
encode_bounds_and_type(ebml_w, ecx, &tpt);
11761184
}
11771185
encode_method_sort(ebml_w, 'p');
1178-
(ecx.encode_inlined_item)(
1179-
ecx, ebml_w, IIMethodRef(def_id, true, m));
1186+
encode_inlined_item(ecx, ebml_w,
1187+
IIMethodRef(def_id, true, m));
11801188
}
11811189
}
11821190

@@ -1212,7 +1220,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
12121220
&lookup_item_type(ecx.tcx,local_def(nitem.id)));
12131221
encode_name(ebml_w, nitem.ident.name);
12141222
if abi == abi::RustIntrinsic {
1215-
(ecx.encode_inlined_item)(ecx, ebml_w, IIForeignRef(nitem));
1223+
encode_inlined_item(ecx, ebml_w, IIForeignRef(nitem));
12161224
} else {
12171225
encode_symbol(ecx, ebml_w, nitem.id);
12181226
}
@@ -1544,12 +1552,12 @@ fn encode_macro_registrar_fn(ecx: &EncodeContext, ebml_w: &mut Encoder) {
15441552
}
15451553
}
15461554

1547-
struct MacroDefVisitor<'a, 'b> {
1548-
ecx: &'a EncodeContext<'a>,
1549-
ebml_w: &'a mut Encoder<'b>
1555+
struct MacroDefVisitor<'a, 'b, 'c> {
1556+
ecx: &'a EncodeContext<'b>,
1557+
ebml_w: &'a mut Encoder<'c>
15501558
}
15511559

1552-
impl<'a, 'b> Visitor<()> for MacroDefVisitor<'a, 'b> {
1560+
impl<'a, 'b, 'c> Visitor<()> for MacroDefVisitor<'a, 'b, 'c> {
15531561
fn visit_item(&mut self, item: &Item, _: ()) {
15541562
match item.node {
15551563
ItemMac(..) => {
@@ -1565,9 +1573,9 @@ impl<'a, 'b> Visitor<()> for MacroDefVisitor<'a, 'b> {
15651573
}
15661574
}
15671575

1568-
fn encode_macro_defs(ecx: &EncodeContext,
1569-
krate: &Crate,
1570-
ebml_w: &mut Encoder) {
1576+
fn encode_macro_defs<'a>(ecx: &'a EncodeContext,
1577+
krate: &Crate,
1578+
ebml_w: &'a mut Encoder) {
15711579
ebml_w.start_tag(tag_exported_macros);
15721580
{
15731581
let mut visitor = MacroDefVisitor {
@@ -1579,12 +1587,12 @@ fn encode_macro_defs(ecx: &EncodeContext,
15791587
ebml_w.end_tag();
15801588
}
15811589

1582-
struct ImplVisitor<'a,'b> {
1583-
ecx: &'a EncodeContext<'a>,
1584-
ebml_w: &'a mut Encoder<'b>,
1590+
struct ImplVisitor<'a,'b,'c> {
1591+
ecx: &'a EncodeContext<'b>,
1592+
ebml_w: &'a mut Encoder<'c>,
15851593
}
15861594

1587-
impl<'a,'b> Visitor<()> for ImplVisitor<'a,'b> {
1595+
impl<'a,'b,'c> Visitor<()> for ImplVisitor<'a,'b,'c> {
15881596
fn visit_item(&mut self, item: &Item, _: ()) {
15891597
match item.node {
15901598
ItemImpl(_, Some(ref trait_ref), _, _) => {
@@ -1617,9 +1625,9 @@ impl<'a,'b> Visitor<()> for ImplVisitor<'a,'b> {
16171625
/// * Destructors (implementations of the Drop trait).
16181626
///
16191627
/// * Implementations of traits not defined in this crate.
1620-
fn encode_impls(ecx: &EncodeContext,
1621-
krate: &Crate,
1622-
ebml_w: &mut Encoder) {
1628+
fn encode_impls<'a>(ecx: &'a EncodeContext,
1629+
krate: &Crate,
1630+
ebml_w: &'a mut Encoder) {
16231631
ebml_w.start_tag(tag_impls);
16241632

16251633
{
@@ -1744,7 +1752,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
17441752
non_inlineable_statics: non_inlineable_statics,
17451753
link_meta: link_meta,
17461754
cstore: cstore,
1747-
encode_inlined_item: encode_inlined_item,
1755+
encode_inlined_item: RefCell::new(encode_inlined_item),
17481756
type_abbrevs: RefCell::new(HashMap::new()),
17491757
};
17501758

src/librustc/metadata/filesearch.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ impl<'a> FileSearch<'a> {
9292
match fs::readdir(lib_search_path) {
9393
Ok(files) => {
9494
let mut rslt = FileDoesntMatch;
95-
let is_rlib = |p: & &Path| {
95+
fn is_rlib(p: & &Path) -> bool {
9696
p.extension_str() == Some("rlib")
97-
};
97+
}
9898
// Reading metadata out of rlibs is faster, and if we find both
9999
// an rlib and a dylib we only read one of the files of
100100
// metadata, so in the name of speed, bring all rlib files to

src/librustc/middle/borrowck/check_loans.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ impl<'a> CheckLoanCtxt<'a> {
327327
self.bccx.loan_path_to_str(&*old_loan.loan_path))
328328
}
329329

330-
AddrOf | AutoRef | RefBinding => {
330+
AddrOf | AutoRef | RefBinding | ClosureInvocation => {
331331
format!("previous borrow of `{}` occurs here",
332332
self.bccx.loan_path_to_str(&*old_loan.loan_path))
333333
}

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

+20
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,26 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
292292
visit::walk_expr(this, ex, ());
293293
}
294294

295+
ast::ExprCall(f, _) => {
296+
let expr_ty = ty::expr_ty_adjusted(tcx, f);
297+
match ty::get(expr_ty).sty {
298+
ty::ty_closure(~ty::ClosureTy {
299+
store: ty::RegionTraitStore(..), ..
300+
}) => {
301+
let scope_r = ty::ReScope(ex.id);
302+
let base_cmt = this.bccx.cat_expr(f);
303+
this.guarantee_valid_kind(f.id,
304+
f.span,
305+
base_cmt,
306+
ty::UniqueImmBorrow,
307+
scope_r,
308+
ClosureInvocation);
309+
}
310+
_ => {}
311+
}
312+
visit::walk_expr(this, ex, ());
313+
}
314+
295315
_ => {
296316
visit::walk_expr(this, ex, ());
297317
}

src/librustc/middle/borrowck/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ pub enum LoanCause {
202202
AddrOf,
203203
AutoRef,
204204
RefBinding,
205+
ClosureInvocation,
205206
}
206207

207208
#[deriving(Eq, TotalEq, Hash)]
@@ -629,6 +630,10 @@ impl<'a> BorrowckCtxt<'a> {
629630
AddrOf | RefBinding | AutoRef => {
630631
format!("cannot borrow {} as mutable", descr)
631632
}
633+
ClosureInvocation => {
634+
self.tcx.sess.span_bug(err.span,
635+
"err_mutbl with a closure invocation");
636+
}
632637
}
633638
}
634639
err_out_of_root_scope(..) => {
@@ -677,6 +682,10 @@ impl<'a> BorrowckCtxt<'a> {
677682
BorrowViolation(RefBinding) => {
678683
"cannot borrow data mutably"
679684
}
685+
686+
BorrowViolation(ClosureInvocation) => {
687+
"closure invocation"
688+
}
680689
};
681690

682691
match cause {

src/librustc/middle/lint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@ fn check_item_non_camel_case_types(cx: &Context, it: &ast::Item) {
11641164
fn is_camel_case(ident: ast::Ident) -> bool {
11651165
let ident = token::get_ident(ident);
11661166
assert!(!ident.get().is_empty());
1167-
let ident = ident.get().trim_chars(&'_');
1167+
let ident = ident.get().trim_chars('_');
11681168

11691169
// start with a non-lowercase letter rather than non-uppercase
11701170
// ones (some scripts don't have a concept of upper/lowercase)

src/librustc/middle/privacy.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -1104,34 +1104,34 @@ impl<'a> SanePrivacyVisitor<'a> {
11041104
/// control over anything so this forbids any mention of any visibility
11051105
fn check_all_inherited(&self, item: &ast::Item) {
11061106
let tcx = self.tcx;
1107-
let check_inherited = |sp: Span, vis: ast::Visibility| {
1107+
fn check_inherited(tcx: &ty::ctxt, sp: Span, vis: ast::Visibility) {
11081108
if vis != ast::Inherited {
11091109
tcx.sess.span_err(sp, "visibility has no effect inside functions");
11101110
}
1111-
};
1111+
}
11121112
let check_struct = |def: &@ast::StructDef| {
11131113
for f in def.fields.iter() {
11141114
match f.node.kind {
1115-
ast::NamedField(_, p) => check_inherited(f.span, p),
1115+
ast::NamedField(_, p) => check_inherited(tcx, f.span, p),
11161116
ast::UnnamedField(..) => {}
11171117
}
11181118
}
11191119
};
1120-
check_inherited(item.span, item.vis);
1120+
check_inherited(tcx, item.span, item.vis);
11211121
match item.node {
11221122
ast::ItemImpl(_, _, _, ref methods) => {
11231123
for m in methods.iter() {
1124-
check_inherited(m.span, m.vis);
1124+
check_inherited(tcx, m.span, m.vis);
11251125
}
11261126
}
11271127
ast::ItemForeignMod(ref fm) => {
11281128
for i in fm.items.iter() {
1129-
check_inherited(i.span, i.vis);
1129+
check_inherited(tcx, i.span, i.vis);
11301130
}
11311131
}
11321132
ast::ItemEnum(ref def, _) => {
11331133
for v in def.variants.iter() {
1134-
check_inherited(v.span, v.node.vis);
1134+
check_inherited(tcx, v.span, v.node.vis);
11351135

11361136
match v.node.kind {
11371137
ast::StructVariantKind(ref s) => check_struct(s),
@@ -1146,7 +1146,8 @@ impl<'a> SanePrivacyVisitor<'a> {
11461146
for m in methods.iter() {
11471147
match *m {
11481148
ast::Required(..) => {}
1149-
ast::Provided(ref m) => check_inherited(m.span, m.vis),
1149+
ast::Provided(ref m) => check_inherited(tcx, m.span,
1150+
m.vis),
11501151
}
11511152
}
11521153
}

0 commit comments

Comments
 (0)