diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index a28744c2ece7..9e4e65653615 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -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. diff --git a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs new file mode 100644 index 000000000000..a5dd202bc072 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs @@ -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(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr new file mode 100644 index 000000000000..3d3912d0796e --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr @@ -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 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 for more information + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stdout b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stdout new file mode 100644 index 000000000000..b4142a4fd8e4 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stdout @@ -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), + ), + }, +} diff --git a/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.rs b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.rs new file mode 100644 index 000000000000..a2be21cddb48 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.rs @@ -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; +} diff --git a/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.stderr b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.stderr new file mode 100644 index 000000000000..9233597c360d --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.stderr @@ -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 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 for more information + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.stdout b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.stdout new file mode 100644 index 000000000000..ab7bd60e48d1 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-struct.stdout @@ -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), + ), + }, +} diff --git a/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.rs b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.rs new file mode 100644 index 000000000000..e06cde73158e --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.rs @@ -0,0 +1,21 @@ +// 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)] + +fn main() { + let mut t = (10, 10); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + || { + println!("{}", t.0); + }; + + // `c` only captures t.0, therefore mutating t.1 is allowed. + let t1 = &mut t.1; + + c(); + *t1 = 20; +} diff --git a/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.stderr b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.stderr new file mode 100644 index 000000000000..f83487ecce55 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.stderr @@ -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 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 for more information + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.stdout b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.stdout new file mode 100644 index 000000000000..517d7564c72c --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/capture-disjoint-field-tuple.stdout @@ -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), + ), + }, +} diff --git a/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.rs b/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.rs index 5eab718736cb..072ed8eeab6f 100644 --- a/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.rs +++ b/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.rs @@ -5,8 +5,9 @@ fn main() { let s = format!("s"); - let c = #[rustc_capture_analysis] || { + let c = #[rustc_capture_analysis] //~^ ERROR: attributes on expressions are experimental + || { println!("This uses new capture analyysis to capture s={}", s); }; } diff --git a/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.stderr b/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.stderr index 4dc1f9a6ab27..133de1d13e85 100644 --- a/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.stderr +++ b/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.stderr @@ -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 for more information diff --git a/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.stdout b/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.stdout index c1fca9afd391..40ac31b4ad90 100644 --- a/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.stdout +++ b/src/test/ui/closures/2229_closure_analysis/feature-gate-capture_disjoint_fields.stdout @@ -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), + ), + }, +} diff --git a/src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.rs b/src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.rs new file mode 100644 index 000000000000..aa251c4526cf --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.rs @@ -0,0 +1,40 @@ +// 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 Filter { + div: i32, +} +impl Filter { + fn allowed(&self, x: i32) -> bool { + x % self.div == 1 + } +} + +struct Data { + filter: Filter, + list: Vec, +} +impl Data { + fn update(&mut self) { + // The closure passed to filter only captures self.filter, + // therefore mutating self.list is allowed. + self.list.retain( + //~^ cannot borrow `self.list` as mutable because it is also borrowed as immutable + #[rustc_capture_analysis] + |v| self.filter.allowed(*v), + ); + } +} + +fn main() { + let mut d = Data { filter: Filter { div: 3 }, list: Vec::new() }; + + for i in 1..10 { + d.list.push(i); + } + + d.update(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.stderr b/src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.stderr new file mode 100644 index 000000000000..3eb4decdeae2 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.stderr @@ -0,0 +1,28 @@ +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 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 | | +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`. diff --git a/src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.stdout b/src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.stdout new file mode 100644 index 000000000000..560b2aa3b57b --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/filter-on-struct-member.stdout @@ -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), + ), + }, +} diff --git a/src/test/ui/closures/2229_closure_analysis/multilevel-path-1.rs b/src/test/ui/closures/2229_closure_analysis/multilevel-path-1.rs new file mode 100644 index 000000000000..bd8d52d6a3c7 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/multilevel-path-1.rs @@ -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 +} diff --git a/src/test/ui/closures/2229_closure_analysis/multilevel-path-1.stderr b/src/test/ui/closures/2229_closure_analysis/multilevel-path-1.stderr new file mode 100644 index 000000000000..bd339a68fa0c --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/multilevel-path-1.stderr @@ -0,0 +1,21 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/multilevel-path-1.rs:22:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #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/multilevel-path-1.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/multilevel-path-1.stdout b/src/test/ui/closures/2229_closure_analysis/multilevel-path-1.stdout new file mode 100644 index 000000000000..525366cb964f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/multilevel-path-1.stdout @@ -0,0 +1,28 @@ +For closure=DefId(0:9 ~ multilevel_path_1[317d]::main::{closure#0}): Using new-style capture analysis +For closure=DefId(0:9 ~ multilevel_path_1[317d]::main::{closure#0}): capture information: { + Place { + base_ty: Wrapper, + base: Upvar( + UpvarId(HirId { owner: DefId(0:8 ~ multilevel_path_1[317d]::main), local_id: 1 };`w`;DefId(0:9 ~ multilevel_path_1[317d]::main::{closure#0})), + ), + projections: [ + Projection { + ty: Point, + kind: Field( + 0, + 0, + ), + }, + ], + }: CaptureInfo { + expr_id: Some( + HirId { + owner: DefId(0:8 ~ multilevel_path_1[317d]::main), + local_id: 20, + }, + ), + capture_kind: ByRef( + UpvarBorrow(ImmBorrow, '_#37r), + ), + }, +} diff --git a/src/test/ui/closures/2229_closure_analysis/multilevel-path-2.rs b/src/test/ui/closures/2229_closure_analysis/multilevel-path-2.rs new file mode 100644 index 000000000000..a8aca53bc73f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/multilevel-path-2.rs @@ -0,0 +1,30 @@ +// 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)] +#![allow(unused)] + +struct Point { + x: i32, + y: i32, +} +struct Wrapper { + p: Point, +} + +fn main() { + let mut w = Wrapper { p: Point { x: 10, y: 10 } }; + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + || { + println!("{}", w.p.x); + }; + + // `c` only captures `w.p.x`, therefore it's safe to mutate `w.p.y`. + let py = &mut w.p.y; + c(); + + *py = 20 +} diff --git a/src/test/ui/closures/2229_closure_analysis/multilevel-path-2.stderr b/src/test/ui/closures/2229_closure_analysis/multilevel-path-2.stderr new file mode 100644 index 000000000000..772dfd643eaa --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/multilevel-path-2.stderr @@ -0,0 +1,21 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/multilevel-path-2.rs:19:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #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/multilevel-path-2.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/multilevel-path-2.stdout b/src/test/ui/closures/2229_closure_analysis/multilevel-path-2.stdout new file mode 100644 index 000000000000..f89670c8b7f3 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/multilevel-path-2.stdout @@ -0,0 +1,35 @@ +For closure=DefId(0:9 ~ multilevel_path_2[317d]::main::{closure#0}): Using new-style capture analysis +For closure=DefId(0:9 ~ multilevel_path_2[317d]::main::{closure#0}): capture information: { + Place { + base_ty: Wrapper, + base: Upvar( + UpvarId(HirId { owner: DefId(0:8 ~ multilevel_path_2[317d]::main), local_id: 1 };`w`;DefId(0:9 ~ multilevel_path_2[317d]::main::{closure#0})), + ), + projections: [ + Projection { + ty: Point, + kind: Field( + 0, + 0, + ), + }, + Projection { + ty: i32, + kind: Field( + 0, + 0, + ), + }, + ], + }: CaptureInfo { + expr_id: Some( + HirId { + owner: DefId(0:8 ~ multilevel_path_2[317d]::main), + local_id: 35, + }, + ), + capture_kind: ByRef( + UpvarBorrow(ImmBorrow, '_#35r), + ), + }, +} diff --git a/src/test/ui/closures/2229_closure_analysis/nested-closure.rs b/src/test/ui/closures/2229_closure_analysis/nested-closure.rs new file mode 100644 index 000000000000..64b69af0f0c1 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/nested-closure.rs @@ -0,0 +1,40 @@ +// 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, +} + +// This testcase ensures that nested closures are handles properly +// - The nested closure is analyzed first. +// - The capture kind of the nested closure is accounted for by the enclosing closure +// - Any captured path by the nested closure that starts off a local variable in the enclosing +// closure is not listed as a capture of the enclosing closure. + +fn main() { + let mut p = Point { x: 5, y: 20 }; + + let mut c1 = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + || { + println!("{}", p.x); + let incr = 10; + let mut c2 = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + || p.y += incr; + c2(); + println!("{}", p.y); + }; + + c1(); + + let px = &p.x; + + println!("{}", px); + + c1(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr b/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr new file mode 100644 index 000000000000..dbd9e3655a32 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr @@ -0,0 +1,30 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/nested-closure.rs:19:18 + | +LL | let mut c1 = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/nested-closure.rs:24:22 + | +LL | let mut c2 = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #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/nested-closure.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/nested-closure.stdout b/src/test/ui/closures/2229_closure_analysis/nested-closure.stdout new file mode 100644 index 000000000000..84d87a75bda9 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/nested-closure.stdout @@ -0,0 +1,98 @@ +For closure=DefId(0:8 ~ nested_closure[317d]::main::{closure#0}::{closure#0}): Using new-style capture analysis +For closure=DefId(0:8 ~ nested_closure[317d]::main::{closure#0}::{closure#0}): capture information: { + Place { + base_ty: Point, + base: Upvar( + UpvarId(HirId { owner: DefId(0:6 ~ nested_closure[317d]::main), local_id: 1 };`p`;DefId(0:8 ~ nested_closure[317d]::main::{closure#0}::{closure#0})), + ), + projections: [ + Projection { + ty: i32, + kind: Field( + 1, + 0, + ), + }, + ], + }: CaptureInfo { + expr_id: Some( + HirId { + owner: DefId(0:6 ~ nested_closure[317d]::main), + local_id: 70, + }, + ), + capture_kind: ByRef( + UpvarBorrow(MutBorrow, '_#109r), + ), + }, + Place { + base_ty: i32, + base: Upvar( + UpvarId(HirId { owner: DefId(0:6 ~ nested_closure[317d]::main), local_id: 5 };`incr`;DefId(0:8 ~ nested_closure[317d]::main::{closure#0}::{closure#0})), + ), + projections: [], + }: CaptureInfo { + expr_id: Some( + HirId { + owner: DefId(0:6 ~ nested_closure[317d]::main), + local_id: 72, + }, + ), + capture_kind: ByRef( + UpvarBorrow(ImmBorrow, '_#110r), + ), + }, +} +For closure=DefId(0:7 ~ nested_closure[317d]::main::{closure#0}): Using new-style capture analysis +For closure=DefId(0:7 ~ nested_closure[317d]::main::{closure#0}): capture information: { + Place { + base_ty: Point, + base: Upvar( + UpvarId(HirId { owner: DefId(0:6 ~ nested_closure[317d]::main), local_id: 1 };`p`;DefId(0:7 ~ nested_closure[317d]::main::{closure#0})), + ), + projections: [ + Projection { + ty: i32, + kind: Field( + 0, + 0, + ), + }, + ], + }: CaptureInfo { + expr_id: Some( + HirId { + owner: DefId(0:6 ~ nested_closure[317d]::main), + local_id: 37, + }, + ), + capture_kind: ByRef( + UpvarBorrow(ImmBorrow, '_#114r), + ), + }, + Place { + base_ty: Point, + base: Upvar( + UpvarId(HirId { owner: DefId(0:6 ~ nested_closure[317d]::main), local_id: 1 };`p`;DefId(0:7 ~ nested_closure[317d]::main::{closure#0})), + ), + projections: [ + Projection { + ty: i32, + kind: Field( + 1, + 0, + ), + }, + ], + }: CaptureInfo { + expr_id: Some( + HirId { + owner: DefId(0:6 ~ nested_closure[317d]::main), + local_id: 70, + }, + ), + capture_kind: ByRef( + UpvarBorrow(MutBorrow, '_#115r), + ), + }, +} diff --git a/src/test/ui/closures/2229_closure_analysis/path-with-array-access.rs b/src/test/ui/closures/2229_closure_analysis/path-with-array-access.rs new file mode 100644 index 000000000000..c967c0b72d40 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/path-with-array-access.rs @@ -0,0 +1,28 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING the feature `capture_disjoint_fields` is incomplete +#![feature(rustc_attrs)] + +struct Point { + x: f32, + y: f32, +} + +struct Pentagon { + points: [Point; 5], +} + +fn main() { + let p1 = Point { x: 10.0, y: 10.0 }; + let p2 = Point { x: 7.5, y: 12.5 }; + let p3 = Point { x: 15.0, y: 15.0 }; + let p4 = Point { x: 12.5, y: 12.5 }; + let p5 = Point { x: 20.0, y: 10.0 }; + + let pent = Pentagon { points: [p1, p2, p3, p4, p5] }; + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + || { + println!("{}", pent.points[5].x); + }; +} diff --git a/src/test/ui/closures/2229_closure_analysis/path-with-array-access.stderr b/src/test/ui/closures/2229_closure_analysis/path-with-array-access.stderr new file mode 100644 index 000000000000..84bcc55d99c9 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/path-with-array-access.stderr @@ -0,0 +1,21 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/path-with-array-access.rs:23:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #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/path-with-array-access.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/path-with-array-access.stdout b/src/test/ui/closures/2229_closure_analysis/path-with-array-access.stdout new file mode 100644 index 000000000000..b843b0494b93 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/path-with-array-access.stdout @@ -0,0 +1,28 @@ +For closure=DefId(0:10 ~ path_with_array_access[317d]::main::{closure#0}): Using new-style capture analysis +For closure=DefId(0:10 ~ path_with_array_access[317d]::main::{closure#0}): capture information: { + Place { + base_ty: Pentagon, + base: Upvar( + UpvarId(HirId { owner: DefId(0:9 ~ path_with_array_access[317d]::main), local_id: 6 };`pent`;DefId(0:10 ~ path_with_array_access[317d]::main::{closure#0})), + ), + projections: [ + Projection { + ty: [Point; 5], + kind: Field( + 0, + 0, + ), + }, + ], + }: CaptureInfo { + expr_id: Some( + HirId { + owner: DefId(0:9 ~ path_with_array_access[317d]::main), + local_id: 83, + }, + ), + capture_kind: ByRef( + UpvarBorrow(ImmBorrow, '_#34r), + ), + }, +} diff --git a/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.rs b/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.rs new file mode 100644 index 000000000000..27ab9d6b7359 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.rs @@ -0,0 +1,33 @@ +// 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)] + +// Test to ensure that min analysis meets capture kind for all paths captured. + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut p = Point { x: 10, y: 20 }; + + // + // Requirements: + // p.x -> MutBoorrow + // p -> ImmBorrow + // + // Requirements met when p is captured via MutBorrow + // + let mut c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + || { + p.x += 10; + println!("{:?}", p); + }; + + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stderr b/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stderr new file mode 100644 index 000000000000..002d2aaab89a --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stderr @@ -0,0 +1,21 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/simple-struct-min-capture.rs:25:17 + | +LL | let mut c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #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/simple-struct-min-capture.rs:3:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stdout b/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stdout new file mode 100644 index 000000000000..02129f1acb55 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stdout @@ -0,0 +1,45 @@ +For closure=DefId(0:4 ~ simple_struct_min_capture[317d]::main::{closure#0}): Using new-style capture analysis +For closure=DefId(0:4 ~ simple_struct_min_capture[317d]::main::{closure#0}): capture information: { + Place { + base_ty: Point, + base: Upvar( + UpvarId(HirId { owner: DefId(0:3 ~ simple_struct_min_capture[317d]::main), local_id: 1 };`p`;DefId(0:4 ~ simple_struct_min_capture[317d]::main::{closure#0})), + ), + projections: [ + Projection { + ty: i32, + kind: Field( + 0, + 0, + ), + }, + ], + }: CaptureInfo { + expr_id: Some( + HirId { + owner: DefId(0:3 ~ simple_struct_min_capture[317d]::main), + local_id: 15, + }, + ), + capture_kind: ByRef( + UpvarBorrow(MutBorrow, '_#34r), + ), + }, + Place { + base_ty: Point, + base: Upvar( + UpvarId(HirId { owner: DefId(0:3 ~ simple_struct_min_capture[317d]::main), local_id: 1 };`p`;DefId(0:4 ~ simple_struct_min_capture[317d]::main::{closure#0})), + ), + projections: [], + }: CaptureInfo { + expr_id: Some( + HirId { + owner: DefId(0:3 ~ simple_struct_min_capture[317d]::main), + local_id: 35, + }, + ), + capture_kind: ByRef( + UpvarBorrow(ImmBorrow, '_#35r), + ), + }, +} diff --git a/src/test/ui/closures/2229_closure_analysis/slice-pat.rs b/src/test/ui/closures/2229_closure_analysis/slice-pat.rs new file mode 100644 index 000000000000..fc966c4193e9 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/slice-pat.rs @@ -0,0 +1,28 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING the feature `capture_disjoint_fields` is incomplete +#![feature(rustc_attrs)] + +// Test to ensure Index projections are handled properly during capture analysis +// +// The array should be moved in entirety, even though only some elements are used. + +fn main() { + let arr : [String; 5] = [ + format!("A"), + format!("B"), + format!("C"), + format!("D"), + format!("E") + ]; + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + || { + let [a, b, .., e] = arr; + assert_eq!(a, "A"); + assert_eq!(b, "B"); + assert_eq!(e, "E"); + }; + + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/slice-pat.stderr b/src/test/ui/closures/2229_closure_analysis/slice-pat.stderr new file mode 100644 index 000000000000..5c6b505d64fd --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/slice-pat.stderr @@ -0,0 +1,21 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/slice-pat.rs:18:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #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/slice-pat.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/slice-pat.stdout b/src/test/ui/closures/2229_closure_analysis/slice-pat.stdout new file mode 100644 index 000000000000..ba9b2bca1967 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/slice-pat.stdout @@ -0,0 +1,20 @@ +For closure=DefId(0:5 ~ slice_pat[317d]::main::{closure#0}): Using new-style capture analysis +For closure=DefId(0:5 ~ slice_pat[317d]::main::{closure#0}): capture information: { + Place { + base_ty: [std::string::String; 5], + base: Upvar( + UpvarId(HirId { owner: DefId(0:3 ~ slice_pat[317d]::main), local_id: 1 };`arr`;DefId(0:5 ~ slice_pat[317d]::main::{closure#0})), + ), + projections: [ + Projection { + ty: std::string::String, + kind: Index, + }, + ], + }: CaptureInfo { + expr_id: None, + capture_kind: ByValue( + None, + ), + }, +}