Skip to content

Commit

Permalink
Add initial set of testcases for RFC 2229
Browse files Browse the repository at this point in the history
Co-authored-by: Dhruv Jauhar <dhruvjhr@gmail.com>
  • Loading branch information
arora-aman and null-sleep committed Oct 17, 2020
1 parent 08b85c8 commit 1209375
Show file tree
Hide file tree
Showing 31 changed files with 841 additions and 3 deletions.
7 changes: 7 additions & 0 deletions compiler/rustc_typeck/src/check/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
.consume_body(body);

log_capture_analysis!(
self,
closure_def_id,
"capture information: {:#?}",
delegate.capture_information
);

if let Some(closure_substs) = infer_kind {
// Unify the (as yet unbound) type variable in the closure
// substs with the kind we inferred.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![feature(capture_disjoint_fields)]
//~^ WARNING the feature `capture_disjoint_fields` is incomplete
#![feature(rustc_attrs)]

// Ensure that capture analysis results in arrays being completely captured.
fn main() {
let mut m = [1, 2, 3, 4, 5];

let mut c = #[rustc_capture_analysis]
|| {
//~^ ERROR: attributes on expressions are experimental
m[0] += 10;
m[1] += 40;
};

c();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0658]: attributes on expressions are experimental
--> $DIR/arrays-completely-captured.rs:9:17
|
LL | let mut c = #[rustc_capture_analysis]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable

warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/arrays-completely-captured.rs:1:12
|
LL | #![feature(capture_disjoint_fields)]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information

error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0658`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
For closure=DefId(0:4 ~ arrays_completely_captured[317d]::main::{closure#0}): Using new-style capture analysis
For closure=DefId(0:4 ~ arrays_completely_captured[317d]::main::{closure#0}): capture information: {
Place {
base_ty: [i32; 5],
base: Upvar(
UpvarId(HirId { owner: DefId(0:3 ~ arrays_completely_captured[317d]::main), local_id: 1 };`m`;DefId(0:4 ~ arrays_completely_captured[317d]::main::{closure#0})),
),
projections: [],
}: CaptureInfo {
expr_id: Some(
HirId {
owner: DefId(0:3 ~ arrays_completely_captured[317d]::main),
local_id: 12,
},
),
capture_kind: ByRef(
UpvarBorrow(MutBorrow, '_#6r),
),
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// FIXME(arora-aman) add run-pass once 2229 is implemented

#![feature(capture_disjoint_fields)]
//~^ WARNING the feature `capture_disjoint_fields` is incomplete
#![feature(rustc_attrs)]

struct Point {
x: i32,
y: i32,
}

fn main() {
let mut p = Point { x: 10, y: 10 };

let c = #[rustc_capture_analysis]
|| {
//~^ ERROR: attributes on expressions are experimental
println!("{}", p.x);
};

// `c` should only capture `p.x`, therefore mutating `p.y` is allowed.
let py = &mut p.y;

c();
*py = 20;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0658]: attributes on expressions are experimental
--> $DIR/capture-disjoint-field-struct.rs:15:13
|
LL | let c = #[rustc_capture_analysis]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable

warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/capture-disjoint-field-struct.rs:3:12
|
LL | #![feature(capture_disjoint_fields)]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information

error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0658`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
For closure=DefId(0:7 ~ capture_disjoint_field_struct[317d]::main::{closure#0}): Using new-style capture analysis
For closure=DefId(0:7 ~ capture_disjoint_field_struct[317d]::main::{closure#0}): capture information: {
Place {
base_ty: Point,
base: Upvar(
UpvarId(HirId { owner: DefId(0:6 ~ capture_disjoint_field_struct[317d]::main), local_id: 1 };`p`;DefId(0:7 ~ capture_disjoint_field_struct[317d]::main::{closure#0})),
),
projections: [
Projection {
ty: i32,
kind: Field(
0,
0,
),
},
],
}: CaptureInfo {
expr_id: Some(
HirId {
owner: DefId(0:6 ~ capture_disjoint_field_struct[317d]::main),
local_id: 31,
},
),
capture_kind: ByRef(
UpvarBorrow(ImmBorrow, '_#35r),
),
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![feature(capture_disjoint_fields)]
//~^ WARNING the feature `capture_disjoint_fields` is incomplete
#![feature(rustc_attrs)]

fn main() {
let mut t = (10, 10);

let c = #[rustc_capture_analysis]
|| {
println!("{}", t.0);
};

// `c` only captures t.0, therefore mutating t.1 is allowed.
let t1 = &mut t.1;

c();
*t1 = 20;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0658]: attributes on expressions are experimental
--> $DIR/capture-disjoint-field-tuple.rs:8:13
|
LL | let c = #[rustc_capture_analysis]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable

warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/capture-disjoint-field-tuple.rs:1:12
|
LL | #![feature(capture_disjoint_fields)]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information

error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0658`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
For closure=DefId(0:4 ~ capture_disjoint_field_tuple[317d]::main::{closure#0}): Using new-style capture analysis
For closure=DefId(0:4 ~ capture_disjoint_field_tuple[317d]::main::{closure#0}): capture information: {
Place {
base_ty: (i32, i32),
base: Upvar(
UpvarId(HirId { owner: DefId(0:3 ~ capture_disjoint_field_tuple[317d]::main), local_id: 1 };`t`;DefId(0:4 ~ capture_disjoint_field_tuple[317d]::main::{closure#0})),
),
projections: [
Projection {
ty: i32,
kind: Field(
0,
0,
),
},
],
}: CaptureInfo {
expr_id: Some(
HirId {
owner: DefId(0:3 ~ capture_disjoint_field_tuple[317d]::main),
local_id: 28,
},
),
capture_kind: ByRef(
UpvarBorrow(ImmBorrow, '_#35r),
),
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
fn main() {
let s = format!("s");

let c = #[rustc_capture_analysis] || {
//~^ ERROR: attributes on expressions are experimental
let c = #[rustc_capture_analysis]
|| {
//~^ ERROR: attributes on expressions are experimental
println!("This uses new capture analyysis to capture s={}", s);
};
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
error[E0658]: attributes on expressions are experimental
--> $DIR/feature-gate-capture_disjoint_fields.rs:8:13
|
LL | let c = #[rustc_capture_analysis] || {
LL | let c = #[rustc_capture_analysis]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
For closure=DefId(0:4 ~ feature_gate_capture_disjoint_fields[317d]::main::{closure#0}): Using new-style capture analysis
For closure=DefId(0:4 ~ feature_gate_capture_disjoint_fields[317d]::main::{closure#0}): capture information: {
Place {
base_ty: std::string::String,
base: Upvar(
UpvarId(HirId { owner: DefId(0:3 ~ feature_gate_capture_disjoint_fields[317d]::main), local_id: 1 };`s`;DefId(0:4 ~ feature_gate_capture_disjoint_fields[317d]::main::{closure#0})),
),
projections: [],
}: CaptureInfo {
expr_id: Some(
HirId {
owner: DefId(0:3 ~ feature_gate_capture_disjoint_fields[317d]::main),
local_id: 52,
},
),
capture_kind: ByRef(
UpvarBorrow(ImmBorrow, '_#50r),
),
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#![feature(capture_disjoint_fields)]
//~^ warning the feature `capture_disjoint_fields` is incomplete
#![feature(rustc_attrs)]

struct Filter {
div: i32,
}
impl Filter {
fn allowed(&self, x: i32) -> bool {
x % self.div == 1
}
}

struct Data {
filter: Filter,
list: Vec<i32>,
}
impl Data {
fn update(&mut self) {
// The closure passed to filter only captures self.filter,
// therefore mutating self.list is allowed.
self.list.retain(
#[rustc_capture_analysis]
|v| self.filter.allowed(*v),
);
//~^ ERROR: attributes on expressions are experimental
}
}

fn main() {
let mut d = Data { filter: Filter { div: 3 }, list: Vec::new() };

for i in 1..10 {
d.list.push(i);
}

d.update();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/filter-on-struct-member.rs:1:12
|
LL | #![feature(capture_disjoint_fields)]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information

error[E0502]: cannot borrow `self.list` as mutable because it is also borrowed as immutable
--> $DIR/filter-on-struct-member.rs:22:9
|
LL | self.list.retain(
| ^ ------ immutable borrow later used by call
| _________|
| |
LL | | #[rustc_capture_analysis]
LL | | |v| self.filter.allowed(*v),
| | --- ---- first borrow occurs due to use of `self` in closure
| | |
| | immutable borrow occurs here
LL | | );
| |_________^ mutable borrow occurs here

error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0502`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
For closure=DefId(0:12 ~ filter_on_struct_member[317d]::{impl#1}::update::{closure#0}): Using new-style capture analysis
For closure=DefId(0:12 ~ filter_on_struct_member[317d]::{impl#1}::update::{closure#0}): capture information: {
Place {
base_ty: &mut Data,
base: Upvar(
UpvarId(HirId { owner: DefId(0:11 ~ filter_on_struct_member[317d]::{impl#1}::update), local_id: 1 };`self`;DefId(0:12 ~ filter_on_struct_member[317d]::{impl#1}::update::{closure#0})),
),
projections: [
Projection {
ty: Data,
kind: Deref,
},
Projection {
ty: Filter,
kind: Field(
0,
0,
),
},
],
}: CaptureInfo {
expr_id: Some(
HirId {
owner: DefId(0:11 ~ filter_on_struct_member[317d]::{impl#1}::update),
local_id: 13,
},
),
capture_kind: ByRef(
UpvarBorrow(ImmBorrow, '_#7r),
),
},
}
34 changes: 34 additions & 0 deletions src/test/ui/closures/2229_closure_analysis/multilevel-path-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#![feature(capture_disjoint_fields)]
//~^ warning the feature `capture_disjoint_fields` is incomplete
#![feature(rustc_attrs)]
#![allow(unused)]

struct Point {
x: i32,
y: i32,
}
struct Wrapper {
p: Point,
}

fn main() {
let mut w = Wrapper { p: Point { x: 10, y: 10 } };

// Only paths that appears within the closure that directly start off
// a variable defined outside the closure are captured.
//
// Therefore `w.p` is captured
// Note that `wp.x` doesn't start off a variable defined outside the closure.
let c = #[rustc_capture_analysis]
|| {
//~^ ERROR: attributes on expressions are experimental
let wp = &w.p;
println!("{}", wp.x);
};

// Since `c` captures `w.p` by an ImmBorrow, `w.p.y` can't be mutated.
let py = &mut w.p.y;
c();

*py = 20
}
Loading

0 comments on commit 1209375

Please sign in to comment.