From a54eefb273393523701d805c5d420fbc83506642 Mon Sep 17 00:00:00 2001 From: Jennifer Wills Date: Wed, 23 Dec 2020 15:38:22 -0500 Subject: [PATCH 1/4] Replace closures_captures and upvar_capture with closure_min_captures make changes to liveness to use closure_min_captures use different span borrow check uses new structures rename to CapturedPlace stop using upvar_capture in regionck remove the bridge cleanup from rebase + remove the upvar_capture reference from mutability_errors.rs remove line from livenes test make our unused var checking more consistent update tests adding more warnings to the tests move is_ancestor_or_same_capture to rustc_middle/ty update names to reflect the closures add FIXME check that all captures are immutable borrows before returning add surrounding if statement like the original move var out of the loop and rename Co-authored-by: Logan Mosier Co-authored-by: Roxane Fruytier --- compiler/rustc_middle/src/ty/context.rs | 37 +----- compiler/rustc_middle/src/ty/mod.rs | 52 ++++++++- .../src/borrow_check/diagnostics/mod.rs | 40 ++++--- .../diagnostics/mutability_errors.rs | 62 +++++++--- compiler/rustc_mir/src/interpret/validity.rs | 23 ++-- compiler/rustc_mir_build/src/build/mod.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 109 +++++++++--------- compiler/rustc_typeck/src/check/regionck.rs | 42 +++++-- compiler/rustc_typeck/src/check/upvar.rs | 76 ------------ compiler/rustc_typeck/src/check/writeback.rs | 20 ---- .../diagnostics/liveness.rs | 91 +++++++++++++++ .../diagnostics/liveness.stderr | 79 +++++++++++++ .../liveness_unintentional_copy.rs | 42 +++++++ .../liveness_unintentional_copy.stderr | 47 ++++++++ 14 files changed, 478 insertions(+), 244 deletions(-) create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e1d79248171a8..f6e8159a1ea3d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -30,9 +30,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; -use rustc_data_structures::stable_hasher::{ - hash_stable_hashmap, HashStable, StableHasher, StableVec, -}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableVec}; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; use rustc_errors::ErrorReported; @@ -382,9 +380,6 @@ pub struct TypeckResults<'tcx> { /// pat_adjustments: ItemLocalMap>>, - /// Borrows - pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>, - /// Records the reasons that we picked the kind of each closure; /// not all closures are present in the map. closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>, @@ -420,12 +415,6 @@ pub struct TypeckResults<'tcx> { /// by this function. pub concrete_opaque_types: FxHashMap>, - /// Given the closure ID this map provides the list of UpvarIDs used by it. - /// The upvarID contains the HIR node ID and it also contains the full path - /// leading to the member of the struct or tuple that is used instead of the - /// entire variable. - pub closure_captures: ty::UpvarListMap, - /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>, @@ -454,7 +443,6 @@ impl<'tcx> TypeckResults<'tcx> { adjustments: Default::default(), pat_binding_modes: Default::default(), pat_adjustments: Default::default(), - upvar_capture_map: Default::default(), closure_kind_origins: Default::default(), liberated_fn_sigs: Default::default(), fru_field_types: Default::default(), @@ -462,7 +450,6 @@ impl<'tcx> TypeckResults<'tcx> { used_trait_imports: Lrc::new(Default::default()), tainted_by_errors: None, concrete_opaque_types: Default::default(), - closure_captures: Default::default(), closure_min_captures: Default::default(), generator_interior_types: ty::Binder::dummy(Default::default()), treat_byte_string_as_slice: Default::default(), @@ -646,10 +633,6 @@ impl<'tcx> TypeckResults<'tcx> { .flatten() } - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> { - self.upvar_capture_map[&upvar_id] - } - pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins } } @@ -693,7 +676,7 @@ impl<'tcx> TypeckResults<'tcx> { impl<'a, 'tcx> HashStable> for TypeckResults<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ty::TypeckResults { - hir_owner, + hir_owner: _, ref type_dependent_defs, ref field_indices, ref user_provided_types, @@ -703,17 +686,13 @@ impl<'a, 'tcx> HashStable> for TypeckResults<'tcx> { ref adjustments, ref pat_binding_modes, ref pat_adjustments, - ref upvar_capture_map, ref closure_kind_origins, ref liberated_fn_sigs, ref fru_field_types, - ref coercion_casts, - ref used_trait_imports, tainted_by_errors, ref concrete_opaque_types, - ref closure_captures, ref closure_min_captures, ref generator_interior_types, ref treat_byte_string_as_slice, @@ -729,17 +708,6 @@ impl<'a, 'tcx> HashStable> for TypeckResults<'tcx> { adjustments.hash_stable(hcx, hasher); pat_binding_modes.hash_stable(hcx, hasher); pat_adjustments.hash_stable(hcx, hasher); - hash_stable_hashmap(hcx, hasher, upvar_capture_map, |up_var_id, hcx| { - let ty::UpvarId { var_path, closure_expr_id } = *up_var_id; - - assert_eq!(var_path.hir_id.owner, hir_owner); - - ( - hcx.local_def_path_hash(var_path.hir_id.owner), - var_path.hir_id.local_id, - hcx.local_def_path_hash(closure_expr_id), - ) - }); closure_kind_origins.hash_stable(hcx, hasher); liberated_fn_sigs.hash_stable(hcx, hasher); @@ -748,7 +716,6 @@ impl<'a, 'tcx> HashStable> for TypeckResults<'tcx> { used_trait_imports.hash_stable(hcx, hasher); tainted_by_errors.hash_stable(hcx, hasher); concrete_opaque_types.hash_stable(hcx, hasher); - closure_captures.hash_stable(hcx, hasher); closure_min_captures.hash_stable(hcx, hasher); generator_interior_types.hash_stable(hcx, hasher); treat_byte_string_as_slice.hash_stable(hcx, hasher); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c27a337554e67..6a4b53affbcc4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -678,9 +678,59 @@ impl CapturedPlace<'tcx> { pub fn get_root_variable(&self) -> hir::HirId { match self.place.base { HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, - base => bug!("Expected upvar, found={:?}", base), + base => bug!("expected upvar, found={:?}", base), } } + + /// Returns the `LocalDefId` of the closure that captureed this Place + pub fn get_closure_local_def_id(&self) -> LocalDefId { + match self.place.base { + HirPlaceBase::Upvar(upvar_id) => upvar_id.closure_expr_id, + base => bug!("expected upvar, found={:?}", base), + } + } + + /// Return span pointing to use that resulted in selecting the current capture kind + pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span { + if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id { + tcx.hir().span(capture_kind_expr_id) + } else if let Some(path_expr_id) = self.info.path_expr_id { + tcx.hir().span(path_expr_id) + } else { + // Fallback on upvars mentioned if neither path or capture expr id is captured + + // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars. + tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap() + [&self.get_root_variable()] + .span + } + } +} + +/// Return true if the `proj_possible_ancestor` represents an ancestor path +/// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`, +/// assuming they both start off of the same root variable. +/// +/// **Note:** It's the caller's responsibility to ensure that both lists of projections +/// start off of the same root variable. +/// +/// Eg: 1. `foo.x` which is represented using `projections=[Field(x)]` is an ancestor of +/// `foo.x.y` which is represented using `projections=[Field(x), Field(y)]`. +/// Note both `foo.x` and `foo.x.y` start off of the same root variable `foo`. +/// 2. Since we only look at the projections here function will return `bar.x` as an a valid +/// ancestor of `foo.x.y`. It's the caller's responsibility to ensure that both projections +/// list are being applied to the same root variable. +pub fn is_ancestor_or_same_capture( + proj_possible_ancestor: &[HirProjectionKind], + proj_capture: &[HirProjectionKind], +) -> bool { + // We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false. + // Therefore we can't just check if all projections are same in the zipped iterator below. + if proj_possible_ancestor.len() > proj_capture.len() { + return false; + } + + proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b) } pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 04ea3cbd8b66d..114524cd50eef 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -388,10 +388,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // so it's safe to call `expect_local`. // // We know the field exists so it's safe to call operator[] and `unwrap` here. - let (&var_id, _) = - self.infcx.tcx.typeck(def_id.expect_local()).closure_captures[&def_id] - .get_index(field.index()) - .unwrap(); + let var_id = self + .infcx + .tcx + .typeck(def_id.expect_local()) + .closure_min_captures_flattened(def_id) + .nth(field.index()) + .unwrap() + .get_root_variable(); self.infcx.tcx.hir().name(var_id).to_string() } @@ -966,12 +970,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr { - for (upvar_hir_id, place) in - self.infcx.tcx.typeck(def_id.expect_local()).closure_captures[&def_id] - .keys() - .zip(places) + for (captured_place, place) in self + .infcx + .tcx + .typeck(def_id.expect_local()) + .closure_min_captures_flattened(def_id) + .zip(places) { - let span = self.infcx.tcx.upvars_mentioned(local_did)?[upvar_hir_id].span; + let upvar_hir_id = captured_place.get_root_variable(); + //FIXME(project-rfc-2229#8): Use better span from captured_place + let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span; match place { Operand::Copy(place) | Operand::Move(place) if target_place == place.as_ref() => @@ -979,10 +987,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("closure_span: found captured local {:?}", place); let body = self.infcx.tcx.hir().body(*body_id); let generator_kind = body.generator_kind(); - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: *upvar_hir_id }, - closure_expr_id: local_did, - }; // If we have a more specific span available, point to that. // We do this even though this span might be part of a borrow error @@ -990,11 +994,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // to a span that shows why the upvar is used in the closure, // so a move-related span is as good as any (and potentially better, // if the overall error is due to a move of the upvar). - let usage_span = - match self.infcx.tcx.typeck(local_did).upvar_capture(upvar_id) { - ty::UpvarCapture::ByValue(Some(span)) => span, - _ => span, - }; + + let usage_span = match captured_place.info.capture_kind { + ty::UpvarCapture::ByValue(Some(span)) => span, + _ => span, + }; return Some((*args_span, generator_kind, usage_span)); } _ => {} diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 2f40a90fb5516..28f6508cab2da 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -510,24 +510,54 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { the_place_err: PlaceRef<'tcx>, err: &mut DiagnosticBuilder<'_>, ) { - let id = id.expect_local(); - let tables = tcx.typeck(id); - let hir_id = tcx.hir().local_def_id_to_hir_id(id); - if let Some((span, place)) = tables.closure_kind_origins().get(hir_id) { - let reason = if let PlaceBase::Upvar(upvar_id) = place.base { - let upvar = ty::place_to_string_for_capture(tcx, place); - match tables.upvar_capture(upvar_id) { - ty::UpvarCapture::ByRef(ty::UpvarBorrow { - kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, - .. - }) => { - format!("mutable borrow of `{}`", upvar) - } - ty::UpvarCapture::ByValue(_) => { - format!("possible mutation of `{}`", upvar) + let closure_local_def_id = id.expect_local(); + let tables = tcx.typeck(closure_local_def_id); + let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_local_def_id); + if let Some((span, closure_kind_origin)) = + &tables.closure_kind_origins().get(closure_hir_id) + { + let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base { + let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin); + let root_hir_id = upvar_id.var_path.hir_id; + // we have a origin for this closure kind starting at this root variable so it's safe to unwrap here + let captured_places = tables.closure_min_captures[id].get(&root_hir_id).unwrap(); + + let origin_projection = closure_kind_origin + .projections + .iter() + .map(|proj| proj.kind) + .collect::>(); + let mut capture_reason = String::new(); + for captured_place in captured_places { + let captured_place_kinds = captured_place + .place + .projections + .iter() + .map(|proj| proj.kind) + .collect::>(); + if rustc_middle::ty::is_ancestor_or_same_capture( + &captured_place_kinds, + &origin_projection, + ) { + match captured_place.info.capture_kind { + ty::UpvarCapture::ByRef(ty::UpvarBorrow { + kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, + .. + }) => { + capture_reason = format!("mutable borrow of `{}`", upvar); + } + ty::UpvarCapture::ByValue(_) => { + capture_reason = format!("possible mutation of `{}`", upvar); + } + _ => bug!("upvar `{}` borrowed, but not mutably", upvar), + } + break; } - val => bug!("upvar `{}` borrowed, but not mutably: {:?}", upvar, val), } + if capture_reason.is_empty() { + bug!("upvar `{}` borrowed, but cannot find reason", upvar); + } + capture_reason } else { bug!("not an upvar") }; diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 2d2799f81e392..062ef7d8b4cbf 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -77,7 +77,7 @@ macro_rules! throw_validation_failure { /// macro_rules! try_validation { ($e:expr, $where:expr, - $( $( $p:pat )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)? + $( $( $p:pat )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)? ) => {{ match $e { Ok(x) => x, @@ -244,17 +244,20 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // generators and closures. ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { let mut name = None; - if let Some(def_id) = def_id.as_local() { - let tables = self.ecx.tcx.typeck(def_id); - if let Some(upvars) = tables.closure_captures.get(&def_id.to_def_id()) { + // FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar + // https://github.com/rust-lang/project-rfc-2229/issues/46 + if let Some(local_def_id) = def_id.as_local() { + let tables = self.ecx.tcx.typeck(local_def_id); + if let Some(captured_place) = + tables.closure_min_captures_flattened(*def_id).nth(field) + { // Sometimes the index is beyond the number of upvars (seen // for a generator). - if let Some((&var_hir_id, _)) = upvars.get_index(field) { - let node = self.ecx.tcx.hir().get(var_hir_id); - if let hir::Node::Binding(pat) = node { - if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { - name = Some(ident.name); - } + let var_hir_id = captured_place.get_root_variable(); + let node = self.ecx.tcx.hir().get(var_hir_id); + if let hir::Node::Binding(pat) = node { + if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { + name = Some(ident.name); } } } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index b928458df8ee4..449976c383fc1 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -821,7 +821,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let hir_typeck_results = self.hir.typeck_results(); // In analyze_closure() in upvar.rs we gathered a list of upvars used by a - // indexed closure and we stored in a map called closure_captures in TypeckResults + // indexed closure and we stored in a map called closure_min_captures in TypeckResults // with the closure's DefId. Here, we run through that vec of UpvarIds for // the given closure and use the necessary information to create upvar // debuginfo and to fill `self.upvar_mutbls`. diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index a96f332374430..9aef49df7b4ff 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -95,7 +95,7 @@ use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; use rustc_index::vec::IndexVec; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, DefIdTree, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, RootVariableMinCaptureList, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; @@ -331,7 +331,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { } } - if let Some(captures) = maps.tcx.typeck(local_def_id).closure_captures.get(&def_id) { + if let Some(captures) = maps.tcx.typeck(local_def_id).closure_min_captures.get(&def_id) { for &var_hir_id in captures.keys() { let var_name = maps.tcx.hir().name(var_hir_id); maps.add_variable(Upvar(var_hir_id, var_name)); @@ -408,10 +408,10 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { if let Some(captures) = self .tcx .typeck(closure_def_id) - .closure_captures + .closure_min_captures .get(&closure_def_id.to_def_id()) { - // If closure captures is Some, upvars_mentioned must also be Some + // If closure_min_captures is Some, upvars_mentioned must also be Some let upvars = self.tcx.upvars_mentioned(closure_def_id).unwrap(); call_caps.extend(captures.keys().map(|var_id| { let upvar = upvars[var_id]; @@ -481,11 +481,10 @@ const ACC_USE: u32 = 4; struct Liveness<'a, 'tcx> { ir: &'a mut IrMaps<'tcx>, - body_owner: LocalDefId, typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, upvars: Option<&'tcx FxIndexMap>, - closure_captures: Option<&'tcx FxIndexMap>, + closure_min_captures: Option<&'tcx RootVariableMinCaptureList<'tcx>>, successors: IndexVec>, rwu_table: rwu_table::RWUTable, @@ -509,8 +508,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let typeck_results = ir.tcx.typeck(body_owner); let param_env = ir.tcx.param_env(body_owner); let upvars = ir.tcx.upvars_mentioned(body_owner); - let closure_captures = typeck_results.closure_captures.get(&body_owner.to_def_id()); - + let closure_min_captures = typeck_results.closure_min_captures.get(&body_owner.to_def_id()); let closure_ln = ir.add_live_node(ClosureNode); let exit_ln = ir.add_live_node(ExitNode); @@ -519,11 +517,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { Liveness { ir, - body_owner, typeck_results, param_env, upvars, - closure_captures, + closure_min_captures, successors: IndexVec::from_elem_n(None, num_live_nodes), rwu_table: rwu_table::RWUTable::new(num_live_nodes, num_vars), closure_ln, @@ -707,25 +704,27 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // if they are live on the entry to the closure, since only the closure // itself can access them on subsequent calls. - if let Some(closure_captures) = self.closure_captures { + if let Some(closure_min_captures) = self.closure_min_captures { // Mark upvars captured by reference as used after closure exits. - // Since closure_captures is Some, upvars must exists too. - let upvars = self.upvars.unwrap(); - for (&var_hir_id, upvar_id) in closure_captures { - let upvar = upvars[&var_hir_id]; - match self.typeck_results.upvar_capture(*upvar_id) { - ty::UpvarCapture::ByRef(_) => { - let var = self.variable(var_hir_id, upvar.span); - self.acc(self.exit_ln, var, ACC_READ | ACC_USE); + for (&var_hir_id, min_capture_list) in closure_min_captures { + for captured_place in min_capture_list { + match captured_place.info.capture_kind { + ty::UpvarCapture::ByRef(_) => { + let var = self.variable( + var_hir_id, + captured_place.get_capture_kind_span(self.ir.tcx), + ); + self.acc(self.exit_ln, var, ACC_READ | ACC_USE); + } + ty::UpvarCapture::ByValue(_) => {} } - ty::UpvarCapture::ByValue(_) => {} } } } let succ = self.propagate_through_expr(&body.value, self.exit_ln); - if self.closure_captures.is_none() { + if self.closure_min_captures.is_none() { // Either not a closure, or closure without any captured variables. // No need to determine liveness of captured variables, since there // are none. @@ -1221,7 +1220,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match path.res { Res::Local(hid) => { let in_upvars = self.upvars.map_or(false, |u| u.contains_key(&hid)); - let in_captures = self.closure_captures.map_or(false, |c| c.contains_key(&hid)); + let in_captures = self.closure_min_captures.map_or(false, |c| c.contains_key(&hid)); match (in_upvars, in_captures) { (false, _) | (true, true) => self.access_var(hir_id, hid, succ, acc, path.span), @@ -1422,52 +1421,52 @@ impl<'tcx> Liveness<'_, 'tcx> { } fn warn_about_unused_upvars(&self, entry_ln: LiveNode) { - let closure_captures = match self.closure_captures { + let closure_min_captures = match self.closure_min_captures { None => return, - Some(closure_captures) => closure_captures, + Some(closure_min_captures) => closure_min_captures, }; - // If closure_captures is Some(), upvars must be Some() too. - let upvars = self.upvars.unwrap(); - for &var_hir_id in closure_captures.keys() { - let upvar = upvars[&var_hir_id]; - let var = self.variable(var_hir_id, upvar.span); - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: self.body_owner, - }; - match self.typeck_results.upvar_capture(upvar_id) { - ty::UpvarCapture::ByValue(_) => {} - ty::UpvarCapture::ByRef(..) => continue, - }; - if self.used_on_entry(entry_ln, var) { - if !self.live_on_entry(entry_ln, var) { + // If closure_min_captures is Some(), upvars must be Some() too. + for (&var_hir_id, min_capture_list) in closure_min_captures { + for captured_place in min_capture_list { + match captured_place.info.capture_kind { + ty::UpvarCapture::ByValue(_) => {} + ty::UpvarCapture::ByRef(..) => continue, + }; + let span = captured_place.get_capture_kind_span(self.ir.tcx); + let var = self.variable(var_hir_id, span); + if self.used_on_entry(entry_ln, var) { + if !self.live_on_entry(entry_ln, var) { + if let Some(name) = self.should_warn(var) { + self.ir.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_ASSIGNMENTS, + var_hir_id, + vec![span], + |lint| { + lint.build(&format!( + "value captured by `{}` is never read", + name + )) + .help("did you mean to capture by reference instead?") + .emit(); + }, + ); + } + } + } else { if let Some(name) = self.should_warn(var) { self.ir.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_ASSIGNMENTS, + lint::builtin::UNUSED_VARIABLES, var_hir_id, - vec![upvar.span], + vec![span], |lint| { - lint.build(&format!("value captured by `{}` is never read", name)) + lint.build(&format!("unused variable: `{}`", name)) .help("did you mean to capture by reference instead?") .emit(); }, ); } } - } else { - if let Some(name) = self.should_warn(var) { - self.ir.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_VARIABLES, - var_hir_id, - vec![upvar.span], - |lint| { - lint.build(&format!("unused variable: `{}`", name)) - .help("did you mean to capture by reference instead?") - .emit(); - }, - ); - } } } } diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 88e8dd3cb129a..366b961b75165 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -771,21 +771,39 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { debug!("link_upvar_region(borrorw_region={:?}, upvar_id={:?}", borrow_region, upvar_id); // A by-reference upvar can't be borrowed for longer than the // upvar is borrowed from the environment. - match self.typeck_results.borrow().upvar_capture(upvar_id) { - ty::UpvarCapture::ByRef(upvar_borrow) => { - self.sub_regions( - infer::ReborrowUpvar(span, upvar_id), - borrow_region, - upvar_borrow.region, - ); - if let ty::ImmBorrow = upvar_borrow.kind { - debug!("link_upvar_region: capture by shared ref"); - return; + let closure_local_def_id = upvar_id.closure_expr_id; + let mut all_captures_are_imm_borrow = true; + for captured_place in self + .typeck_results + .borrow() + .closure_min_captures + .get(&closure_local_def_id.to_def_id()) + .and_then(|root_var_min_cap| root_var_min_cap.get(&upvar_id.var_path.hir_id)) + .into_iter() + .flatten() + { + match captured_place.info.capture_kind { + ty::UpvarCapture::ByRef(upvar_borrow) => { + self.sub_regions( + infer::ReborrowUpvar(span, upvar_id), + borrow_region, + upvar_borrow.region, + ); + if let ty::ImmBorrow = upvar_borrow.kind { + debug!("link_upvar_region: capture by shared ref"); + } else { + all_captures_are_imm_borrow = false; + } + } + ty::UpvarCapture::ByValue(_) => { + all_captures_are_imm_borrow = false; } } - ty::UpvarCapture::ByValue(_) => {} } - let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id); + if all_captures_are_imm_borrow { + return; + } + let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_local_def_id); let ty = self.resolve_node_type(fn_hir_id); debug!("link_upvar_region: ty={:?}", ty); diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 69c09528662d3..8d87b2d125106 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -220,8 +220,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.log_closure_min_capture_info(closure_def_id, span); - self.min_captures_to_closure_captures_bridge(closure_def_id); - // Now that we've analyzed the closure, we know how each // variable is borrowed, and we know what traits the closure // implements (Fn vs FnMut etc). We now have some updates to do @@ -284,80 +282,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect() } - /// Bridge for closure analysis - /// ---------------------------- - /// - /// For closure with DefId `c`, the bridge converts structures required for supporting RFC 2229, - /// to structures currently used in the compiler for handling closure captures. - /// - /// For example the following structure will be converted: - /// - /// closure_min_captures - /// foo -> [ {foo.x, ImmBorrow}, {foo.y, MutBorrow} ] - /// bar -> [ {bar.z, ByValue}, {bar.q, MutBorrow} ] - /// - /// to - /// - /// 1. closure_captures - /// foo -> UpvarId(foo, c), bar -> UpvarId(bar, c) - /// - /// 2. upvar_capture_map - /// UpvarId(foo,c) -> MutBorrow, UpvarId(bar, c) -> ByValue - fn min_captures_to_closure_captures_bridge(&self, closure_def_id: DefId) { - let mut closure_captures: FxIndexMap = Default::default(); - let mut upvar_capture_map = ty::UpvarCaptureMap::default(); - - if let Some(min_captures) = - self.typeck_results.borrow().closure_min_captures.get(&closure_def_id) - { - for (var_hir_id, min_list) in min_captures.iter() { - for captured_place in min_list { - let place = &captured_place.place; - let capture_info = captured_place.info; - - let upvar_id = match place.base { - PlaceBase::Upvar(upvar_id) => upvar_id, - base => bug!("Expected upvar, found={:?}", base), - }; - - assert_eq!(upvar_id.var_path.hir_id, *var_hir_id); - assert_eq!(upvar_id.closure_expr_id, closure_def_id.expect_local()); - - closure_captures.insert(*var_hir_id, upvar_id); - - let new_capture_kind = - if let Some(capture_kind) = upvar_capture_map.get(&upvar_id) { - // upvar_capture_map only stores the UpvarCapture (CaptureKind), - // so we create a fake capture info with no expression. - let fake_capture_info = ty::CaptureInfo { - capture_kind_expr_id: None, - path_expr_id: None, - capture_kind: *capture_kind, - }; - determine_capture_info(fake_capture_info, capture_info).capture_kind - } else { - capture_info.capture_kind - }; - upvar_capture_map.insert(upvar_id, new_capture_kind); - } - } - } - debug!("For closure_def_id={:?}, closure_captures={:#?}", closure_def_id, closure_captures); - debug!( - "For closure_def_id={:?}, upvar_capture_map={:#?}", - closure_def_id, upvar_capture_map - ); - - if !closure_captures.is_empty() { - self.typeck_results - .borrow_mut() - .closure_captures - .insert(closure_def_id, closure_captures); - - self.typeck_results.borrow_mut().upvar_capture_map.extend(upvar_capture_map); - } - } - /// Analyzes the information collected by `InferBorrowKind` to compute the min number of /// Places (and corresponding capture kind) that we need to keep track of to support all /// the required captured paths. diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index af82a3bb4f59a..bc34306e8226f 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -56,7 +56,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } wbcx.visit_body(body); wbcx.visit_min_capture_map(); - wbcx.visit_upvar_capture_map(); wbcx.visit_closures(); wbcx.visit_liberated_fn_sigs(); wbcx.visit_fru_field_types(); @@ -74,9 +73,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.typeck_results.treat_byte_string_as_slice = mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice); - wbcx.typeck_results.closure_captures = - mem::take(&mut self.typeck_results.borrow_mut().closure_captures); - if self.is_tainted_by_errors() { // FIXME(eddyb) keep track of `ErrorReported` from where the error was emitted. wbcx.typeck_results.tainted_by_errors = Some(ErrorReported); @@ -363,22 +359,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { self.typeck_results.closure_min_captures = min_captures_wb; } - fn visit_upvar_capture_map(&mut self) { - for (upvar_id, upvar_capture) in self.fcx.typeck_results.borrow().upvar_capture_map.iter() { - let new_upvar_capture = match *upvar_capture { - ty::UpvarCapture::ByValue(span) => ty::UpvarCapture::ByValue(span), - ty::UpvarCapture::ByRef(ref upvar_borrow) => { - ty::UpvarCapture::ByRef(ty::UpvarBorrow { - kind: upvar_borrow.kind, - region: self.tcx().lifetimes.re_erased, - }) - } - }; - debug!("Upvar capture for {:?} resolved to {:?}", upvar_id, new_upvar_capture); - self.typeck_results.upvar_capture_map.insert(*upvar_id, new_upvar_capture); - } - } - fn visit_closures(&mut self) { let fcx_typeck_results = self.fcx.typeck_results.borrow(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs new file mode 100644 index 0000000000000..09491f296f667 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.rs @@ -0,0 +1,91 @@ +// check-pass +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +#![allow(unreachable_code)] +#![warn(unused)] + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} + +pub fn f() { + let mut a = 1; + let mut c = Point{ x:1, y:0 }; + + // Captured by value, but variable is dead on entry. + (move || { + // This will not trigger a warning for unused variable as + // c.x will be treated as a Non-tracked place + c.x = 1; + println!("{}", c.x); + a = 1; //~ WARN value captured by `a` is never read + println!("{}", a); + })(); + + // Read and written to, but never actually used. + (move || { + // This will not trigger a warning for unused variable as + // c.x will be treated as a Non-tracked place + c.x += 1; + a += 1; //~ WARN unused variable: `a` + })(); + + (move || { + println!("{}", c.x); + // Value is read by closure itself on later invocations. + // This will not trigger a warning for unused variable as + // c.x will be treated as a Non-tracked place + c.x += 1; + println!("{}", a); + a += 1; + })(); + let b = Box::new(42); + (move || { + println!("{}", c.x); + // Never read because this is FnOnce closure. + // This will not trigger a warning for unused variable as + // c.x will be treated as a Non-tracked place + c.x += 1; + println!("{}", a); + a += 1; //~ WARN value assigned to `a` is never read + drop(b); + })(); +} + +#[derive(Debug)] +struct MyStruct<'a> { + x: Option<& 'a str>, + y: i32, +} + +pub fn nested() { + let mut a : Option<& str>; + a = None; + let mut b : Option<& str>; + b = None; + let mut d = MyStruct{ x: None, y: 1}; + let mut e = MyStruct{ x: None, y: 1}; + (|| { + (|| { + // This will not trigger a warning for unused variable as + // d.x will be treated as a Non-tracked place + d.x = Some("d1"); + d.x = Some("d2"); + a = Some("d1"); //~ WARN value assigned to `a` is never read + a = Some("d2"); + })(); + (move || { + // This will not trigger a warning for unused variable as + //e.x will be treated as a Non-tracked place + e.x = Some("e1"); + e.x = Some("e2"); + b = Some("e1"); //~ WARN value assigned to `b` is never read + //~| WARN unused variable: `b` + b = Some("e2"); //~ WARN value assigned to `b` is never read + })(); + })(); +} + +fn main() {} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr new file mode 100644 index 0000000000000..81bbc4e1dc0c2 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness.stderr @@ -0,0 +1,79 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/liveness.rs:2:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: value captured by `a` is never read + --> $DIR/liveness.rs:23:9 + | +LL | a = 1; + | ^ + | +note: the lint level is defined here + --> $DIR/liveness.rs:5:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]` + = help: did you mean to capture by reference instead? + +warning: unused variable: `a` + --> $DIR/liveness.rs:32:9 + | +LL | a += 1; + | ^ + | +note: the lint level is defined here + --> $DIR/liveness.rs:5:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + = help: did you mean to capture by reference instead? + +warning: value assigned to `a` is never read + --> $DIR/liveness.rs:52:9 + | +LL | a += 1; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `a` is never read + --> $DIR/liveness.rs:76:13 + | +LL | a = Some("d1"); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `b` is never read + --> $DIR/liveness.rs:84:13 + | +LL | b = Some("e1"); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `b` is never read + --> $DIR/liveness.rs:86:13 + | +LL | b = Some("e2"); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `b` + --> $DIR/liveness.rs:84:13 + | +LL | b = Some("e1"); + | ^ + | + = help: did you mean to capture by reference instead? + +warning: 8 warnings emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs new file mode 100644 index 0000000000000..e2035464dfa8a --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.rs @@ -0,0 +1,42 @@ +// check-pass +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +#![warn(unused)] + +#[derive(Debug)] +struct MyStruct { + a: i32, + b: i32, +} + +pub fn unintentional_copy_one() { + let mut a = 1; + let mut last = MyStruct{ a: 1, b: 1}; + let mut f = move |s| { + // This will not trigger a warning for unused variable + // as last.a will be treated as a Non-tracked place + last.a = s; + a = s; + //~^ WARN value assigned to `a` is never read + //~| WARN unused variable: `a` + }; + f(2); + f(3); + f(4); +} + +pub fn unintentional_copy_two() { + let mut a = 1; + let mut sum = MyStruct{ a: 1, b: 0}; + (1..10).for_each(move |x| { + // This will not trigger a warning for unused variable + // as sum.b will be treated as a Non-tracked place + sum.b += x; + a += x; //~ WARN unused variable: `a` + }); +} + +fn main() { + unintentional_copy_one(); + unintentional_copy_two(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr new file mode 100644 index 0000000000000..35b0c22fc4fb9 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/liveness_unintentional_copy.stderr @@ -0,0 +1,47 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/liveness_unintentional_copy.rs:2:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: value assigned to `a` is never read + --> $DIR/liveness_unintentional_copy.rs:19:9 + | +LL | a = s; + | ^ + | +note: the lint level is defined here + --> $DIR/liveness_unintentional_copy.rs:4:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]` + = help: maybe it is overwritten before being read? + +warning: unused variable: `a` + --> $DIR/liveness_unintentional_copy.rs:19:9 + | +LL | a = s; + | ^ + | +note: the lint level is defined here + --> $DIR/liveness_unintentional_copy.rs:4:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + = help: did you mean to capture by reference instead? + +warning: unused variable: `a` + --> $DIR/liveness_unintentional_copy.rs:35:9 + | +LL | a += x; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: 4 warnings emitted + From 1ad8bfbc4ffbbd7e6be14bc73242b02eff9b74d4 Mon Sep 17 00:00:00 2001 From: Chris Pardy Date: Wed, 17 Mar 2021 02:51:27 -0400 Subject: [PATCH 2/4] bring in path spans to ClosureUse, to_string for captured_place --- compiler/rustc_middle/src/mir/mod.rs | 2 + compiler/rustc_middle/src/ty/mod.rs | 20 ++++ .../diagnostics/conflict_errors.rs | 6 ++ .../diagnostics/explain_borrow.rs | 71 ++++++++++---- .../src/borrow_check/diagnostics/mod.rs | 67 +++++++------ .../borrow_check/diagnostics/move_errors.rs | 2 +- .../diagnostics/mutability_errors.rs | 2 +- .../borrow_check/diagnostics/region_errors.rs | 1 + compiler/rustc_mir/src/borrow_check/mod.rs | 8 +- .../borrowck/borrowck-closures-mut-and-imm.rs | 1 + .../diagnostics/borrowck/borrowck-1.rs | 18 ++++ .../diagnostics/borrowck/borrowck-2.rs | 27 ++++++ .../borrowck/borrowck-closures-mut-and-imm.rs | 97 +++++++++++++++++++ 13 files changed, 269 insertions(+), 53 deletions(-) create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4d8615a215fc0..4c91f56ba191f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2318,6 +2318,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { }; let mut struct_fmt = fmt.debug_struct(&name); + // FIXME: This should be a list of capture names/places if let Some(upvars) = tcx.upvars_mentioned(def_id) { for (&var_id, place) in upvars.keys().zip(places) { let var_name = tcx.hir().name(var_id); @@ -2337,6 +2338,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let name = format!("[generator@{:?}]", tcx.hir().span(hir_id)); let mut struct_fmt = fmt.debug_struct(&name); + // FIXME: This should be a list of capture names/places if let Some(upvars) = tcx.upvars_mentioned(def_id) { for (&var_id, place) in upvars.keys().zip(places) { let var_name = tcx.hir().name(var_id); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6a4b53affbcc4..009571c5eeaab 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -673,6 +673,10 @@ pub struct CapturedPlace<'tcx> { } impl CapturedPlace<'tcx> { + pub fn to_string(&self, tcx: TyCtxt<'tcx>) -> String { + place_to_string_for_capture(tcx, &self.place) + } + /// Returns the hir-id of the root variable for the captured place. /// e.g., if `a.b.c` was captured, would return the hir-id for `a`. pub fn get_root_variable(&self) -> hir::HirId { @@ -690,6 +694,22 @@ impl CapturedPlace<'tcx> { } } + /// Return span pointing to use that resulted in selecting the captured path + pub fn get_path_span(&self, tcx: TyCtxt<'tcx>) -> Span { + if let Some(path_expr_id) = self.info.path_expr_id { + tcx.hir().span(path_expr_id) + } else if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id { + tcx.hir().span(capture_kind_expr_id) + } else { + // Fallback on upvars mentioned if neither path or capture expr id is captured + + // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars. + tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap() + [&self.get_root_variable()] + .span + } + } + /// Return span pointing to use that resulted in selecting the current capture kind pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span { if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 24b9408ffb657..ec6847be6e56e 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -433,11 +433,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.args_or_use(); + // cpardy // Conflicting borrows are reported separately, so only check for move // captures. let use_spans = self.move_spans(place.as_ref(), location); let span = use_spans.var_or_use(); + // If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use + // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure let mut err = self.cannot_use_when_mutably_borrowed( span, &self.describe_any_place(place.as_ref()), @@ -817,6 +820,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); let borrow_spans = self.retrieve_borrow_spans(borrow); + // cpardy: borrowed value doesn't live long enough, in closure case either span should be fine let borrow_span = borrow_spans.var_or_use(); assert!(root_place.projection.is_empty()); @@ -957,6 +961,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location, name, borrow, drop_span, borrow_spans ); + // cpardy: I think this one should be ok seems to be about local values, not captures let borrow_span = borrow_spans.var_or_use(); if let BorrowExplanation::MustBeValidFor { category, @@ -1072,6 +1077,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); let borrow_spans = self.retrieve_borrow_spans(borrow); + // cpardy: Not really sure about this one let borrow_span = borrow_spans.var_or_use(); let mut err = self.cannot_borrow_across_destructor(borrow_span); diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index 06e3f4b91f61f..b5a71b418e1c6 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -24,8 +24,8 @@ use super::{find_use, RegionName, UseSpans}; #[derive(Debug)] pub(in crate::borrow_check) enum BorrowExplanation { - UsedLater(LaterUseKind, Span), - UsedLaterInLoop(LaterUseKind, Span), + UsedLater(LaterUseKind, Span, Option), + UsedLaterInLoop(LaterUseKind, Span, Option), UsedLaterWhenDropped { drop_loc: Location, dropped_local: Local, @@ -67,7 +67,7 @@ impl BorrowExplanation { borrow_span: Option, ) { match *self { - BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => { + BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => { let message = match later_use_kind { LaterUseKind::TraitCapture => "captured here by trait object", LaterUseKind::ClosureCapture => "captured here by closure", @@ -75,14 +75,31 @@ impl BorrowExplanation { LaterUseKind::FakeLetRead => "stored here", LaterUseKind::Other => "used here", }; - if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { - err.span_label( - var_or_use_span, - format!("{}borrow later {}", borrow_desc, message), - ); + // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same + if path_span.map_or(true, |path_span| path_span == var_or_use_span) { + if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { + err.span_label( + var_or_use_span, + format!("{}borrow later {}", borrow_desc, message), + ); + } + } else { + // path_span must be `Some` as otherwise the if condition is true + let path_span = path_span.unwrap(); + // path_span is only present in the case of closure capture + assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); + if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { + let path_label = "used here by closure"; + let capture_kind_label = message; + err.span_label( + var_or_use_span, + format!("{}borrow later {}", borrow_desc, capture_kind_label), + ); + err.span_label(path_span, path_label); + } } } - BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => { + BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) => { let message = match later_use_kind { LaterUseKind::TraitCapture => { "borrow captured here by trait object, in later iteration of loop" @@ -94,7 +111,24 @@ impl BorrowExplanation { LaterUseKind::FakeLetRead => "borrow later stored here", LaterUseKind::Other => "borrow used here, in later iteration of loop", }; - err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message)); + // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same + if path_span.map_or(true, |path_span| path_span == var_or_use_span) { + err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message)); + } else { + // path_span must be `Some` as otherwise the if condition is true + let path_span = path_span.unwrap(); + // path_span is only present in the case of closure capture + assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture)); + if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { + let path_label = "used here by closure"; + let capture_kind_label = message; + err.span_label( + var_or_use_span, + format!("{}borrow later {}", borrow_desc, capture_kind_label), + ); + err.span_label(path_span, path_label); + } + } } BorrowExplanation::UsedLaterWhenDropped { drop_loc, @@ -311,13 +345,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let borrow_location = location; if self.is_use_in_later_iteration_of_loop(borrow_location, location) { let later_use = self.later_use_kind(borrow, spans, location); - BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1) + BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2) } else { // Check if the location represents a `FakeRead`, and adapt the error // message to the `FakeReadCause` it is from: in particular, // the ones inserted in optimized `let var = ` patterns. let later_use = self.later_use_kind(borrow, spans, location); - BorrowExplanation::UsedLater(later_use.0, later_use.1) + BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2) } } @@ -498,16 +532,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } /// Determine how the borrow was later used. + /// First span returned points to the location of the conflicting use + /// Second span if `Some` is returned in the case of closures and points + /// to the use of the path fn later_use_kind( &self, borrow: &BorrowData<'tcx>, use_spans: UseSpans<'tcx>, location: Location, - ) -> (LaterUseKind, Span) { + ) -> (LaterUseKind, Span, Option) { match use_spans { - UseSpans::ClosureUse { var_span, .. } => { + UseSpans::ClosureUse { capture_kind_span, path_span, .. } => { // Used in a closure. - (LaterUseKind::ClosureCapture, var_span) + (LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span)) } UseSpans::PatUse(span) | UseSpans::OtherUse(span) @@ -542,7 +579,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } }; - return (LaterUseKind::Call, function_span); + return (LaterUseKind::Call, function_span, None); } else { LaterUseKind::Other } @@ -550,7 +587,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { LaterUseKind::Other }; - (kind, span) + (kind, span, None) } } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 114524cd50eef..55801f2877bbd 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -215,11 +215,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { PlaceRef { local, projection: [proj_base @ .., elem] } => { match elem { ProjectionElem::Deref => { - // FIXME(project-rfc_2229#36): print capture precisely here. let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); - let name = self.upvars[var_index].name.to_string(); + let name = self.upvars[var_index].place.to_string(self.infcx.tcx); if self.upvars[var_index].by_ref { buf.push_str(&name); } else { @@ -264,7 +263,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); - let name = self.upvars[var_index].name.to_string(); + let name = self.upvars[var_index].place.to_string(self.infcx.tcx); buf.push_str(&name); } else { let field_name = self @@ -549,8 +548,12 @@ pub(super) enum UseSpans<'tcx> { /// The span of the args of the closure, including the `move` keyword if /// it's present. args_span: Span, - /// The span of the first use of the captured variable inside the closure. - var_span: Span, + /// The span of the use resulting in capture kind + /// Check `ty::CaptureInfo` for more details + capture_kind_span: Span, + /// The span of the use resulting in the captured path + /// Check `ty::CaptureInfo` for more details + path_span: Span, }, /// The access is caused by using a variable as the receiver of a method /// that takes 'self' @@ -599,9 +602,10 @@ impl UseSpans<'_> { } } + // FIXME Add a path_span variant of this function pub(super) fn var_or_use(self) -> Span { match self { - UseSpans::ClosureUse { var_span: span, .. } + UseSpans::ClosureUse { capture_kind_span: span, .. } | UseSpans::PatUse(span) | UseSpans::OtherUse(span) => span, UseSpans::FnSelfUse { @@ -635,8 +639,15 @@ impl UseSpans<'_> { err: &mut DiagnosticBuilder<'_>, message: impl Into, ) { - if let UseSpans::ClosureUse { var_span, .. } = self { - err.span_label(var_span, message); + if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self { + if capture_kind_span == path_span { + err.span_label(capture_kind_span, message); + } else { + let path_label = "which is captured in it's entirety because of its use here"; + let capture_kind_label = message; + err.span_label(capture_kind_span, capture_kind_label); + err.span_label(path_span, path_label); + } } } @@ -784,10 +795,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { box AggregateKind::Closure(def_id, _) | box AggregateKind::Generator(def_id, _, _) => { debug!("move_spans: def_id={:?} places={:?}", def_id, places); - if let Some((args_span, generator_kind, var_span)) = + if let Some((args_span, generator_kind, capture_kind_span, path_span)) = self.closure_span(*def_id, moved_place, places) { - return ClosureUse { generator_kind, args_span, var_span }; + return ClosureUse { + generator_kind, + args_span, + capture_kind_span, + path_span, + }; } } _ => {} @@ -937,10 +953,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "borrow_spans: def_id={:?} is_generator={:?} places={:?}", def_id, is_generator, places ); - if let Some((args_span, generator_kind, var_span)) = + if let Some((args_span, generator_kind, capture_kind_span, path_span)) = self.closure_span(*def_id, Place::from(target).as_ref(), places) { - return ClosureUse { generator_kind, args_span, var_span }; + return ClosureUse { generator_kind, args_span, capture_kind_span, path_span }; } else { return OtherUse(use_span); } @@ -954,13 +970,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { OtherUse(use_span) } - /// Finds the span of a captured variable within a closure or generator. + /// Finds the spans of a captured place within a closure or generator. + /// The first span is the location of the use resulting in the capture kind of the capture + /// The second span is the location the use resulting in the captured path of the capture fn closure_span( &self, def_id: DefId, target_place: PlaceRef<'tcx>, places: &[Operand<'tcx>], - ) -> Option<(Span, Option, Span)> { + ) -> Option<(Span, Option, Span, Span)> { debug!( "closure_span: def_id={:?} target_place={:?} places={:?}", def_id, target_place, places @@ -977,9 +995,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .closure_min_captures_flattened(def_id) .zip(places) { - let upvar_hir_id = captured_place.get_root_variable(); - //FIXME(project-rfc-2229#8): Use better span from captured_place - let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span; match place { Operand::Copy(place) | Operand::Move(place) if target_place == place.as_ref() => @@ -988,18 +1003,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let body = self.infcx.tcx.hir().body(*body_id); let generator_kind = body.generator_kind(); - // If we have a more specific span available, point to that. - // We do this even though this span might be part of a borrow error - // message rather than a move error message. Our goal is to point - // to a span that shows why the upvar is used in the closure, - // so a move-related span is as good as any (and potentially better, - // if the overall error is due to a move of the upvar). - - let usage_span = match captured_place.info.capture_kind { - ty::UpvarCapture::ByValue(Some(span)) => span, - _ => span, - }; - return Some((*args_span, generator_kind, usage_span)); + return Some(( + *args_span, + generator_kind, + captured_place.get_capture_kind_span(self.infcx.tcx), + captured_place.get_path_span(self.infcx.tcx), + )); } _ => {} } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs index fb7694b7d88e9..7008c935b92e5 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs @@ -348,7 +348,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // FIXME(project-rfc-2229#8): Improve borrow-check diagnostics in case of precise // capture. let upvar_hir_id = upvar.place.get_root_variable(); - let upvar_name = upvar.name; + let upvar_name = upvar.place.to_string(self.infcx.tcx); let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); let place_name = self.describe_any_place(move_place.as_ref()); diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 28f6508cab2da..0becda152ba61 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -85,7 +85,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if self.is_upvar_field_projection(access_place.as_ref()).is_some() { reason = ", as it is not declared as mutable".to_string(); } else { - let name = self.upvars[upvar_index.index()].name; + let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx); reason = format!(", as `{}` is not declared as mutable", name); } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs index 058986593a41b..c3f781c0e9e30 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs @@ -385,6 +385,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { diag.span_label(*span, message); + // FIXME: This should store a captured_place not a hir id if let ReturnConstraint::ClosureUpvar(upvar) = kind { let def_id = match self.regioncx.universal_regions().defining_ty { DefiningTy::Closure(def_id, _) => def_id, diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 375d464917118..fe7c423bec75d 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -73,9 +73,6 @@ crate use region_infer::RegionInferenceContext; // FIXME(eddyb) perhaps move this somewhere more centrally. #[derive(Debug)] crate struct Upvar<'tcx> { - // FIXME(project-rfc_2229#36): print capture precisely here. - name: Symbol, - place: CapturedPlace<'tcx>, /// If true, the capture is behind a reference. @@ -158,13 +155,12 @@ fn do_mir_borrowck<'a, 'tcx>( let upvars: Vec<_> = tables .closure_min_captures_flattened(def.did.to_def_id()) .map(|captured_place| { - let var_hir_id = captured_place.get_root_variable(); let capture = captured_place.info.capture_kind; let by_ref = match capture { ty::UpvarCapture::ByValue(_) => false, ty::UpvarCapture::ByRef(..) => true, }; - Upvar { name: tcx.hir().name(var_hir_id), place: captured_place.clone(), by_ref } + Upvar { place: captured_place.clone(), by_ref } }) .collect(); @@ -1564,6 +1560,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if borrow_of_local_data(borrow.borrowed_place) { let err = self.cannot_borrow_across_generator_yield( + //cpardy: I think this is fine, comment above suggests this only happens if a generator is yielding local data, + // unrelated to closure captures self.retrieve_borrow_spans(borrow).var_or_use(), yield_span, ); diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs index 2dc405ffcd4c0..74831c646b558 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs +++ b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs @@ -1,6 +1,7 @@ // Tests that two closures cannot simultaneously have mutable // and immutable access to the variable. Issue #6801. +#![feature(capture_disjoint_fields)] #![feature(box_syntax)] fn get(x: &isize) -> isize { diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs new file mode 100644 index 0000000000000..b19faa7e74109 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs @@ -0,0 +1,18 @@ +#![feature(capture_disjoint_fields)] + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} +fn main() { + let mut p = Point {x: 1, y: 2 }; + + let y = &mut p.y; + let mut c = || { + let x = &mut p.x; + println!("{:?}", p); + }; + c(); + *y+=1; +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs new file mode 100644 index 0000000000000..27172455d7359 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs @@ -0,0 +1,27 @@ +#![feature(capture_disjoint_fields)] + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} +fn foo () -> impl FnMut()->() { + let mut p = Point {x: 1, y: 2 }; + let mut c = || { + p.x+=5; + println!("{:?}", p); + }; + c +} +fn main() { + // let c = foo(); + let mut p = Point {x: 1, y: 2 }; + + let y = &p.y; + let mut c = || { + println!("{:?}", p); + let x = &mut p.x; + }; + c(); + println!("{}", y); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs new file mode 100644 index 0000000000000..298613e1e673d --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs @@ -0,0 +1,97 @@ +// Tests that two closures cannot simultaneously have mutable +// and immutable access to the variable. Issue #6801. + +#![feature(capture_disjoint_fields)] +#![feature(box_syntax)] + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} + +fn get(x: &isize) -> isize { + *x +} + +fn set(x: &mut isize) { + *x = 4; +} + +fn a() { + let mut p = Point {x: 3, y:4}; + let c2 = || p.y * 5; + let c1 = || { + dbg!(&p); + p.x = 4; + }; + //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + drop(c2); +} + +// fn b() { +// let mut x = 3; +// let c1 = || set(&mut x); +// let c2 = || get(&x); +// //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable +// drop(c1); +// } + +// fn c() { +// let mut x = 3; +// let c1 = || set(&mut x); +// let c2 = || x * 5; +// //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable +// drop(c1); +// } + +// fn d() { +// let mut x = 3; +// let c2 = || x * 5; +// x = 5; +// //~^ ERROR cannot assign to `x` because it is borrowed +// drop(c2); +// } + +// fn e() { +// let mut x = 3; +// let c1 = || get(&x); +// x = 5; +// //~^ ERROR cannot assign to `x` because it is borrowed +// drop(c1); +// } + +// fn f() { +// let mut x: Box<_> = box 3; +// let c1 = || get(&*x); +// *x = 5; +// //~^ ERROR cannot assign to `*x` because it is borrowed +// drop(c1); +// } + +// fn g() { +// struct Foo { +// f: Box +// } + +// let mut x: Box<_> = box Foo { f: box 3 }; +// let c1 = || get(&*x.f); +// *x.f = 5; +// //~^ ERROR cannot assign to `*x.f` because it is borrowed +// drop(c1); +// } + +// fn h() { +// struct Foo { +// f: Box +// } + +// let mut x: Box<_> = box Foo { f: box 3 }; +// let c1 = || get(&*x.f); +// let c2 = || *x.f = 5; +// //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable +// drop(c1); +// } + +fn main() { +} From 674c229ece1a14ad5efd14538dbf3e2ca17eb88e Mon Sep 17 00:00:00 2001 From: Chris Pardy Date: Wed, 17 Mar 2021 15:52:25 -0400 Subject: [PATCH 3/4] add tests --- .../diagnostics/borrowck/borrowck-1.stderr | 27 +++++++++++++++++ .../diagnostics/borrowck/borrowck-2.rs | 9 ------ .../diagnostics/borrowck/borrowck-2.stderr | 27 +++++++++++++++++ .../diagnostics/borrowck/borrowck-3.rs | 17 +++++++++++ .../diagnostics/borrowck/borrowck-3.stderr | 26 ++++++++++++++++ .../diagnostics/borrowck/borrowck-4.rs | 19 ++++++++++++ .../diagnostics/borrowck/borrowck-4.stderr | 30 +++++++++++++++++++ .../borrowck-closures-mut-and-imm.stderr | 29 ++++++++++++++++++ 8 files changed, 175 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr new file mode 100644 index 0000000000000..2c357b147c65f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr @@ -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/borrowck-1.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0499]: cannot borrow `p` as mutable more than once at a time + --> $DIR/borrowck-1.rs:12:17 + | +LL | let y = &mut p.y; + | -------- first mutable borrow occurs here +LL | let mut c = || { + | ^^ second mutable borrow occurs here +LL | let x = &mut p.x; + | --- second borrow occurs due to use of `p` in closure +LL | println!("{:?}", p); + | - which is captured in it's entirety because of its use here +... +LL | *y+=1; + | ----- first borrow later used here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs index 27172455d7359..7559ed17fa155 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs @@ -5,16 +5,7 @@ struct Point { x: i32, y: i32, } -fn foo () -> impl FnMut()->() { - let mut p = Point {x: 1, y: 2 }; - let mut c = || { - p.x+=5; - println!("{:?}", p); - }; - c -} fn main() { - // let c = foo(); let mut p = Point {x: 1, y: 2 }; let y = &p.y; diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr new file mode 100644 index 0000000000000..88fc25bd1e3a7 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr @@ -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/borrowck-2.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 `p` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-2.rs:12:17 + | +LL | let y = &p.y; + | ---- immutable borrow occurs here +LL | let mut c = || { + | ^^ mutable borrow occurs here +LL | println!("{:?}", p); + | - which is captured in it's entirety because of its use here +LL | let x = &mut p.x; + | --- second borrow occurs due to use of `p` in closure +... +LL | println!("{}", y); + | - immutable borrow later used 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/diagnostics/borrowck/borrowck-3.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs new file mode 100644 index 0000000000000..a4690f2b90f67 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs @@ -0,0 +1,17 @@ +#![feature(capture_disjoint_fields)] + +#[derive(Debug)] +struct Point { + x: String, + y: String, +} +fn main() { + let mut c = { + let mut p = Point {x: "1".to_string(), y: "2".to_string() }; + || { + let x = &mut p.x; + println!("{:?}", p); + } + }; + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr new file mode 100644 index 0000000000000..888632c6f674d --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr @@ -0,0 +1,26 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/borrowck-3.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0597]: `p` does not live long enough + --> $DIR/borrowck-3.rs:12:25 + | +LL | let mut c = { + | ----- borrow later stored here +LL | let mut p = Point {x: "1".to_string(), y: "2".to_string() }; +LL | || { + | -- value captured here +LL | let x = &mut p.x; + | ^^^ borrowed value does not live long enough +... +LL | }; + | - `p` dropped here while still borrowed + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs new file mode 100644 index 0000000000000..37ad1bbd7f8cb --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs @@ -0,0 +1,19 @@ +#![feature(capture_disjoint_fields)] + +#[derive(Debug)] +struct Point { + x: i32, + y: i32, +} +fn foo () -> impl FnMut()->() { + let mut p = Point {x: 1, y: 2 }; + let mut c = || { + p.x+=5; + println!("{:?}", p); + }; + c +} +fn main() { + let c = foo(); + c(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr new file mode 100644 index 0000000000000..403cdc034efea --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr @@ -0,0 +1,30 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/borrowck-4.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0373]: closure may outlive the current function, but it borrows `p`, which is owned by the current function + --> $DIR/borrowck-4.rs:10:17 + | +LL | let mut c = || { + | ^^ may outlive borrowed value `p` +LL | p.x+=5; + | --- `p` is borrowed here + | +note: closure is returned here + --> $DIR/borrowck-4.rs:8:14 + | +LL | fn foo () -> impl FnMut()->() { + | ^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword + | +LL | let mut c = move || { + | ^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr new file mode 100644 index 0000000000000..d44f20ed4dda1 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr @@ -0,0 +1,29 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/borrowck-closures-mut-and-imm.rs:4:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-mut-and-imm.rs:24:14 + | +LL | let c2 = || p.y * 5; + | -- --- first borrow occurs due to use of `p.y` in closure + | | + | immutable borrow occurs here +LL | let c1 = || { + | ^^ mutable borrow occurs here +LL | dbg!(&p); + | - which is captured in it's entirety because of its use here +LL | p.x = 4; + | --- second borrow occurs due to use of `p` in closure +... +LL | drop(c2); + | -- immutable borrow later used here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0502`. From 4a9850fed469d599a3c9f32c0d968a83ec9ce4c1 Mon Sep 17 00:00:00 2001 From: Chris Pardy Date: Thu, 15 Apr 2021 18:42:54 -0400 Subject: [PATCH 4/4] closure diags --- compiler/rustc_middle/src/mir/mod.rs | 9 +++ .../diagnostics/conflict_errors.rs | 46 +++++++----- .../src/borrow_check/diagnostics/mod.rs | 20 ++++- .../borrow_check/diagnostics/move_errors.rs | 7 +- .../diagnostics/mutability_errors.rs | 1 + ...async-borrowck-escaping-block-error.stderr | 6 +- .../borrowck/borrowck-closures-mut-and-imm.rs | 1 - .../borrowck-closures-mut-and-imm.stderr | 8 +- .../borrowck-closures-mut-of-imm.stderr | 4 +- .../borrowck-closures-mut-of-mut.stderr | 4 +- .../borrowck-closures-slice-patterns.stderr | 8 +- .../borrowck-closures-two-mut-fail.stderr | 6 +- .../borrowck/borrowck-closures-two-mut.stderr | 6 +- .../borrowck/borrowck-closures-unique.stderr | 2 +- .../borrowck-closures-use-after-free.stderr | 2 +- .../borrowck-insert-during-each.stderr | 4 +- .../borrowck-loan-blocks-move-cc.stderr | 4 +- .../ui/borrowck/borrowck-loan-rcvr.stderr | 2 +- .../borrowck/borrowck-move-by-capture.stderr | 8 +- ...rowck-move-moved-value-into-closure.stderr | 4 +- ...27282-mutate-before-diverging-arm-2.stderr | 2 +- ...sue-27282-reborrow-ref-mut-in-guard.stderr | 2 +- ...issue-58776-borrowck-scans-children.stderr | 4 +- .../diagnostics/borrowck/borrowck-1.rs | 2 + .../diagnostics/borrowck/borrowck-1.stderr | 7 +- .../diagnostics/borrowck/borrowck-2.rs | 2 + .../diagnostics/borrowck/borrowck-2.stderr | 7 +- .../diagnostics/borrowck/borrowck-3.rs | 2 + .../diagnostics/borrowck/borrowck-3.stderr | 5 +- .../diagnostics/borrowck/borrowck-4.rs | 2 + .../diagnostics/borrowck/borrowck-4.stderr | 9 ++- .../borrowck/borrowck-closures-mut-and-imm.rs | 75 +------------------ .../borrowck-closures-mut-and-imm.stderr | 9 ++- .../diagnostics/box.stderr | 6 +- .../diagnostics/cant-mutate-imm-borrow.stderr | 2 +- .../diagnostics/cant-mutate-imm.rs | 4 +- .../diagnostics/cant-mutate-imm.stderr | 4 +- .../diagnostics/multilevel-path.stderr | 2 +- .../diagnostics/mut_ref.stderr | 4 +- .../simple-struct-min-capture.stderr | 4 +- src/test/ui/error-codes/E0504.stderr | 2 +- .../yield-while-ref-reborrowed.stderr | 2 +- src/test/ui/issues/issue-11192.stderr | 2 +- ...27282-mutate-before-diverging-arm-1.stderr | 2 +- ...27282-mutate-before-diverging-arm-3.stderr | 2 +- src/test/ui/issues/issue-61623.stderr | 2 +- src/test/ui/issues/issue-6801.stderr | 2 +- src/test/ui/nll/closure-access-spans.stderr | 4 +- src/test/ui/nll/closure-borrow-spans.stderr | 12 +-- src/test/ui/nll/closure-captures.stderr | 12 +-- .../escape-upvar-nested.stderr | 4 +- src/test/ui/nll/closure-use-spans.stderr | 4 +- src/test/ui/nll/closures-in-loops.stderr | 2 +- src/test/ui/nll/issue-51268.stderr | 2 +- 54 files changed, 171 insertions(+), 189 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4c91f56ba191f..c8336c0015d30 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -700,6 +700,15 @@ impl BorrowKind { BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, } } + + pub fn describe_mutability(&self) -> String { + match *self { + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => { + "immutable".to_string() + } + BorrowKind::Mut { .. } => "mutable".to_string(), + } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index ec6847be6e56e..9f07b78d62ddd 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -99,7 +99,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); err.span_label(span, format!("use of possibly-uninitialized {}", item_msg)); - use_spans.var_span_label( + use_spans.var_span_label_path_only( &mut err, format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), ); @@ -242,6 +242,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { partially_str, move_spans.describe() ), + "moved", ); } } @@ -274,7 +275,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - use_spans.var_span_label( + use_spans.var_span_label_path_only( &mut err, format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()), ); @@ -404,13 +405,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg)); err.span_label(span, format!("move out of {} occurs here", value_msg)); - borrow_spans.var_span_label( + borrow_spans.var_span_label_path_only( &mut err, format!("borrow occurs due to use{}", borrow_spans.describe()), ); - move_spans - .var_span_label(&mut err, format!("move occurs due to use{}", move_spans.describe())); + move_spans.var_span_label( + &mut err, + format!("move occurs due to use{}", move_spans.describe()), + "moved", + ); self.explain_why_borrow_contains_point(location, borrow, None) .add_explanation_to_diagnostic( @@ -433,7 +437,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.args_or_use(); - // cpardy // Conflicting borrows are reported separately, so only check for move // captures. let use_spans = self.move_spans(place.as_ref(), location); @@ -448,11 +451,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self.describe_any_place(borrow.borrowed_place.as_ref()), ); - borrow_spans.var_span_label(&mut err, { - let place = &borrow.borrowed_place; - let desc_place = self.describe_any_place(place.as_ref()); - format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe()) - }); + borrow_spans.var_span_label( + &mut err, + { + let place = &borrow.borrowed_place; + let desc_place = self.describe_any_place(place.as_ref()); + format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe()) + }, + "mutable", + ); self.explain_why_borrow_contains_point(location, borrow, None) .add_explanation_to_diagnostic( @@ -564,6 +571,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { desc_place, borrow_spans.describe(), ), + "immutable", ); return err; @@ -640,7 +648,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if issued_spans == borrow_spans { borrow_spans.var_span_label( &mut err, - format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe()), + format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),), + gen_borrow_kind.describe_mutability(), ); } else { let borrow_place = &issued_borrow.borrowed_place; @@ -652,6 +661,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_place_desc, issued_spans.describe(), ), + issued_borrow.kind.describe_mutability(), ); borrow_spans.var_span_label( @@ -661,6 +671,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { desc_place, borrow_spans.describe(), ), + gen_borrow_kind.describe_mutability(), ); } @@ -820,7 +831,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); let borrow_spans = self.retrieve_borrow_spans(borrow); - // cpardy: borrowed value doesn't live long enough, in closure case either span should be fine let borrow_span = borrow_spans.var_or_use(); assert!(root_place.projection.is_empty()); @@ -961,7 +971,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location, name, borrow, drop_span, borrow_spans ); - // cpardy: I think this one should be ok seems to be about local values, not captures let borrow_span = borrow_spans.var_or_use(); if let BorrowExplanation::MustBeValidFor { category, @@ -1077,7 +1086,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); let borrow_spans = self.retrieve_borrow_spans(borrow); - // cpardy: Not really sure about this one let borrow_span = borrow_spans.var_or_use(); let mut err = self.cannot_borrow_across_destructor(borrow_span); @@ -1551,6 +1559,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { loan_spans.var_span_label( &mut err, format!("borrow occurs due to use{}", loan_spans.describe()), + loan.kind.describe_mutability(), ); err.buffer(&mut self.errors_buffer); @@ -1561,8 +1570,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); - loan_spans - .var_span_label(&mut err, format!("borrow occurs due to use{}", loan_spans.describe())); + loan_spans.var_span_label( + &mut err, + format!("borrow occurs due to use{}", loan_spans.describe()), + loan.kind.describe_mutability(), + ); self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic( self.infcx.tcx, diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 55801f2877bbd..1ac7fe846c68d 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -605,7 +605,7 @@ impl UseSpans<'_> { // FIXME Add a path_span variant of this function pub(super) fn var_or_use(self) -> Span { match self { - UseSpans::ClosureUse { capture_kind_span: span, .. } + UseSpans::ClosureUse { path_span: span, .. } | UseSpans::PatUse(span) | UseSpans::OtherUse(span) => span, UseSpans::FnSelfUse { @@ -633,18 +633,32 @@ impl UseSpans<'_> { } } + // Add a span label to the use of the captured variable, if it exists. + // only adds label to the `path_span` + pub(super) fn var_span_label_path_only( + self, + err: &mut DiagnosticBuilder<'_>, + message: impl Into, + ) { + if let UseSpans::ClosureUse { path_span, .. } = self { + err.span_label(path_span, message); + } + } + // Add a span label to the use of the captured variable, if it exists. pub(super) fn var_span_label( self, err: &mut DiagnosticBuilder<'_>, message: impl Into, + kind_desc: impl Into, ) { if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self { if capture_kind_span == path_span { err.span_label(capture_kind_span, message); } else { - let path_label = "which is captured in it's entirety because of its use here"; - let capture_kind_label = message; + let capture_kind_label = + format!("capture is {} because of use here", kind_desc.into()); + let path_label = message; err.span_label(capture_kind_span, capture_kind_label); err.span_label(path_span, path_label); } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs index 7008c935b92e5..6cef2c13eda48 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs @@ -478,8 +478,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), ""); use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc)); - use_spans - .var_span_label(err, format!("move occurs due to use{}", use_spans.describe())); + use_spans.var_span_label( + err, + format!("move occurs due to use{}", use_spans.describe()), + "moved", + ); } } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 0becda152ba61..e42d4fc46221b 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -195,6 +195,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { "mutable borrow occurs due to use of {} in closure", self.describe_any_place(access_place.as_ref()), ), + "mutable", ); borrow_span } diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr index 193026541d073..599d0e1355790 100644 --- a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr +++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr @@ -21,9 +21,9 @@ error[E0373]: async block may outlive the current function, but it borrows `x`, --> $DIR/async-borrowck-escaping-block-error.rs:11:11 | LL | async { *x } - | ^^^-^^ - | | | - | | `x` is borrowed here + | ^^--^^ + | | | + | | `x` is borrowed here | may outlive borrowed value `x` | note: async block is returned here diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs index 74831c646b558..2dc405ffcd4c0 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs +++ b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs @@ -1,7 +1,6 @@ // Tests that two closures cannot simultaneously have mutable // and immutable access to the variable. Issue #6801. -#![feature(capture_disjoint_fields)] #![feature(box_syntax)] fn get(x: &isize) -> isize { diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr index edeb21c16d3c8..fadcd11a592aa 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr @@ -73,7 +73,7 @@ error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/borrowck-closures-mut-and-imm.rs:57:5 | LL | let c1 = || get(&*x); - | -- - borrow occurs due to use in closure + | -- -- borrow occurs due to use in closure | | | borrow of `*x` occurs here LL | *x = 5; @@ -86,7 +86,7 @@ error[E0506]: cannot assign to `*x.f` because it is borrowed --> $DIR/borrowck-closures-mut-and-imm.rs:69:5 | LL | let c1 = || get(&*x.f); - | -- - borrow occurs due to use in closure + | -- ---- borrow occurs due to use in closure | | | borrow of `*x.f` occurs here LL | *x.f = 5; @@ -99,11 +99,11 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/borrowck-closures-mut-and-imm.rs:81:14 | LL | let c1 = || get(&*x.f); - | -- - first borrow occurs due to use of `x` in closure + | -- ---- first borrow occurs due to use of `x` in closure | | | immutable borrow occurs here LL | let c2 = || *x.f = 5; - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ ---- second borrow occurs due to use of `x` in closure | | | mutable borrow occurs here LL | diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr index 784b903a5896a..537ec9895e106 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr @@ -14,12 +14,12 @@ error[E0524]: two closures require unique access to `x` at the same time --> $DIR/borrowck-closures-mut-of-imm.rs:11:18 | LL | let mut c1 = || set(&mut *x); - | -- - first borrow occurs due to use of `x` in closure + | -- -- first borrow occurs due to use of `x` in closure | | | first closure is constructed here LL | LL | let mut c2 = || set(&mut *x); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ -- second borrow occurs due to use of `x` in closure | | | second closure is constructed here ... diff --git a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr index 471173e595f47..e5ee5a401050a 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr +++ b/src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr @@ -2,11 +2,11 @@ error[E0524]: two closures require unique access to `x` at the same time --> $DIR/borrowck-closures-mut-of-mut.rs:14:18 | LL | let mut c1 = || set(&mut *x); - | -- - first borrow occurs due to use of `x` in closure + | -- -- first borrow occurs due to use of `x` in closure | | | first closure is constructed here LL | let mut c2 = || set(&mut *x); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ -- second borrow occurs due to use of `x` in closure | | | second closure is constructed here LL | diff --git a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr index 9e1e47a92412a..411d85b8e0562 100644 --- a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr +++ b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr @@ -45,7 +45,7 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut LL | let f = || { | -- immutable borrow occurs here LL | let [ref y, ref z @ ..] = *x; - | - first borrow occurs due to use of `x` in closure + | -- first borrow occurs due to use of `x` in closure LL | }; LL | let r = &mut *x; | ^^^^^^^ mutable borrow occurs here @@ -59,7 +59,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u LL | let mut f = || { | -- closure construction occurs here LL | let [ref mut y, ref mut z @ ..] = *x; - | - first borrow occurs due to use of `x` in closure + | -- first borrow occurs due to use of `x` in closure LL | }; LL | let r = &x; | ^^ second borrow occurs here @@ -86,7 +86,7 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut LL | let f = || { | -- immutable borrow occurs here LL | if let [ref y, ref z @ ..] = *x {} - | - first borrow occurs due to use of `x` in closure + | -- first borrow occurs due to use of `x` in closure LL | }; LL | let r = &mut *x; | ^^^^^^^ mutable borrow occurs here @@ -100,7 +100,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u LL | let mut f = || { | -- closure construction occurs here LL | if let [ref mut y, ref mut z @ ..] = *x {} - | - first borrow occurs due to use of `x` in closure + | -- first borrow occurs due to use of `x` in closure LL | }; LL | let r = &x; | ^^ second borrow occurs here diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr index 07f477d17868f..d0044ce139c2b 100644 --- a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr +++ b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr @@ -48,7 +48,7 @@ LL | let c1 = to_fn_mut(|| x = 5); | | | first mutable borrow occurs here LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ -------------- second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here LL | @@ -59,11 +59,11 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-closures-two-mut-fail.rs:53:24 | LL | let c1 = to_fn_mut(|| set(&mut *x.f)); - | -- - first borrow occurs due to use of `x` in closure + | -- ---- first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here LL | let c2 = to_fn_mut(|| set(&mut *x.f)); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ ---- second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here LL | diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr index bffb11640744c..5846d72568675 100644 --- a/src/test/ui/borrowck/borrowck-closures-two-mut.stderr +++ b/src/test/ui/borrowck/borrowck-closures-two-mut.stderr @@ -48,7 +48,7 @@ LL | let c1 = to_fn_mut(|| x = 5); | | | first mutable borrow occurs here LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ -------------- second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here LL | @@ -59,11 +59,11 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-closures-two-mut.rs:49:24 | LL | let c1 = to_fn_mut(|| set(&mut *x.f)); - | -- - first borrow occurs due to use of `x` in closure + | -- ---- first borrow occurs due to use of `x` in closure | | | first mutable borrow occurs here LL | let c2 = to_fn_mut(|| set(&mut *x.f)); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ ---- second borrow occurs due to use of `x` in closure | | | second mutable borrow occurs here LL | diff --git a/src/test/ui/borrowck/borrowck-closures-unique.stderr b/src/test/ui/borrowck/borrowck-closures-unique.stderr index 64c2f419ffa65..23d3cc0e76ff7 100644 --- a/src/test/ui/borrowck/borrowck-closures-unique.stderr +++ b/src/test/ui/borrowck/borrowck-closures-unique.stderr @@ -20,7 +20,7 @@ LL | let c1 = || get(x); | | | borrow occurs here LL | let c2 = || { get(x); set(x); }; - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ - second borrow occurs due to use of `x` in closure | | | closure construction occurs here LL | c1; diff --git a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr index f22b7da811949..a6dbcf36077a7 100644 --- a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr +++ b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr @@ -4,7 +4,7 @@ error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as m LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here LL | ptr = box Foo { x: ptr.x + 1 }; - | --- first borrow occurs due to use of `ptr` in closure + | --- first borrow occurs due to use of `ptr` in closure LL | }; LL | test(&*ptr); | ---- ^^^^^ immutable borrow occurs here diff --git a/src/test/ui/borrowck/borrowck-insert-during-each.stderr b/src/test/ui/borrowck/borrowck-insert-during-each.stderr index 796390c093b10..a1ac45795fae2 100644 --- a/src/test/ui/borrowck/borrowck-insert-during-each.stderr +++ b/src/test/ui/borrowck/borrowck-insert-during-each.stderr @@ -9,7 +9,7 @@ LL | | LL | | |a| { | | --- closure construction occurs here LL | | f.n.insert(*a); - | | - first borrow occurs due to use of `f` in closure + | | --- first borrow occurs due to use of `f` in closure LL | | }) | |__________^ second borrow occurs here @@ -24,7 +24,7 @@ LL | LL | |a| { | ^^^ closure construction occurs here LL | f.n.insert(*a); - | - second borrow occurs due to use of `f` in closure + | --- second borrow occurs due to use of `f` in closure error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr index 2acbcd94f8bbf..ac25502ad053c 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr +++ b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr @@ -7,7 +7,7 @@ LL | thread::spawn(move|| { | ^^^^^^ move out of `v` occurs here LL | LL | println!("v={}", *v); - | - move occurs due to use in closure + | -- move occurs due to use in closure LL | }); LL | w.use_ref(); | - borrow later used here @@ -21,7 +21,7 @@ LL | thread::spawn(move|| { | ^^^^^^ move out of `v` occurs here LL | LL | println!("v={}", *v); - | - move occurs due to use in closure + | -- move occurs due to use in closure LL | }); LL | w.use_ref(); | - borrow later used here diff --git a/src/test/ui/borrowck/borrowck-loan-rcvr.stderr b/src/test/ui/borrowck/borrowck-loan-rcvr.stderr index ec3edc80323f5..489ec7d04ed1d 100644 --- a/src/test/ui/borrowck/borrowck-loan-rcvr.stderr +++ b/src/test/ui/borrowck/borrowck-loan-rcvr.stderr @@ -7,7 +7,7 @@ LL | p.blockm(|| { | | immutable borrow later used by call | immutable borrow occurs here LL | p.x = 10; - | - second borrow occurs due to use of `p` in closure + | --- second borrow occurs due to use of `p` in closure error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable --> $DIR/borrowck-loan-rcvr.rs:34:5 diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr index 837bd08253b3b..628f206e0a896 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr +++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr @@ -5,10 +5,10 @@ LL | let bar: Box<_> = box 3; | --- captured outer variable LL | let _g = to_fn_mut(|| { LL | let _h = to_fn_once(move || -> isize { *bar }); - | ^^^^^^^^^^^^^^^^ --- - | | | - | | move occurs because `bar` has type `Box`, which does not implement the `Copy` trait - | | move occurs due to use in closure + | ^^^^^^^^^^^^^^^^ ---- + | | | + | | move occurs because `bar` has type `Box`, which does not implement the `Copy` trait + | | move occurs due to use in closure | move out of `bar` occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr index 44f423c2bd936..1ac4999e6e11d 100644 --- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr +++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr @@ -5,11 +5,11 @@ LL | let t: Box<_> = box 3; | - move occurs because `t` has type `Box`, which does not implement the `Copy` trait LL | LL | call_f(move|| { *t + 1 }); - | ------ - variable moved due to use in closure + | ------ -- variable moved due to use in closure | | | value moved into closure here LL | call_f(move|| { *t + 1 }); - | ^^^^^^ - use occurs due to use in closure + | ^^^^^^ -- use occurs due to use in closure | | | value used here after move diff --git a/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr b/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr index f0a3151f4e12f..dd46308d14004 100644 --- a/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr +++ b/src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr @@ -5,7 +5,7 @@ LL | match x { | - value is immutable in match guard ... LL | (|| { *x = None; drop(force_fn_once); })(); - | ^^ - borrow occurs due to use of `x` in closure + | ^^ -- borrow occurs due to use of `x` in closure | | | cannot mutably borrow diff --git a/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr b/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr index f0264b56ea569..48433432de1bd 100644 --- a/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr +++ b/src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern g --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25 | LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })(); - | ^^ - mutable borrow occurs due to use of `r` in closure + | ^^ -- mutable borrow occurs due to use of `r` in closure | | | cannot borrow as mutable | diff --git a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.stderr b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.stderr index 9b1d6fa7d3575..9d76ae01e8caa 100644 --- a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.stderr +++ b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.stderr @@ -2,7 +2,7 @@ error[E0506]: cannot assign to `greeting` because it is borrowed --> $DIR/issue-58776-borrowck-scans-children.rs:5:5 | LL | let res = (|| (|| &greeting)())(); - | -- -------- borrow occurs due to use in closure + | -- -------------- borrow occurs due to use in closure | | | borrow of `greeting` occurs here LL | @@ -16,7 +16,7 @@ error[E0505]: cannot move out of `greeting` because it is borrowed --> $DIR/issue-58776-borrowck-scans-children.rs:7:10 | LL | let res = (|| (|| &greeting)())(); - | -- -------- borrow occurs due to use in closure + | -- -------------- borrow occurs due to use in closure | | | borrow of `greeting` occurs here ... diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs index b19faa7e74109..2f3358dcd8db7 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs @@ -1,4 +1,5 @@ #![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete #[derive(Debug)] struct Point { @@ -10,6 +11,7 @@ fn main() { let y = &mut p.y; let mut c = || { + //~^ ERROR cannot borrow `p` as mutable more than once at a time let x = &mut p.x; println!("{:?}", p); }; diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr index 2c357b147c65f..e15067b264d63 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr @@ -8,16 +8,17 @@ LL | #![feature(capture_disjoint_fields)] = note: see issue #53488 for more information error[E0499]: cannot borrow `p` as mutable more than once at a time - --> $DIR/borrowck-1.rs:12:17 + --> $DIR/borrowck-1.rs:13:17 | LL | let y = &mut p.y; | -------- first mutable borrow occurs here LL | let mut c = || { | ^^ second mutable borrow occurs here +LL | LL | let x = &mut p.x; - | --- second borrow occurs due to use of `p` in closure + | --- capture is mutable because of use here LL | println!("{:?}", p); - | - which is captured in it's entirety because of its use here + | - second borrow occurs due to use of `p` in closure ... LL | *y+=1; | ----- first borrow later used here diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs index 7559ed17fa155..06c6a87eb105d 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs @@ -1,4 +1,5 @@ #![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete #[derive(Debug)] struct Point { @@ -10,6 +11,7 @@ fn main() { let y = &p.y; let mut c = || { + //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable println!("{:?}", p); let x = &mut p.x; }; diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr index 88fc25bd1e3a7..a195b981eaadd 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr @@ -8,16 +8,17 @@ LL | #![feature(capture_disjoint_fields)] = note: see issue #53488 for more information error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-2.rs:12:17 + --> $DIR/borrowck-2.rs:13:17 | LL | let y = &p.y; | ---- immutable borrow occurs here LL | let mut c = || { | ^^ mutable borrow occurs here +LL | LL | println!("{:?}", p); - | - which is captured in it's entirety because of its use here + | - second borrow occurs due to use of `p` in closure LL | let x = &mut p.x; - | --- second borrow occurs due to use of `p` in closure + | --- capture is mutable because of use here ... LL | println!("{}", y); | - immutable borrow later used here diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs index a4690f2b90f67..ba998f78c87ac 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs @@ -1,4 +1,5 @@ #![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete #[derive(Debug)] struct Point { @@ -11,6 +12,7 @@ fn main() { || { let x = &mut p.x; println!("{:?}", p); + //~^ ERROR `p` does not live long enough } }; c(); diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr index 888632c6f674d..b54c729a307c0 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr @@ -8,7 +8,7 @@ LL | #![feature(capture_disjoint_fields)] = note: see issue #53488 for more information error[E0597]: `p` does not live long enough - --> $DIR/borrowck-3.rs:12:25 + --> $DIR/borrowck-3.rs:14:29 | LL | let mut c = { | ----- borrow later stored here @@ -16,7 +16,8 @@ LL | let mut p = Point {x: "1".to_string(), y: "2".to_string() }; LL | || { | -- value captured here LL | let x = &mut p.x; - | ^^^ borrowed value does not live long enough +LL | println!("{:?}", p); + | ^ borrowed value does not live long enough ... LL | }; | - `p` dropped here while still borrowed diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs index 37ad1bbd7f8cb..4fab0189c27f8 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs @@ -1,4 +1,5 @@ #![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete #[derive(Debug)] struct Point { @@ -8,6 +9,7 @@ struct Point { fn foo () -> impl FnMut()->() { let mut p = Point {x: 1, y: 2 }; let mut c = || { + //~^ ERROR closure may outlive the current function, but it borrows `p` p.x+=5; println!("{:?}", p); }; diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr index 403cdc034efea..905fa3475edd8 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr @@ -8,15 +8,16 @@ LL | #![feature(capture_disjoint_fields)] = note: see issue #53488 for more information error[E0373]: closure may outlive the current function, but it borrows `p`, which is owned by the current function - --> $DIR/borrowck-4.rs:10:17 + --> $DIR/borrowck-4.rs:11:17 | LL | let mut c = || { | ^^ may outlive borrowed value `p` -LL | p.x+=5; - | --- `p` is borrowed here +... +LL | println!("{:?}", p); + | - `p` is borrowed here | note: closure is returned here - --> $DIR/borrowck-4.rs:8:14 + --> $DIR/borrowck-4.rs:9:14 | LL | fn foo () -> impl FnMut()->() { | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs index 298613e1e673d..b23947ad5d1bf 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs @@ -2,6 +2,7 @@ // and immutable access to the variable. Issue #6801. #![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete #![feature(box_syntax)] #[derive(Debug)] @@ -10,88 +11,16 @@ struct Point { y: i32, } -fn get(x: &isize) -> isize { - *x -} - -fn set(x: &mut isize) { - *x = 4; -} - fn a() { let mut p = Point {x: 3, y:4}; let c2 = || p.y * 5; let c1 = || { + //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable dbg!(&p); p.x = 4; }; - //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable drop(c2); } -// fn b() { -// let mut x = 3; -// let c1 = || set(&mut x); -// let c2 = || get(&x); -// //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable -// drop(c1); -// } - -// fn c() { -// let mut x = 3; -// let c1 = || set(&mut x); -// let c2 = || x * 5; -// //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable -// drop(c1); -// } - -// fn d() { -// let mut x = 3; -// let c2 = || x * 5; -// x = 5; -// //~^ ERROR cannot assign to `x` because it is borrowed -// drop(c2); -// } - -// fn e() { -// let mut x = 3; -// let c1 = || get(&x); -// x = 5; -// //~^ ERROR cannot assign to `x` because it is borrowed -// drop(c1); -// } - -// fn f() { -// let mut x: Box<_> = box 3; -// let c1 = || get(&*x); -// *x = 5; -// //~^ ERROR cannot assign to `*x` because it is borrowed -// drop(c1); -// } - -// fn g() { -// struct Foo { -// f: Box -// } - -// let mut x: Box<_> = box Foo { f: box 3 }; -// let c1 = || get(&*x.f); -// *x.f = 5; -// //~^ ERROR cannot assign to `*x.f` because it is borrowed -// drop(c1); -// } - -// fn h() { -// struct Foo { -// f: Box -// } - -// let mut x: Box<_> = box Foo { f: box 3 }; -// let c1 = || get(&*x.f); -// let c2 = || *x.f = 5; -// //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable -// drop(c1); -// } - fn main() { } diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr index d44f20ed4dda1..58975c6f46fe4 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr @@ -8,7 +8,7 @@ LL | #![feature(capture_disjoint_fields)] = note: see issue #53488 for more information error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-closures-mut-and-imm.rs:24:14 + --> $DIR/borrowck-closures-mut-and-imm.rs:17:14 | LL | let c2 = || p.y * 5; | -- --- first borrow occurs due to use of `p.y` in closure @@ -16,11 +16,12 @@ LL | let c2 = || p.y * 5; | immutable borrow occurs here LL | let c1 = || { | ^^ mutable borrow occurs here +LL | LL | dbg!(&p); - | - which is captured in it's entirety because of its use here + | - second borrow occurs due to use of `p` in closure LL | p.x = 4; - | --- second borrow occurs due to use of `p` in closure -... + | --- capture is mutable because of use here +LL | }; LL | drop(c2); | -- immutable borrow later used here diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr index 17a9332fb3e6c..174faa33c49ab 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr @@ -13,7 +13,7 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed LL | let mut c = || { | -- borrow of `e.0.0.m.x` occurs here LL | e.0.0.m.x = format!("not-x"); - | - borrow occurs due to use in closure + | --------- borrow occurs due to use in closure ... LL | e.0.0.m.x = format!("not-x"); | ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here @@ -27,7 +27,7 @@ error[E0502]: cannot borrow `e.0.0.m.x` as immutable because it is also borrowed LL | let mut c = || { | -- mutable borrow occurs here LL | e.0.0.m.x = format!("not-x"); - | - first borrow occurs due to use of `e.0.0.m.x` in closure + | --------- first borrow occurs due to use of `e.0.0.m.x` in closure ... LL | println!("{}", e.0.0.m.x); | ^^^^^^^^^ immutable borrow occurs here @@ -41,7 +41,7 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed LL | let c = || { | -- borrow of `e.0.0.m.x` occurs here LL | println!("{}", e.0.0.m.x); - | - borrow occurs due to use in closure + | --------- borrow occurs due to use in closure ... LL | e.0.0.m.x = format!("not-x"); | ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr index 861bc44b78ded..39a11fb332725 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr @@ -14,7 +14,7 @@ LL | let mut c = || { | ^^ cannot borrow as mutable LL | LL | z.0.0.0 = format!("X1"); - | - mutable borrow occurs due to use of `z.0.0.0` in closure + | ------- mutable borrow occurs due to use of `z.0.0.0` in closure error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs index 997ecc7ddddf1..928c866726f71 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs @@ -11,7 +11,7 @@ fn mut_error_struct() { let mut c = || { z.0.0.0 = 20; - //~^ ERROR: cannot assign to `z`, as it is not declared as mutable + //~^ ERROR: cannot assign to `z.0.0.0`, as it is not declared as mutable }; c(); @@ -23,7 +23,7 @@ fn mut_error_box() { let mut c = || { bx.0 = 20; - //~^ ERROR: cannot assign to `bx`, as it is not declared as mutable + //~^ ERROR: cannot assign to `*bx.0`, as it is not declared as mutable }; c(); diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr index 5e15635ac6e1b..9fb8dd4a1c36e 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr @@ -7,7 +7,7 @@ LL | #![feature(capture_disjoint_fields)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #53488 for more information -error[E0594]: cannot assign to `z`, as it is not declared as mutable +error[E0594]: cannot assign to `z.0.0.0`, as it is not declared as mutable --> $DIR/cant-mutate-imm.rs:13:9 | LL | let z = (y, 10); @@ -16,7 +16,7 @@ LL | let z = (y, 10); LL | z.0.0.0 = 20; | ^^^^^^^^^^^^ cannot assign -error[E0594]: cannot assign to `bx`, as it is not declared as mutable +error[E0594]: cannot assign to `*bx.0`, as it is not declared as mutable --> $DIR/cant-mutate-imm.rs:25:9 | LL | let bx = Box::new(x); diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr index e5a396c4e98ae..a3d1f550557af 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr @@ -13,7 +13,7 @@ error[E0499]: cannot borrow `w.p.x` as mutable more than once at a time LL | let mut c = || { | -- first mutable borrow occurs here LL | w.p.x += 20; - | - first borrow occurs due to use of `w.p.x` in closure + | ----- first borrow occurs due to use of `w.p.x` in closure ... LL | let py = &mut w.p.x; | ^^^^^^^^^^ second mutable borrow occurs here diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr index 8cb2ed2235d55..831e486db82af 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr @@ -17,7 +17,7 @@ LL | let c = || { | ^^ `ref_mref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable LL | LL | **ref_mref_x = y; - | ---------- mutable borrow occurs due to use of `**ref_mref_x` in closure + | ------------ mutable borrow occurs due to use of `**ref_mref_x` in closure error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference --> $DIR/mut_ref.rs:27:13 @@ -26,7 +26,7 @@ LL | let c = || { | ^^ cannot borrow as mutable LL | LL | **mref_ref_x = y; - | ---------- mutable borrow occurs due to use of `**mref_ref_x` in closure + | ------------ mutable borrow occurs due to use of `**mref_ref_x` in closure error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr index 45a61cd98b101..f1748fda151c5 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr @@ -13,7 +13,9 @@ error[E0502]: cannot borrow `p` as immutable because it is also borrowed as muta LL | let mut c = || { | -- mutable borrow occurs here LL | p.x += 10; - | - first borrow occurs due to use of `p` in closure + | --- capture is mutable because of use here +LL | println!("{:?}", p); + | - first borrow occurs due to use of `p` in closure ... LL | println!("{:?}", p); | ^ immutable borrow occurs here diff --git a/src/test/ui/error-codes/E0504.stderr b/src/test/ui/error-codes/E0504.stderr index 1f2a0407a3963..04811721aa521 100644 --- a/src/test/ui/error-codes/E0504.stderr +++ b/src/test/ui/error-codes/E0504.stderr @@ -7,7 +7,7 @@ LL | LL | let x = move || { | ^^^^^^^ move out of `fancy_num` occurs here LL | println!("child function: {}", fancy_num.num); - | --------- move occurs due to use in closure + | ------------- move occurs due to use in closure ... LL | println!("main function: {}", fancy_ref.num); | ------------- borrow later used here diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.stderr index fd885660d0927..68d785efcfe5d 100644 --- a/src/test/ui/generator/yield-while-ref-reborrowed.stderr +++ b/src/test/ui/generator/yield-while-ref-reborrowed.stderr @@ -4,7 +4,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u LL | let mut b = || { | -- generator construction occurs here LL | let a = &mut *x; - | - first borrow occurs due to use of `x` in generator + | -- first borrow occurs due to use of `x` in generator ... LL | println!("{}", x); | ^ second borrow occurs here diff --git a/src/test/ui/issues/issue-11192.stderr b/src/test/ui/issues/issue-11192.stderr index dfe7b3f6b5f9c..2a9d913171c3e 100644 --- a/src/test/ui/issues/issue-11192.stderr +++ b/src/test/ui/issues/issue-11192.stderr @@ -5,7 +5,7 @@ LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here LL | println!("access {}", foo.x); LL | ptr = box Foo { x: ptr.x + 1 }; - | --- first borrow occurs due to use of `ptr` in closure + | --- first borrow occurs due to use of `ptr` in closure ... LL | test(&*ptr); | ---- ^^^^^ immutable borrow occurs here diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr index 188f0b25c3084..a1f973e0fdf5a 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr @@ -5,7 +5,7 @@ LL | match x { | - value is immutable in match guard ... LL | (|| { *x = None; drop(force_fn_once); })(); - | ^^ - borrow occurs due to use of `x` in closure + | ^^ -- borrow occurs due to use of `x` in closure | | | cannot mutably borrow diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr index f46a42d750817..4a4a25790b985 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr @@ -5,7 +5,7 @@ LL | match **x { | --- value is immutable in match guard ... LL | (|| { *x = &None; drop(force_fn_once); })(); - | ^^ - borrow occurs due to use of `x` in closure + | ^^ -- borrow occurs due to use of `x` in closure | | | cannot mutably borrow diff --git a/src/test/ui/issues/issue-61623.stderr b/src/test/ui/issues/issue-61623.stderr index 883a1c441d6bb..901c75981768e 100644 --- a/src/test/ui/issues/issue-61623.stderr +++ b/src/test/ui/issues/issue-61623.stderr @@ -10,7 +10,7 @@ error[E0502]: cannot borrow `*x.1` as mutable because it is also borrowed as imm --> $DIR/issue-61623.rs:6:19 | LL | f2(|| x.0, f1(x.1)) - | -- -- - ^^^ mutable borrow occurs here + | -- -- --- ^^^ mutable borrow occurs here | | | | | | | first borrow occurs due to use of `x` in closure | | immutable borrow occurs here diff --git a/src/test/ui/issues/issue-6801.stderr b/src/test/ui/issues/issue-6801.stderr index dbb8e6530c053..48c6acd1f49e4 100644 --- a/src/test/ui/issues/issue-6801.stderr +++ b/src/test/ui/issues/issue-6801.stderr @@ -2,7 +2,7 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/issue-6801.rs:19:13 | LL | let sq = || { *x * *x }; - | -- - borrow occurs due to use in closure + | -- -- borrow occurs due to use in closure | | | borrow of `x` occurs here LL | diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr index ccc043a189059..8eded8f28572e 100644 --- a/src/test/ui/nll/closure-access-spans.stderr +++ b/src/test/ui/nll/closure-access-spans.stderr @@ -28,7 +28,7 @@ error[E0500]: closure requires unique access to `x` but it is already borrowed LL | let r = &mut x; | ------ borrow occurs here LL | || *x = 2; - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ -- second borrow occurs due to use of `x` in closure | | | closure construction occurs here LL | r.use_mut(); @@ -88,7 +88,7 @@ LL | fn closure_unique_capture_moved(x: &mut String) { LL | let r = x; | - value moved here LL | || *x = String::new(); - | ^^ - borrow occurs due to use in closure + | ^^ -- borrow occurs due to use in closure | | | value borrowed here after move diff --git a/src/test/ui/nll/closure-borrow-spans.stderr b/src/test/ui/nll/closure-borrow-spans.stderr index a3bcbbab3ec69..fffbee4d4a8e1 100644 --- a/src/test/ui/nll/closure-borrow-spans.stderr +++ b/src/test/ui/nll/closure-borrow-spans.stderr @@ -110,7 +110,7 @@ error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/closure-borrow-spans.rs:65:13 | LL | let f = || *x = 0; - | -- - borrow occurs due to use in closure + | -- -- borrow occurs due to use in closure | | | borrow of `x` occurs here LL | let y = x; @@ -122,7 +122,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u --> $DIR/closure-borrow-spans.rs:71:13 | LL | let f = || *x = 0; - | -- - first borrow occurs due to use of `x` in closure + | -- -- first borrow occurs due to use of `x` in closure | | | closure construction occurs here LL | let y = &x; @@ -134,7 +134,7 @@ error[E0501]: cannot borrow `x` as mutable because previous closure requires uni --> $DIR/closure-borrow-spans.rs:77:13 | LL | let f = || *x = 0; - | -- - first borrow occurs due to use of `x` in closure + | -- -- first borrow occurs due to use of `x` in closure | | | closure construction occurs here LL | let y = &mut x; @@ -143,10 +143,10 @@ LL | f.use_ref(); | - first borrow later used here error[E0597]: `x` does not live long enough - --> $DIR/closure-borrow-spans.rs:86:17 + --> $DIR/closure-borrow-spans.rs:86:16 | LL | f = || *x = 0; - | -- ^ borrowed value does not live long enough + | -- ^^ borrowed value does not live long enough | | | value captured here LL | } @@ -158,7 +158,7 @@ error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/closure-borrow-spans.rs:93:5 | LL | let f = || *x = 0; - | -- - borrow occurs due to use in closure + | -- -- borrow occurs due to use in closure | | | borrow of `*x` occurs here LL | *x = 1; diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr index dd5f32ef4f581..a59e553315ae6 100644 --- a/src/test/ui/nll/closure-captures.stderr +++ b/src/test/ui/nll/closure-captures.stderr @@ -133,9 +133,9 @@ LL | fn_ref(|| { LL | | || | | ^^ cannot borrow as mutable LL | | *x = 1;}); - | |__________-_____- in this closure - | | - | mutable borrow occurs due to use of `x` in closure + | |_________--_____- in this closure + | | + | mutable borrow occurs due to use of `x` in closure error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/closure-captures.rs:51:9 @@ -150,9 +150,9 @@ LL | fn_ref(move || { LL | | || | | ^^ cannot borrow as mutable LL | | *x = 1;}); - | |__________-_____- in this closure - | | - | mutable borrow occurs due to use of `x` in closure + | |_________--_____- in this closure + | | + | mutable borrow occurs due to use of `x` in closure error: aborting due to 12 previous errors diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index e1b446fc61f61..a37c630e1bfb2 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -45,12 +45,12 @@ LL | | } = note: defining type: test error[E0597]: `y` does not live long enough - --> $DIR/escape-upvar-nested.rs:21:40 + --> $DIR/escape-upvar-nested.rs:21:32 | LL | let mut closure = || { | -- value captured here LL | let mut closure1 = || p = &y; - | ^ borrowed value does not live long enough + | ^^^^^^^^^ borrowed value does not live long enough ... LL | } | - `y` dropped here while still borrowed diff --git a/src/test/ui/nll/closure-use-spans.stderr b/src/test/ui/nll/closure-use-spans.stderr index ec7e0f308557d..87162904ba6cd 100644 --- a/src/test/ui/nll/closure-use-spans.stderr +++ b/src/test/ui/nll/closure-use-spans.stderr @@ -6,7 +6,7 @@ LL | let y = &x; LL | x = 0; | ^^^^^ assignment to borrowed `x` occurs here LL | || *y; - | - borrow later captured here by closure + | -- borrow later captured here by closure error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-use-spans.rs:11:5 @@ -16,7 +16,7 @@ LL | let y = &mut x; LL | x = 0; | ^^^^^ assignment to borrowed `x` occurs here LL | || *y = 1; - | - borrow later captured here by closure + | -- borrow later captured here by closure error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-use-spans.rs:17:5 diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr index 2f134f83ced19..2be0460df1fc6 100644 --- a/src/test/ui/nll/closures-in-loops.stderr +++ b/src/test/ui/nll/closures-in-loops.stderr @@ -21,7 +21,7 @@ error[E0524]: two closures require unique access to `x` at the same time --> $DIR/closures-in-loops.rs:20:16 | LL | v.push(|| *x = String::new()); - | ^^ - borrows occur due to use of `x` in closure + | ^^ -- borrows occur due to use of `x` in closure | | | closures are constructed here in different iterations of loop diff --git a/src/test/ui/nll/issue-51268.stderr b/src/test/ui/nll/issue-51268.stderr index 420c94f8e1bd2..a40643f16d99c 100644 --- a/src/test/ui/nll/issue-51268.stderr +++ b/src/test/ui/nll/issue-51268.stderr @@ -8,7 +8,7 @@ LL | self.thing.bar(|| { | | LL | | LL | | &self.number; - | | ---- first borrow occurs due to use of `self` in closure + | | ----------- first borrow occurs due to use of `self` in closure LL | | }); | |__________^ mutable borrow occurs here