Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack closure soundness. #7363

Merged
merged 7 commits into from
Jun 29, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/libextra/fun_treemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ pub fn traverse<K, V: Copy>(m: Treemap<K, V>, f: &fn(&K, &V)) {
// matches to me, so I changed it. but that may be a
// de-optimization -- tjc
Node(@ref k, @ref v, left, right) => {
traverse(left, f);
traverse(left, |k,v| f(k,v));
f(k, v);
traverse(right, f);
traverse(right, |k,v| f(k,v));
}
}
}
4 changes: 2 additions & 2 deletions src/libextra/rope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ pub mod node {

pub fn loop_chars(node: @Node, it: &fn(c: char) -> bool) -> bool {
return loop_leaves(node,|leaf| {
leaf.content.slice(leaf.byte_offset, leaf.byte_len).iter().all(it)
leaf.content.slice(leaf.byte_offset, leaf.byte_len).iter().all(|c| it(c))
});
}

Expand All @@ -1101,7 +1101,7 @@ pub mod node {
loop {
match (*current) {
Leaf(x) => return it(x),
Concat(ref x) => if loop_leaves(x.left, it) { //non tail call
Concat(ref x) => if loop_leaves(x.left, |l| it(l)) { //non tail call
current = x.right; //tail call
} else {
return false;
Expand Down
9 changes: 5 additions & 4 deletions src/libextra/sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ pub fn merge_sort<T:Copy>(v: &[T], le: Le<T>) -> ~[T] {
let mid = v_len / 2 + begin;
let a = (begin, mid);
let b = (mid, end);
return merge(le, merge_sort_(v, a, le), merge_sort_(v, b, le));
return merge(|x,y| le(x,y), merge_sort_(v, a, |x,y| le(x,y)),
merge_sort_(v, b, |x,y| le(x,y)));
}

fn merge<T:Copy>(le: Le<T>, a: &[T], b: &[T]) -> ~[T] {
Expand Down Expand Up @@ -83,10 +84,10 @@ fn qsort<T>(arr: &mut [T], left: uint,
right: uint, compare_func: Le<T>) {
if right > left {
let pivot = (left + right) / 2u;
let new_pivot = part::<T>(arr, left, right, pivot, compare_func);
let new_pivot = part::<T>(arr, left, right, pivot, |x,y| compare_func(x,y));
if new_pivot != 0u {
// Need to do this check before recursing due to overflow
qsort::<T>(arr, left, new_pivot - 1u, compare_func);
qsort::<T>(arr, left, new_pivot - 1u, |x,y| compare_func(x,y));
}
qsort::<T>(arr, new_pivot + 1u, right, compare_func);
}
Expand Down Expand Up @@ -1202,7 +1203,7 @@ mod big_tests {

struct LVal<'self> {
val: uint,
key: &'self fn(@uint),
key: &'self fn:Copy(@uint),
}

#[unsafe_destructor]
Expand Down
12 changes: 7 additions & 5 deletions src/libextra/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,9 @@ impl RWlock {
(&self.order_lock).acquire();
do (&self.access_lock).access_waitqueue {
(&self.order_lock).release();
task::rekillable(blk)
do task::rekillable {
blk()
}
}
}
}
Expand Down Expand Up @@ -1182,12 +1184,12 @@ mod tests {
Write => x.write(blk),
Downgrade =>
do x.write_downgrade |mode| {
(&mode).write(blk);
do mode.write { blk() };
},
DowngradeRead =>
do x.write_downgrade |mode| {
let mode = x.downgrade(mode);
(&mode).read(blk);
do mode.read { blk() };
},
}
}
Expand Down Expand Up @@ -1340,10 +1342,10 @@ mod tests {
fn lock_cond(x: &RWlock, downgrade: bool, blk: &fn(c: &Condvar)) {
if downgrade {
do x.write_downgrade |mode| {
(&mode).write_cond(blk)
do mode.write_cond |c| { blk(c) }
}
} else {
x.write_cond(blk)
do x.write_cond |c| { blk(c) }
}
}
let x = ~RWlock();
Expand Down
6 changes: 3 additions & 3 deletions src/libextra/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ impl BenchHarness {

// Initial bench run to get ballpark figure.
let mut n = 1_u64;
self.bench_n(n, f);
self.bench_n(n, |x| f(x));

while n < 1_000_000_000 &&
self.ns_elapsed() < 1_000_000_000 {
Expand All @@ -694,7 +694,7 @@ impl BenchHarness {

n = u64::max(u64::min(n+n/2, 100*last), last+1);
n = round_up(n);
self.bench_n(n, f);
self.bench_n(n, |x| f(x));
}
}

Expand All @@ -714,7 +714,7 @@ impl BenchHarness {
magnitude * 2);

let samples = do vec::from_fn(n_samples) |_| {
self.bench_n(n_iter as u64, f);
self.bench_n(n_iter as u64, |x| f(x));
self.ns_per_iter() as f64
};

Expand Down
12 changes: 6 additions & 6 deletions src/libextra/treemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,14 +511,14 @@ impl<K: TotalOrd, V> TreeNode<K, V> {

fn each<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>,
f: &fn(&'r K, &'r V) -> bool) -> bool {
node.iter().advance(|x| each(&x.left, f) && f(&x.key, &x.value) &&
each(&x.right, f))
node.iter().advance(|x| each(&x.left, |k,v| f(k,v)) && f(&x.key, &x.value) &&
each(&x.right, |k,v| f(k,v)))
}

fn each_reverse<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>,
f: &fn(&'r K, &'r V) -> bool) -> bool {
node.iter().advance(|x| each_reverse(&x.right, f) && f(&x.key, &x.value) &&
each_reverse(&x.left, f))
node.iter().advance(|x| each_reverse(&x.right, |k,v| f(k,v)) && f(&x.key, &x.value) &&
each_reverse(&x.left, |k,v| f(k,v)))
}

fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode<K, V>>,
Expand All @@ -527,9 +527,9 @@ fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode<K, V>>,
match *node {
Some(~TreeNode{key: ref key, value: ref mut value, left: ref mut left,
right: ref mut right, _}) => {
if !mutate_values(left, f) { return false }
if !mutate_values(left, |k,v| f(k,v)) { return false }
if !f(key, value) { return false }
if !mutate_values(right, f) { return false }
if !mutate_values(right, |k,v| f(k,v)) { return false }
}
None => return false
}
Expand Down
2 changes: 1 addition & 1 deletion src/libextra/workcache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ struct WorkKey {
impl to_bytes::IterBytes for WorkKey {
#[inline]
fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
self.kind.iter_bytes(lsb0, f) && self.name.iter_bytes(lsb0, f)
self.kind.iter_bytes(lsb0, |b| f(b)) && self.name.iter_bytes(lsb0, |b| f(b))
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/librust/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ impl ValidUsage {
}

enum Action<'self> {
Call(&'self fn(args: &[~str]) -> ValidUsage),
CallMain(&'static str, &'self fn()),
Call(&'self fn:Copy(args: &[~str]) -> ValidUsage),
CallMain(&'static str, &'self fn:Copy()),
}

enum UsageSource<'self> {
UsgStr(&'self str),
UsgCall(&'self fn()),
UsgCall(&'self fn:Copy()),
}

struct Command<'self> {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/metadata/filesearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>,
debug!("filesearch: searching additional lib search paths [%?]",
self.addl_lib_search_paths.len());
// a little weird
self.addl_lib_search_paths.iter().advance(f);
self.addl_lib_search_paths.iter().advance(|path| f(path));

debug!("filesearch: searching target lib path");
if !f(&make_target_lib_path(self.sysroot,
Expand Down
40 changes: 20 additions & 20 deletions src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,11 @@ fn parse_trait_store(st: &mut PState) -> ty::TraitStore {
fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs {
let self_r = parse_opt(st, |st| parse_region(st) );

let self_ty = parse_opt(st, |st| parse_ty(st, conv) );
let self_ty = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)) );

assert_eq!(next(st), '[');
let mut params: ~[ty::t] = ~[];
while peek(st) != ']' { params.push(parse_ty(st, conv)); }
while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); }
st.pos = st.pos + 1u;

return ty::substs {
Expand Down Expand Up @@ -270,8 +270,8 @@ fn parse_str(st: &mut PState, term: char) -> ~str {
}

fn parse_trait_ref(st: &mut PState, conv: conv_did) -> ty::TraitRef {
let def = parse_def(st, NominalType, conv);
let substs = parse_substs(st, conv);
let def = parse_def(st, NominalType, |x,y| conv(x,y));
let substs = parse_substs(st, |x,y| conv(x,y));
ty::TraitRef {def_id: def, substs: substs}
}

Expand Down Expand Up @@ -301,18 +301,18 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
'c' => return ty::mk_char(),
't' => {
assert_eq!(next(st), '[');
let def = parse_def(st, NominalType, conv);
let substs = parse_substs(st, conv);
let def = parse_def(st, NominalType, |x,y| conv(x,y));
let substs = parse_substs(st, |x,y| conv(x,y));
assert_eq!(next(st), ']');
return ty::mk_enum(st.tcx, def, substs);
}
'x' => {
assert_eq!(next(st), '[');
let def = parse_def(st, NominalType, conv);
let substs = parse_substs(st, conv);
let def = parse_def(st, NominalType, |x,y| conv(x,y));
let substs = parse_substs(st, |x,y| conv(x,y));
let store = parse_trait_store(st);
let mt = parse_mutability(st);
let bounds = parse_bounds(st, conv);
let bounds = parse_bounds(st, |x,y| conv(x,y));
assert_eq!(next(st), ']');
return ty::mk_trait(st.tcx, def, substs, store, mt, bounds.builtin_bounds);
}
Expand Down Expand Up @@ -346,7 +346,7 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
'T' => {
assert_eq!(next(st), '[');
let mut params = ~[];
while peek(st) != ']' { params.push(parse_ty(st, conv)); }
while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); }
st.pos = st.pos + 1u;
return ty::mk_tup(st.tcx, params);
}
Expand Down Expand Up @@ -380,15 +380,15 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
}
}
'"' => {
let _ = parse_def(st, TypeWithId, conv);
let inner = parse_ty(st, conv);
let _ = parse_def(st, TypeWithId, |x,y| conv(x,y));
let inner = parse_ty(st, |x,y| conv(x,y));
inner
}
'B' => ty::mk_opaque_box(st.tcx),
'a' => {
assert_eq!(next(st), '[');
let did = parse_def(st, NominalType, conv);
let substs = parse_substs(st, conv);
let did = parse_def(st, NominalType, |x,y| conv(x,y));
let substs = parse_substs(st, |x,y| conv(x,y));
assert_eq!(next(st), ']');
return ty::mk_struct(st.tcx, did, substs);
}
Expand Down Expand Up @@ -473,8 +473,8 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy {
let purity = parse_purity(next(st));
let onceness = parse_onceness(next(st));
let region = parse_region(st);
let bounds = parse_bounds(st, conv);
let sig = parse_sig(st, conv);
let bounds = parse_bounds(st, |x,y| conv(x,y));
let sig = parse_sig(st, |x,y| conv(x,y));
ty::ClosureTy {
purity: purity,
sigil: sigil,
Expand All @@ -500,7 +500,7 @@ fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig {
assert_eq!(next(st), '[');
let mut inputs = ~[];
while peek(st) != ']' {
inputs.push(parse_ty(st, conv));
inputs.push(parse_ty(st, |x,y| conv(x,y)));
}
st.pos += 1u; // eat the ']'
let ret_ty = parse_ty(st, conv);
Expand Down Expand Up @@ -544,8 +544,8 @@ pub fn parse_type_param_def_data(data: &[u8], start: uint,
}

fn parse_type_param_def(st: &mut PState, conv: conv_did) -> ty::TypeParameterDef {
ty::TypeParameterDef {def_id: parse_def(st, NominalType, conv),
bounds: @parse_bounds(st, conv)}
ty::TypeParameterDef {def_id: parse_def(st, NominalType, |x,y| conv(x,y)),
bounds: @parse_bounds(st, |x,y| conv(x,y))}
}

fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
Expand All @@ -571,7 +571,7 @@ fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
param_bounds.builtin_bounds.add(ty::BoundSized);
}
'I' => {
param_bounds.trait_bounds.push(@parse_trait_ref(st, conv));
param_bounds.trait_bounds.push(@parse_trait_ref(st, |x,y| conv(x,y)));
}
'.' => {
return param_bounds;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/borrowck/move_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ impl MoveData {

let mut p = self.path(index).first_child;
while p != InvalidMovePathIndex {
if !self.each_extending_path(p, f) {
if !self.each_extending_path(p, |x| f(x)) {
return false;
}
p = self.path(p).next_sibling;
Expand Down
37 changes: 25 additions & 12 deletions src/librustc/middle/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ fn with_appropriate_checker(cx: Context, id: node_id,
// check that only immutable variables are implicitly copied in
check_imm_free_var(cx, fv.def, fv.span);

check_freevar_bounds(cx, fv.span, var_t, bounds);
check_freevar_bounds(cx, fv.span, var_t, bounds, None);
}

fn check_for_box(cx: Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) {
Expand All @@ -182,13 +182,18 @@ fn with_appropriate_checker(cx: Context, id: node_id,
// check that only immutable variables are implicitly copied in
check_imm_free_var(cx, fv.def, fv.span);

check_freevar_bounds(cx, fv.span, var_t, bounds);
check_freevar_bounds(cx, fv.span, var_t, bounds, None);
}

fn check_for_block(cx: Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) {
fn check_for_block(cx: Context, fv: &freevar_entry,
bounds: ty::BuiltinBounds, region: ty::Region) {
let id = ast_util::def_id_of_def(fv.def).node;
let var_t = ty::node_id_to_type(cx.tcx, id);
check_freevar_bounds(cx, fv.span, var_t, bounds);
// FIXME(#3569): Figure out whether the implicit borrow is actually
// mutable. Currently we assume all upvars are referenced mutably.
let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, region, var_t);
check_freevar_bounds(cx, fv.span, implicit_borrowed_type,
bounds, Some(var_t));
}

fn check_for_bare(cx: Context, fv: @freevar_entry) {
Expand All @@ -205,8 +210,9 @@ fn with_appropriate_checker(cx: Context, id: node_id,
ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, bounds: bounds, _}) => {
b(|cx, fv| check_for_box(cx, fv, bounds))
}
ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, bounds: bounds, _}) => {
b(|cx, fv| check_for_block(cx, fv, bounds))
ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, bounds: bounds,
region: region, _}) => {
b(|cx, fv| check_for_block(cx, fv, bounds, region))
}
ty::ty_bare_fn(_) => {
b(check_for_bare)
Expand Down Expand Up @@ -366,14 +372,21 @@ pub fn check_typaram_bounds(cx: Context,
}

pub fn check_freevar_bounds(cx: Context, sp: span, ty: ty::t,
bounds: ty::BuiltinBounds)
bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
{
do check_builtin_bounds(cx, ty, bounds) |missing| {
cx.tcx.sess.span_err(
sp,
fmt!("cannot capture variable of type `%s`, which does not fulfill \
`%s`, in a bounded closure",
ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx)));
// Will be Some if the freevar is implicitly borrowed (stack closure).
// Emit a less mysterious error message in this case.
match referenced_ty {
Some(rty) => cx.tcx.sess.span_err(sp,
fmt!("cannot implicitly borrow variable of type `%s` in a bounded \
stack closure (implicit reference does not fulfill `%s`)",
ty_to_str(cx.tcx, rty), missing.user_string(cx.tcx))),
None => cx.tcx.sess.span_err(sp,
fmt!("cannot capture variable of type `%s`, which does \
not fulfill `%s`, in a bounded closure",
ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx))),
}
cx.tcx.sess.span_note(
sp,
fmt!("this closure's environment must satisfy `%s`",
Expand Down
Loading