From b6cf070eb4c228c146ca9971cddeb034084f88de Mon Sep 17 00:00:00 2001 From: Roxane Date: Sun, 21 Feb 2021 10:20:40 -0500 Subject: [PATCH] Attempt to deal with nested closures properly --- compiler/rustc_typeck/src/check/upvar.rs | 7 +- compiler/rustc_typeck/src/expr_use_visitor.rs | 40 ++++-- ...tructure-pattern-closure-within-closure.rs | 21 ++++ ...ture-pattern-closure-within-closure.stderr | 110 ++++++++++++++++ .../run_pass/destructure_patterns-1.rs | 118 ++++++++++++++++++ .../run_pass/destructure_patterns-1.stderr | 42 +++++++ .../run_pass/destructure_patterns.rs | 52 ++++++++ .../run_pass/destructure_patterns.stderr | 61 +++++++++ .../no_capture_with_wildcard_match.rs | 12 ++ .../no_capture_with_wildcard_match.stderr | 32 +++++ .../run_pass/struct_update_syntax.rs | 23 ++++ .../run_pass/struct_update_syntax.stderr | 57 +++++++++ 12 files changed, 560 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns-1.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns-1.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.stderr diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 74e2ca51039d..932f07ff1bd1 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -1153,7 +1153,6 @@ struct InferBorrowKind<'a, 'tcx> { /// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow } /// ``` capture_information: InferredCaptureInformation<'tcx>, - // [FIXME] RFC2229 Change Vec to FxHashSet fake_reads: FxHashSet>, // these need to be fake read. } @@ -1416,9 +1415,9 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { - fn fake_read(&mut self, place: PlaceWithHirId<'tcx>) { - if let PlaceBase::Upvar(_) = place.place.base { - self.fake_reads.insert(place.place); + fn fake_read(&mut self, place: Place<'tcx>) { + if let PlaceBase::Upvar(_) = place.base { + self.fake_reads.insert(place); } } diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 45ecf30cd50e..ad39b93c067e 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -5,7 +5,7 @@ pub use self::ConsumeMode::*; // Export these here so that Clippy can use them. -pub use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId, Projection}; +pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; use rustc_hir as hir; use rustc_hir::def::Res; @@ -54,7 +54,7 @@ pub trait Delegate<'tcx> { fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId); // [FIXME] RFC2229 This should also affect clippy ref: https://github.com/sexxi-goose/rust/pull/27 - fn fake_read(&mut self, place: PlaceWithHirId<'tcx>); + fn fake_read(&mut self, place: Place<'tcx>); } #[derive(Copy, Clone, PartialEq, Debug)] @@ -558,7 +558,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat); - self.delegate.fake_read(discr_place.clone()); + self.delegate.fake_read(discr_place.place.clone()); let tcx = self.tcx(); let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self; @@ -620,8 +620,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing /// closure as the DefId. fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) { - debug!("walk_captures({:?})", closure_expr); - // Over here we walk a closure that is nested inside the current body // If the current body is a closure, then we also want to report back any fake reads, // starting off of variables that are captured by our parent as well. @@ -635,6 +633,32 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ty::Closure(..) | ty::Generator(..) ); + // [FIXME] RFC2229 Closures within closures don't work + if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) { + for fake_read in fake_reads.iter() { + // Use this as a reference for if we should promote the fake read + match fake_read.base { + PlaceBase::Upvar(upvar_id) => { + if upvars.map_or(body_owner_is_closure, |upvars| { + !upvars.contains_key(&upvar_id.var_path.hir_id) + }) { + // The nested closure might be capturing the current (enclosing) closure's local variables. + // We check if the root variable is ever mentioned within the enclosing closure, if not + // then for the current body (if it's a closure) these aren't captures, we will ignore them. + continue; + } + } + _ => { + bug!( + "Do not know how to get HirId out of Rvalue and StaticItem {:?}", + fake_read.base + ); + } + }; + self.delegate.fake_read(fake_read.clone()); + } + } + if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id) { for (var_hir_id, min_list) in min_captures.iter() { @@ -664,12 +688,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { place.projections.clone(), ); - // [FIXME] RFC2229 We want to created another loop that iterates mc.typeck_results.fake_reads() - // [FIXME] RFC2229 Add tests for nested closures - if body_owner_is_closure { - self.delegate.fake_read(place_with_id.clone()); - } - match capture_info.capture_kind { ty::UpvarCapture::ByValue(_) => { let mode = copy_or_move(&self.mc, &place_with_id); diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs new file mode 100644 index 000000000000..db067b6c9bca --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs @@ -0,0 +1,21 @@ +#![feature(capture_disjoint_fields)] +#![feature(rustc_attrs)] + +fn main() { + let _z = 9; + let t = (String::from("Hello"), String::from("World")); + let g = (String::from("Mr"), String::from("Goose")); + + let a = #[rustc_capture_analysis] || { + let (_, g2) = g; + println!("{}", g2); + let c = #[rustc_capture_analysis] || { + let (_, t2) = t; + println!("{}", t2); + }; + + c(); + }; + + a(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr new file mode 100644 index 000000000000..c9a1a32fc579 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr @@ -0,0 +1,110 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/destructure-pattern-closure-within-closure.rs:9:13 + | +LL | let a = #[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/destructure-pattern-closure-within-closure.rs:12:17 + | +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/destructure-pattern-closure-within-closure.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: First Pass analysis includes: + --> $DIR/destructure-pattern-closure-within-closure.rs:12:43 + | +LL | let c = #[rustc_capture_analysis] || { + | ___________________________________________^ +LL | | let (_, t2) = t; +LL | | println!("{}", t2); +LL | | }; + | |_________^ + | +note: Capturing t[(1, 0)] -> ByValue + --> $DIR/destructure-pattern-closure-within-closure.rs:13:27 + | +LL | let (_, t2) = t; + | ^ + +error: Min Capture analysis includes: + --> $DIR/destructure-pattern-closure-within-closure.rs:12:43 + | +LL | let c = #[rustc_capture_analysis] || { + | ___________________________________________^ +LL | | let (_, t2) = t; +LL | | println!("{}", t2); +LL | | }; + | |_________^ + | +note: Min Capture t[(1, 0)] -> ByValue + --> $DIR/destructure-pattern-closure-within-closure.rs:13:27 + | +LL | let (_, t2) = t; + | ^ + +error: First Pass analysis includes: + --> $DIR/destructure-pattern-closure-within-closure.rs:9:39 + | +LL | let a = #[rustc_capture_analysis] || { + | _______________________________________^ +LL | | let (_, g2) = g; +LL | | println!("{}", g2); +LL | | let c = #[rustc_capture_analysis] || { +... | +LL | | c(); +LL | | }; + | |_____^ + | +note: Capturing g[(1, 0)] -> ByValue + --> $DIR/destructure-pattern-closure-within-closure.rs:10:23 + | +LL | let (_, g2) = g; + | ^ +note: Capturing t[(1, 0)] -> ByValue + --> $DIR/destructure-pattern-closure-within-closure.rs:13:27 + | +LL | let (_, t2) = t; + | ^ + +error: Min Capture analysis includes: + --> $DIR/destructure-pattern-closure-within-closure.rs:9:39 + | +LL | let a = #[rustc_capture_analysis] || { + | _______________________________________^ +LL | | let (_, g2) = g; +LL | | println!("{}", g2); +LL | | let c = #[rustc_capture_analysis] || { +... | +LL | | c(); +LL | | }; + | |_____^ + | +note: Min Capture g[(1, 0)] -> ByValue + --> $DIR/destructure-pattern-closure-within-closure.rs:10:23 + | +LL | let (_, g2) = g; + | ^ +note: Min Capture t[(1, 0)] -> ByValue + --> $DIR/destructure-pattern-closure-within-closure.rs:13:27 + | +LL | let (_, t2) = t; + | ^ + +error: aborting due to 6 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/run_pass/destructure_patterns-1.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns-1.rs new file mode 100644 index 000000000000..757b506fd6ed --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns-1.rs @@ -0,0 +1,118 @@ +//check-pass +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +#![warn(unused)] + +struct Point { + x: u32, + y: u32, +} + +fn test1() { + let _z = 9; + let t = (String::from("Hello"), String::from("World")); + + let c = || { + let (t1, t2) = t; + println!("{} {}", t1, t2); + }; + + c(); +} + +fn test2() { + let _z = 9; + let t = (String::from("Hello"), String::from("World")); + + let c = || { + let (t1, _) = t; + println!("{}", t1); + }; + + c(); +} + +fn test3() { + let _z = 9; + let t = (String::from("Hello"), String::from("World")); + + let c = || { + let (_, t2) = t; + println!("{}", t2); + }; + + c(); +} + +fn test4() { + let _z = 9; + let t = (String::from("Hello"), String::from("World")); + //~^ WARN unused variable: `t` + + let c = || { + let (_, _) = t; + }; + + c(); +} + +fn test5() { + let _z = 9; + let t = (String::new(), String::new()); + let _c = || { + let _a = match t { + (t1, _) => t1, + }; + }; +} + +fn test6() { + let _z = 9; + let t = (String::new(), String::new()); + let _c = || { + let _a = match t { + (_, t2) => t2, + }; + }; +} + +fn test7() { + let x = 0; + //~^ WARN unused variable: `x` + let tup = (1, 2); + //~^ WARN unused variable: `tup` + let p = Point { x: 10, y: 20 }; + + let c = || { + let _ = x; + let Point { x, y } = p; // 1 + //~^ WARN unused variable: `x` + println!("{}", y); + let (_, _) = tup; // 2 + }; + + c(); +} + +fn test8() { + let _z = 9; + let t = (String::from("Hello"), String::from("World")); + + let c = || { + let (_, t) = t; + println!("{}", t); + }; + + c(); +} + +fn main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns-1.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns-1.stderr new file mode 100644 index 000000000000..1ae64eb83ef7 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns-1.stderr @@ -0,0 +1,42 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/destructure_patterns-1.rs:2:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: unused variable: `t` + --> $DIR/destructure_patterns-1.rs:49:9 + | +LL | let t = (String::from("Hello"), String::from("World")); + | ^ help: if this is intentional, prefix it with an underscore: `_t` + | +note: the lint level is defined here + --> $DIR/destructure_patterns-1.rs:4:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: unused variable: `x` + --> $DIR/destructure_patterns-1.rs:88:21 + | +LL | let Point { x, y } = p; // 1 + | ^ help: try ignoring the field: `x: _` + +warning: unused variable: `x` + --> $DIR/destructure_patterns-1.rs:80:9 + | +LL | let x = 0; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + +warning: unused variable: `tup` + --> $DIR/destructure_patterns-1.rs:82:9 + | +LL | let tup = (1, 2); + | ^^^ help: if this is intentional, prefix it with an underscore: `_tup` + +warning: 5 warnings emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs new file mode 100644 index 000000000000..6f958bb18c38 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs @@ -0,0 +1,52 @@ +#![feature(capture_disjoint_fields)] +#![feature(rustc_attrs)] + +struct S { + a: String, + b: String, +} + +fn main() { + let t = (String::new(), String::new()); + + let s = S { + a: String::new(), + b: String::new(), + }; + + let c = #[rustc_capture_analysis] || { + let (t1, t2) = t; + }; + + + // MIR Build + // + // Create place for the initalizer in let which is `t` + // + // I'm reading Field 1 from `t`, so apply Field projections; + // + // new place -> t[1] + // + // I'm reading Field 2 from `t`, so apply Field projections; + // + // new place -> t[2] + // + // New + // --------- + // + // I'm building something starting at `t` + // + // I read field 1 from `t` + // + // I need to use `t[1]`, therefore the place must be constructable + // + // Find the capture index for `t[1]` for this closure. + // + // I read field 2 from `t` + // + // I need to use `t[2]`, therefore the place must be constructable + // + // Find the capture index for `t[2]` for this closure. + + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr new file mode 100644 index 000000000000..1ee5d2abf133 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr @@ -0,0 +1,61 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/destructure_patterns.rs:17: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/destructure_patterns.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: First Pass analysis includes: + --> $DIR/destructure_patterns.rs:17:39 + | +LL | let c = #[rustc_capture_analysis] || { + | _______________________________________^ +LL | | let (t1, t2) = t; +LL | | }; + | |_____^ + | +note: Capturing t[(0, 0)] -> ByValue + --> $DIR/destructure_patterns.rs:18:24 + | +LL | let (t1, t2) = t; + | ^ +note: Capturing t[(1, 0)] -> ByValue + --> $DIR/destructure_patterns.rs:18:24 + | +LL | let (t1, t2) = t; + | ^ + +error: Min Capture analysis includes: + --> $DIR/destructure_patterns.rs:17:39 + | +LL | let c = #[rustc_capture_analysis] || { + | _______________________________________^ +LL | | let (t1, t2) = t; +LL | | }; + | |_____^ + | +note: Min Capture t[(0, 0)] -> ByValue + --> $DIR/destructure_patterns.rs:18:24 + | +LL | let (t1, t2) = t; + | ^ +note: Min Capture t[(1, 0)] -> ByValue + --> $DIR/destructure_patterns.rs:18:24 + | +LL | let (t1, t2) = t; + | ^ + +error: aborting due to 3 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/run_pass/no_capture_with_wildcard_match.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.rs new file mode 100644 index 000000000000..188035161017 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.rs @@ -0,0 +1,12 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +#![feature(rustc_attrs)] + +fn main() { + let foo = [1, 2, 3]; + let c = #[rustc_capture_analysis] || { + //~^ ERROR: attributes on expressions are experimental + //~| ERROR: First Pass analysis includes: + match foo { _ => () }; + }; +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.stderr new file mode 100644 index 000000000000..e2e825fe9425 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.stderr @@ -0,0 +1,32 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/no_capture_with_wildcard_match.rs:7: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/no_capture_with_wildcard_match.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: First Pass analysis includes: + --> $DIR/no_capture_with_wildcard_match.rs:7:39 + | +LL | let c = #[rustc_capture_analysis] || { + | _______________________________________^ +LL | | +LL | | +LL | | match foo { _ => () }; +LL | | }; + | |_____^ + +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/run_pass/struct_update_syntax.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.rs new file mode 100644 index 000000000000..9757860fb4c7 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.rs @@ -0,0 +1,23 @@ +#![feature(capture_disjoint_fields)] +#![feature(rustc_attrs)] + +struct S { + a: String, + b: String, +} + +fn main() { + let s = S { + a: String::new(), + b: String::new(), + }; + + let c = #[rustc_capture_analysis] || { + let s2 = S { + a: format!("New a"), + ..s + }; + }; + + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.stderr new file mode 100644 index 000000000000..15d8040c46c5 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.stderr @@ -0,0 +1,57 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/struct_update_syntax.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/struct_update_syntax.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: First Pass analysis includes: + --> $DIR/struct_update_syntax.rs:15:39 + | +LL | let c = #[rustc_capture_analysis] || { + | _______________________________________^ +LL | | let s2 = S { +LL | | a: format!("New a"), +LL | | ..s +LL | | }; +LL | | }; + | |_____^ + | +note: Capturing s[(1, 0)] -> ByValue + --> $DIR/struct_update_syntax.rs:18:15 + | +LL | ..s + | ^ + +error: Min Capture analysis includes: + --> $DIR/struct_update_syntax.rs:15:39 + | +LL | let c = #[rustc_capture_analysis] || { + | _______________________________________^ +LL | | let s2 = S { +LL | | a: format!("New a"), +LL | | ..s +LL | | }; +LL | | }; + | |_____^ + | +note: Min Capture s[(1, 0)] -> ByValue + --> $DIR/struct_update_syntax.rs:18:15 + | +LL | ..s + | ^ + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`.