From 3698e03fb60893786843df01b50dc8326f6c5c5a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 9 Oct 2021 22:11:13 +0100 Subject: [PATCH 1/4] Remove span from UpvarCapture::ByValue This span is unused and is superseded by capture_kind_expr_id in CaptureInfo --- .../src/diagnostics/mutability_errors.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_middle/src/ty/closure.rs | 8 +--- .../src/build/expr/as_place.rs | 2 +- compiler/rustc_mir_build/src/build/mod.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 4 +- compiler/rustc_typeck/src/check/regionck.rs | 2 +- compiler/rustc_typeck/src/check/upvar.rs | 45 +++++++------------ compiler/rustc_typeck/src/expr_use_visitor.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- 11 files changed, 28 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index b5dad5ccdea8e..73a5a9cf0c357 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -712,7 +712,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }) => { capture_reason = format!("mutable borrow of `{}`", upvar); } - ty::UpvarCapture::ByValue(_) => { + ty::UpvarCapture::ByValue => { capture_reason = format!("possible mutation of `{}`", upvar); } _ => bug!("upvar `{}` borrowed, but not mutably", upvar), diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index fe34d6e7ca9dd..7e961e1e750be 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -186,7 +186,7 @@ fn do_mir_borrowck<'a, 'tcx>( .map(|captured_place| { let capture = captured_place.info.capture_kind; let by_ref = match capture { - ty::UpvarCapture::ByValue(_) => false, + ty::UpvarCapture::ByValue => false, ty::UpvarCapture::ByRef(..) => true, }; Upvar { place: captured_place.clone(), by_ref } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 771acc2964913..d3acf130f4fb3 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -56,13 +56,7 @@ pub enum UpvarCapture<'tcx> { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases /// depending on inference. - /// - /// If the upvar was inferred to be captured by value (e.g. `move` - /// was not used), then the `Span` points to a usage that - /// required it. There may be more than one such usage - /// (e.g. `|| { a; a; }`), in which case we pick an - /// arbitrary one. - ByValue(Option), + ByValue, /// Upvar is captured by reference. ByRef(UpvarBorrow<'tcx>), diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index c6a34ece24576..7e1fc21f3ffc3 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -266,7 +266,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( // we need to deref it upvar_resolved_place_builder = match capture.info.capture_kind { ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(), - ty::UpvarCapture::ByValue(_) => upvar_resolved_place_builder, + ty::UpvarCapture::ByValue => upvar_resolved_place_builder, }; let next_projection = capture.place.projections.len(); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index cb94e75997237..a4f3a63e40b60 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -930,7 +930,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut projs = closure_env_projs.clone(); projs.push(ProjectionElem::Field(Field::new(i), ty)); match capture { - ty::UpvarCapture::ByValue(_) => {} + ty::UpvarCapture::ByValue => {} ty::UpvarCapture::ByRef(..) => { projs.push(ProjectionElem::Deref); } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index bdde6b4a356c1..1c03c7b060518 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1108,7 +1108,7 @@ impl<'tcx> Cx<'tcx> { let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); match upvar_capture { - ty::UpvarCapture::ByValue(_) => captured_place_expr, + ty::UpvarCapture::ByValue => captured_place_expr, ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow.kind { ty::BorrowKind::ImmBorrow => BorrowKind::Shared, diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 9ee305b712f61..2e3bf7ea548ac 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -726,7 +726,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ); self.acc(self.exit_ln, var, ACC_READ | ACC_USE); } - ty::UpvarCapture::ByValue(_) => {} + ty::UpvarCapture::ByValue => {} } } } @@ -1481,7 +1481,7 @@ impl<'tcx> Liveness<'_, 'tcx> { 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::ByValue => {} ty::UpvarCapture::ByRef(..) => continue, }; let span = captured_place.get_capture_kind_span(self.ir.tcx); diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 1b42edc83be20..89a7a0cf99981 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -867,7 +867,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { all_captures_are_imm_borrow = false; } } - ty::UpvarCapture::ByValue(_) => { + ty::UpvarCapture::ByValue => { all_captures_are_imm_borrow = false; } } diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index ffd7d29bbbbee..0325f50563fb1 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -409,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let updated = match capture_info.capture_kind { - ty::UpvarCapture::ByValue(..) => match closure_kind { + ty::UpvarCapture::ByValue => match closure_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { (ty::ClosureKind::FnOnce, Some((usage_span, place.clone()))) } @@ -1086,7 +1086,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for captured_place in root_var_min_capture_list.iter() { match captured_place.info.capture_kind { // Only care about captures that are moved into the closure - ty::UpvarCapture::ByValue(..) => { + ty::UpvarCapture::ByValue => { projections_list.push(captured_place.place.projections.as_slice()); diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise { source_expr: captured_place.info.path_expr_id, @@ -1481,7 +1481,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into // the closure. hir::CaptureBy::Value if !place.deref_tys().any(ty::TyS::is_ref) => { - ty::UpvarCapture::ByValue(None) + ty::UpvarCapture::ByValue } hir::CaptureBy::Value | hir::CaptureBy::Ref => { let origin = UpvarRegion(upvar_id, closure_span); @@ -1678,7 +1678,7 @@ fn apply_capture_kind_on_capture_ty<'tcx>( capture_kind: UpvarCapture<'tcx>, ) -> Ty<'tcx> { match capture_kind { - ty::UpvarCapture::ByValue(_) => ty, + ty::UpvarCapture::ByValue => ty, ty::UpvarCapture::ByRef(borrow) => tcx .mk_ref(borrow.region, ty::TypeAndMut { ty: ty, mutbl: borrow.kind.to_mutbl_lossy() }), } @@ -1756,12 +1756,10 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { debug!(?upvar_id); - let usage_span = tcx.hir().span(diag_expr_id); - let capture_info = ty::CaptureInfo { capture_kind_expr_id: Some(diag_expr_id), path_expr_id: Some(diag_expr_id), - capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)), + capture_kind: ty::UpvarCapture::ByValue, }; let curr_info = self.capture_information[&place_with_id.place]; @@ -1841,7 +1839,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { debug!(?curr_capture_info); - if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind { + if let ty::UpvarCapture::ByValue = curr_capture_info.capture_kind { // It's already captured by value, we don't need to do anything here return; } else if let ty::UpvarCapture::ByRef(curr_upvar_borrow) = curr_capture_info.capture_kind { @@ -1961,7 +1959,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { }, // Just truncating the place will never cause capture kind to be updated to ByValue - ty::UpvarCapture::ByValue(..) => unreachable!(), + ty::UpvarCapture::ByValue => unreachable!(), } } @@ -1980,7 +1978,7 @@ fn restrict_precision_for_drop_types<'a, 'tcx>( ) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span); - if let (false, UpvarCapture::ByValue(..)) = (is_copy_type, curr_mode) { + if let (false, UpvarCapture::ByValue) = (is_copy_type, curr_mode) { for i in 0..place.projections.len() { match place.ty_before_projection(i).kind() { ty::Adt(def, _) if def.destructor(fcx.tcx).is_some() => { @@ -2070,9 +2068,7 @@ fn adjust_for_move_closure<'tcx>( truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx); } - // AMAN: I think we don't need the span inside the ByValue anymore - // we have more detailed span in CaptureInfo - (place, ty::UpvarCapture::ByValue(None)) + (place, ty::UpvarCapture::ByValue) } /// Adjust closure capture just that if taking ownership of data, only move data @@ -2085,7 +2081,7 @@ fn adjust_for_non_move_closure<'tcx>( place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); match kind { - ty::UpvarCapture::ByValue(..) => { + ty::UpvarCapture::ByValue => { if let Some(idx) = contains_deref { truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx); } @@ -2128,7 +2124,7 @@ fn construct_capture_kind_reason_string<'tcx>( let place_str = construct_place_string(tcx, place); let capture_kind_str = match capture_info.capture_kind { - ty::UpvarCapture::ByValue(_) => "ByValue".into(), + ty::UpvarCapture::ByValue => "ByValue".into(), ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind), }; @@ -2149,7 +2145,7 @@ fn construct_capture_info_string<'tcx>( let place_str = construct_place_string(tcx, place); let capture_kind_str = match capture_info.capture_kind { - ty::UpvarCapture::ByValue(_) => "ByValue".into(), + ty::UpvarCapture::ByValue => "ByValue".into(), ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind), }; format!("{} -> {}", place_str, capture_kind_str) @@ -2240,18 +2236,11 @@ fn determine_capture_info<'tcx>( // If the capture kind is equivalent then, we don't need to escalate and can compare the // expressions. let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) { - (ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => { - // We don't need to worry about the spans being ignored here. - // - // The expr_id in capture_info corresponds to the span that is stored within - // ByValue(span) and therefore it gets handled with priortizing based on - // expressions below. - true - } + (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true, (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { ref_a.kind == ref_b.kind } - (ty::UpvarCapture::ByValue(_), _) | (ty::UpvarCapture::ByRef(_), _) => false, + (ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false, }; if eq_capture_kind { @@ -2263,8 +2252,8 @@ fn determine_capture_info<'tcx>( // We select the CaptureKind which ranks higher based the following priority order: // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow match (capture_info_a.capture_kind, capture_info_b.capture_kind) { - (ty::UpvarCapture::ByValue(_), _) => capture_info_a, - (_, ty::UpvarCapture::ByValue(_)) => capture_info_b, + (ty::UpvarCapture::ByValue, _) => capture_info_a, + (_, ty::UpvarCapture::ByValue) => capture_info_b, (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { match (ref_a.kind, ref_b.kind) { // Take LHS: @@ -2319,7 +2308,7 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>( } ty::UpvarCapture::ByRef(..) => {} - ty::UpvarCapture::ByValue(..) => {} + ty::UpvarCapture::ByValue => {} } place.projections.truncate(len); diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 1ae0ff3036471..5b6e73ef5ee1e 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -796,7 +796,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ); match capture_info.capture_kind { - ty::UpvarCapture::ByValue(_) => { + ty::UpvarCapture::ByValue => { self.delegate_consume(&place_with_id, place_with_id.hir_id); } ty::UpvarCapture::ByRef(upvar_borrow) => { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 9179e67c4f4ee..5ce68bc4d1d5c 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -969,7 +969,7 @@ pub fn can_move_expr_to_closure(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> }; if !self.locals.contains(&local_id) { let capture = match capture.info.capture_kind { - UpvarCapture::ByValue(_) => CaptureKind::Value, + UpvarCapture::ByValue => CaptureKind::Value, UpvarCapture::ByRef(borrow) => match borrow.kind { BorrowKind::ImmBorrow => CaptureKind::Ref(Mutability::Not), BorrowKind::UniqueImmBorrow | BorrowKind::MutBorrow => { From 48258ffe5af8a8fc2926e9e0bb8dc857ad8bfed6 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 13 Oct 2021 21:20:10 +0100 Subject: [PATCH 2/4] Remove region from UpvarCapture and move it to CapturedPlace Region info is completely unnecessary for upvar capture kind computation and is only needed to create the final upvar tuple ty. Doing so makes creation of UpvarCapture very cheap and expose further cleanup opportunity. --- .../src/diagnostics/mutability_errors.rs | 7 +- compiler/rustc_middle/src/ty/closure.rs | 26 +-- compiler/rustc_middle/src/ty/mod.rs | 4 +- .../rustc_middle/src/ty/structural_impls.rs | 6 - compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- compiler/rustc_typeck/src/check/regionck.rs | 4 +- compiler/rustc_typeck/src/check/upvar.rs | 166 +++++++++--------- compiler/rustc_typeck/src/expr_use_visitor.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- 9 files changed, 103 insertions(+), 116 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 73a5a9cf0c357..02935af8314f0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -706,10 +706,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &origin_projection, ) { match captured_place.info.capture_kind { - ty::UpvarCapture::ByRef(ty::UpvarBorrow { - kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, - .. - }) => { + ty::UpvarCapture::ByRef( + ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, + ) => { capture_reason = format!("mutable borrow of `{}`", upvar); } ty::UpvarCapture::ByValue => { diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index d3acf130f4fb3..9c2f0ca061a7f 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -52,29 +52,18 @@ impl UpvarId { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] -pub enum UpvarCapture<'tcx> { +pub enum UpvarCapture { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases /// depending on inference. ByValue, /// Upvar is captured by reference. - ByRef(UpvarBorrow<'tcx>), -} - -#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] -pub struct UpvarBorrow<'tcx> { - /// The kind of borrow: by-ref upvars have access to shared - /// immutable borrows, which are not part of the normal language - /// syntax. - pub kind: BorrowKind, - - /// Region of the resulting reference. - pub region: ty::Region<'tcx>, + ByRef(BorrowKind), } pub type UpvarListMap = FxHashMap>; -pub type UpvarCaptureMap<'tcx> = FxHashMap>; +pub type UpvarCaptureMap = FxHashMap; /// Given the closure DefId this map provides a map of root variables to minimum /// set of `CapturedPlace`s that need to be tracked to support all captures of that closure. @@ -144,10 +133,13 @@ pub struct CapturedPlace<'tcx> { pub place: HirPlace<'tcx>, /// `CaptureKind` and expression(s) that resulted in such capture of `place`. - pub info: CaptureInfo<'tcx>, + pub info: CaptureInfo, /// Represents if `place` can be mutated or not. pub mutability: hir::Mutability, + + /// Region of the resulting reference if the upvar is captured by ref. + pub region: Option>, } impl<'tcx> CapturedPlace<'tcx> { @@ -281,7 +273,7 @@ pub fn is_ancestor_or_same_capture( /// for a particular capture as well as identifying the part of the source code /// that triggered this capture to occur. #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)] -pub struct CaptureInfo<'tcx> { +pub struct CaptureInfo { /// Expr Id pointing to use that resulted in selecting the current capture kind /// /// Eg: @@ -319,7 +311,7 @@ pub struct CaptureInfo<'tcx> { pub path_expr_id: Option, /// Capture mode that was selected - pub capture_kind: UpvarCapture<'tcx>, + pub capture_kind: UpvarCapture, } pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 78ccfbd5e8cdc..d61554b29ac4b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -56,8 +56,8 @@ pub use self::binding::BindingMode::*; pub use self::closure::{ is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo, CapturedPlace, ClosureKind, MinCaptureInformationMap, MinCaptureList, - RootVariableMinCaptureList, UpvarBorrow, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, - UpvarPath, CAPTURE_STRUCT_LOCAL, + RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath, + CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Unevaluated, ValTree}; pub use self::context::{ diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 98b1a8b4d7631..bb8c2b180e40e 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -47,12 +47,6 @@ impl fmt::Debug for ty::UpvarId { } } -impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "UpvarBorrow({:?}, {:?})", self.kind, self.region) - } -} - impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { with_no_trimmed_paths(|| fmt::Display::fmt(self, f)) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 1c03c7b060518..c62de1543883e 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1110,7 +1110,7 @@ impl<'tcx> Cx<'tcx> { match upvar_capture { ty::UpvarCapture::ByValue => captured_place_expr, ty::UpvarCapture::ByRef(upvar_borrow) => { - let borrow_kind = match upvar_borrow.kind { + let borrow_kind = match upvar_borrow { ty::BorrowKind::ImmBorrow => BorrowKind::Shared, ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique, ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false }, diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 89a7a0cf99981..0c2f40733505d 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -859,9 +859,9 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.sub_regions( infer::ReborrowUpvar(span, upvar_id), borrow_region, - upvar_borrow.region, + captured_place.region.unwrap(), ); - if let ty::ImmBorrow = upvar_borrow.kind { + if let ty::ImmBorrow = upvar_borrow { debug!("link_upvar_region: capture by shared ref"); } else { all_captures_are_imm_borrow = false; diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 0325f50563fb1..591c2fc5a8145 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -72,7 +72,7 @@ enum PlaceAncestryRelation { /// Intermediate format to store a captured `Place` and associated `ty::CaptureInfo` /// during capture analysis. Information in this map feeds into the minimum capture /// analysis pass. -type InferredCaptureInformation<'tcx> = FxIndexMap, ty::CaptureInfo<'tcx>>; +type InferredCaptureInformation<'tcx> = FxIndexMap, ty::CaptureInfo>; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) { @@ -208,7 +208,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut delegate = InferBorrowKind { fcx: self, closure_def_id, - closure_span: span, capture_information: Default::default(), fake_reads: Default::default(), }; @@ -231,7 +230,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (capture_information, closure_kind, origin) = self .process_collected_capture_information(capture_clause, delegate.capture_information); - self.compute_min_captures(closure_def_id, capture_information); + self.compute_min_captures(closure_def_id, capture_information, span); let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); @@ -252,9 +251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("seed place {:?}", place); - let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id); - let capture_kind = - self.init_capture_kind_for_place(&place, capture_clause, upvar_id, span); + let capture_kind = self.init_capture_kind_for_place(&place, capture_clause); let fake_info = ty::CaptureInfo { capture_kind_expr_id: None, path_expr_id: None, @@ -266,7 +263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // This will update the min captures based on this new fake information. - self.compute_min_captures(closure_def_id, capture_information); + self.compute_min_captures(closure_def_id, capture_information, span); } let before_feature_tys = self.final_upvar_tys(closure_def_id); @@ -362,7 +359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { captured_place.place, upvar_ty, capture, captured_place.mutability, ); - apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture) + apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region) }) .collect() } @@ -417,10 +414,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::ClosureKind::FnOnce => (closure_kind, origin), }, - ty::UpvarCapture::ByRef(ty::UpvarBorrow { - kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, - .. - }) => { + ty::UpvarCapture::ByRef( + ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, + ) => { match closure_kind { ty::ClosureKind::Fn => { (ty::ClosureKind::FnMut, Some((usage_span, place.clone()))) @@ -535,6 +531,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, closure_def_id: DefId, capture_information: InferredCaptureInformation<'tcx>, + closure_span: Span, ) { if capture_information.is_empty() { return; @@ -554,8 +551,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) { None => { let mutability = self.determine_capture_mutability(&typeck_results, &place); - let min_cap_list = - vec![ty::CapturedPlace { place, info: capture_info, mutability }]; + let min_cap_list = vec![ty::CapturedPlace { + place, + info: capture_info, + mutability, + region: None, + }]; root_var_min_capture_list.insert(var_hir_id, min_cap_list); continue; } @@ -640,12 +641,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only need to insert when we don't have an ancestor in the existing min capture list if !ancestor_found { let mutability = self.determine_capture_mutability(&typeck_results, &place); - let captured_place = - ty::CapturedPlace { place, info: updated_capture_info, mutability }; + let captured_place = ty::CapturedPlace { + place, + info: updated_capture_info, + mutability, + region: None, + }; min_cap_list.push(captured_place); } } + // For each capture that is determined to be captured by ref, add region info. + for (_, captures) in &mut root_var_min_capture_list { + for capture in captures { + match capture.info.capture_kind { + ty::UpvarCapture::ByRef(_) => { + let PlaceBase::Upvar(upvar_id) = capture.place.base else { bug!("expected upvar") }; + let origin = UpvarRegion(upvar_id, closure_span); + let upvar_region = self.next_region_var(origin); + capture.region = Some(upvar_region); + } + _ => (), + } + } + } + debug!( "For closure={:?}, min_captures before sorting={:?}", closure_def_id, root_var_min_capture_list @@ -947,7 +967,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { max_capture_info = determine_capture_info(max_capture_info, capture.info); } - apply_capture_kind_on_capture_ty(self.tcx, ty, max_capture_info.capture_kind) + apply_capture_kind_on_capture_ty( + self.tcx, + ty, + max_capture_info.capture_kind, + Some(&ty::ReErased), + ) } }; @@ -977,6 +1002,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, capture.place.ty(), capture.info.capture_kind, + Some(&ty::ReErased), ); // Checks if a capture implements any of the auto traits @@ -1470,9 +1496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, place: &Place<'tcx>, capture_clause: hir::CaptureBy, - upvar_id: ty::UpvarId, - closure_span: Span, - ) -> ty::UpvarCapture<'tcx> { + ) -> ty::UpvarCapture { match capture_clause { // In case of a move closure if the data is accessed through a reference we // want to capture by ref to allow precise capture using reborrows. @@ -1483,12 +1507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::CaptureBy::Value if !place.deref_tys().any(ty::TyS::is_ref) => { ty::UpvarCapture::ByValue } - hir::CaptureBy::Value | hir::CaptureBy::Ref => { - let origin = UpvarRegion(upvar_id, closure_span); - let upvar_region = self.next_region_var(origin); - let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region }; - ty::UpvarCapture::ByRef(upvar_borrow) - } + hir::CaptureBy::Value | hir::CaptureBy::Ref => ty::UpvarCapture::ByRef(ty::ImmBorrow), } } @@ -1513,7 +1532,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn log_capture_analysis_first_pass( &self, closure_def_id: rustc_hir::def_id::DefId, - capture_information: &FxIndexMap, ty::CaptureInfo<'tcx>>, + capture_information: &FxIndexMap, ty::CaptureInfo>, closure_span: Span, ) { if self.should_log_capture_analysis(closure_def_id) { @@ -1630,8 +1649,8 @@ fn restrict_repr_packed_field_ref_capture<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, place: &Place<'tcx>, - mut curr_borrow_kind: ty::UpvarCapture<'tcx>, -) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { + mut curr_borrow_kind: ty::UpvarCapture, +) -> (Place<'tcx>, ty::UpvarCapture) { let pos = place.projections.iter().enumerate().position(|(i, p)| { let ty = place.ty_before_projection(i); @@ -1675,12 +1694,14 @@ fn restrict_repr_packed_field_ref_capture<'tcx>( fn apply_capture_kind_on_capture_ty<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, - capture_kind: UpvarCapture<'tcx>, + capture_kind: UpvarCapture, + region: Option>, ) -> Ty<'tcx> { match capture_kind { ty::UpvarCapture::ByValue => ty, - ty::UpvarCapture::ByRef(borrow) => tcx - .mk_ref(borrow.region, ty::TypeAndMut { ty: ty, mutbl: borrow.kind.to_mutbl_lossy() }), + ty::UpvarCapture::ByRef(kind) => { + tcx.mk_ref(region.unwrap(), ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() }) + } } } @@ -1710,8 +1731,6 @@ struct InferBorrowKind<'a, 'tcx> { // The def-id of the closure whose kind and upvar accesses are being inferred. closure_def_id: DefId, - closure_span: Span, - /// For each Place that is captured by the closure, we track the minimal kind of /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access. /// @@ -1749,7 +1768,6 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, ) { - let tcx = self.fcx.tcx; let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return; }; @@ -1842,15 +1860,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { if let ty::UpvarCapture::ByValue = curr_capture_info.capture_kind { // It's already captured by value, we don't need to do anything here return; - } else if let ty::UpvarCapture::ByRef(curr_upvar_borrow) = curr_capture_info.capture_kind { - // Use the same region as the current capture information - // Doesn't matter since only one of the UpvarBorrow will be used. - let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region }; - + } else if let ty::UpvarCapture::ByRef(_) = curr_capture_info.capture_kind { let capture_info = ty::CaptureInfo { capture_kind_expr_id: Some(diag_expr_id), path_expr_id: Some(diag_expr_id), - capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow), + capture_kind: ty::UpvarCapture::ByRef(kind), }; let updated_info = determine_capture_info(curr_capture_info, capture_info); self.capture_information[&place_with_id.place] = updated_info; @@ -1868,10 +1882,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { // Initialize to ImmBorrow // We will escalate the CaptureKind based on any uses we see or in `process_collected_capture_information`. - let origin = UpvarRegion(upvar_id, self.closure_span); - let upvar_region = self.fcx.next_region_var(origin); - let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region }; - let capture_kind = ty::UpvarCapture::ByRef(upvar_borrow); + let capture_kind = ty::UpvarCapture::ByRef(ty::ImmBorrow); let expr_id = Some(diag_expr_id); let capture_info = ty::CaptureInfo { @@ -1894,10 +1905,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { if let PlaceBase::Upvar(_) = place.base { // We need to restrict Fake Read precision to avoid fake reading unsafe code, // such as deref of a raw pointer. - let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::UpvarBorrow { - kind: ty::BorrowKind::ImmBorrow, - region: &ty::ReErased, - }); + let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow); let (place, _) = restrict_capture_precision(place, dummy_capture_kind); @@ -1928,8 +1936,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { bk: ty::BorrowKind, ) { // The region here will get discarded/ignored - let dummy_capture_kind = - ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: bk, region: &ty::ReErased }); + let dummy_capture_kind = ty::UpvarCapture::ByRef(bk); // We only want repr packed restriction to be applied to reading references into a packed // struct, and not when the data is being moved. Therefore we call this method here instead @@ -1948,7 +1955,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { } match updated_kind { - ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, .. }) => match kind { + ty::UpvarCapture::ByRef(kind) => match kind { ty::ImmBorrow => {} ty::UniqueImmBorrow => { self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id); @@ -1973,9 +1980,9 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { fn restrict_precision_for_drop_types<'a, 'tcx>( fcx: &'a FnCtxt<'a, 'tcx>, mut place: Place<'tcx>, - mut curr_mode: ty::UpvarCapture<'tcx>, + mut curr_mode: ty::UpvarCapture, span: Span, -) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { +) -> (Place<'tcx>, ty::UpvarCapture) { let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span); if let (false, UpvarCapture::ByValue) = (is_copy_type, curr_mode) { @@ -1999,8 +2006,8 @@ fn restrict_precision_for_drop_types<'a, 'tcx>( /// - No projections are applied on top of Union ADTs, since these require unsafe blocks. fn restrict_precision_for_unsafe<'tcx>( mut place: Place<'tcx>, - mut curr_mode: ty::UpvarCapture<'tcx>, -) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { + mut curr_mode: ty::UpvarCapture, +) -> (Place<'tcx>, ty::UpvarCapture) { if place.base_ty.is_unsafe_ptr() { truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0); } @@ -2032,8 +2039,8 @@ fn restrict_precision_for_unsafe<'tcx>( /// Returns the truncated place and updated cature mode. fn restrict_capture_precision<'tcx>( place: Place<'tcx>, - curr_mode: ty::UpvarCapture<'tcx>, -) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { + curr_mode: ty::UpvarCapture, +) -> (Place<'tcx>, ty::UpvarCapture) { let (mut place, mut curr_mode) = restrict_precision_for_unsafe(place, curr_mode); if place.projections.is_empty() { @@ -2060,8 +2067,8 @@ fn restrict_capture_precision<'tcx>( /// Truncate deref of any reference. fn adjust_for_move_closure<'tcx>( mut place: Place<'tcx>, - mut kind: ty::UpvarCapture<'tcx>, -) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { + mut kind: ty::UpvarCapture, +) -> (Place<'tcx>, ty::UpvarCapture) { let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); if let Some(idx) = first_deref { @@ -2075,8 +2082,8 @@ fn adjust_for_move_closure<'tcx>( /// from enclosing stack frame. fn adjust_for_non_move_closure<'tcx>( mut place: Place<'tcx>, - mut kind: ty::UpvarCapture<'tcx>, -) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { + mut kind: ty::UpvarCapture, +) -> (Place<'tcx>, ty::UpvarCapture) { let contains_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); @@ -2119,13 +2126,13 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String fn construct_capture_kind_reason_string<'tcx>( tcx: TyCtxt<'_>, place: &Place<'tcx>, - capture_info: &ty::CaptureInfo<'tcx>, + capture_info: &ty::CaptureInfo, ) -> String { let place_str = construct_place_string(tcx, place); let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), - ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind), + ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind), }; format!("{} captured as {} here", place_str, capture_kind_str) @@ -2140,13 +2147,13 @@ fn construct_path_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String { fn construct_capture_info_string<'tcx>( tcx: TyCtxt<'_>, place: &Place<'tcx>, - capture_info: &ty::CaptureInfo<'tcx>, + capture_info: &ty::CaptureInfo, ) -> String { let place_str = construct_place_string(tcx, place); let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), - ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind), + ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind), }; format!("{} -> {}", place_str, capture_kind_str) } @@ -2229,17 +2236,15 @@ fn migration_suggestion_for_2229( /// would've already handled `E1`, and have an existing capture_information for it. /// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return /// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics. -fn determine_capture_info<'tcx>( - capture_info_a: ty::CaptureInfo<'tcx>, - capture_info_b: ty::CaptureInfo<'tcx>, -) -> ty::CaptureInfo<'tcx> { +fn determine_capture_info( + capture_info_a: ty::CaptureInfo, + capture_info_b: ty::CaptureInfo, +) -> ty::CaptureInfo { // If the capture kind is equivalent then, we don't need to escalate and can compare the // expressions. let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) { (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true, - (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { - ref_a.kind == ref_b.kind - } + (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b, (ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false, }; @@ -2255,7 +2260,7 @@ fn determine_capture_info<'tcx>( (ty::UpvarCapture::ByValue, _) => capture_info_a, (_, ty::UpvarCapture::ByValue) => capture_info_b, (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { - match (ref_a.kind, ref_b.kind) { + match (ref_a, ref_b) { // Take LHS: (ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow) | (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a, @@ -2283,7 +2288,7 @@ fn determine_capture_info<'tcx>( /// contained `Deref` of `&mut`. fn truncate_place_to_len_and_update_capture_kind<'tcx>( place: &mut Place<'tcx>, - curr_mode: &mut ty::UpvarCapture<'tcx>, + curr_mode: &mut ty::UpvarCapture, len: usize, ) { let is_mut_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Mut)); @@ -2293,15 +2298,12 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>( // Note that if the place contained Deref of a raw pointer it would've not been MutBorrow, so // we don't need to worry about that case here. match curr_mode { - ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: ty::BorrowKind::MutBorrow, region }) => { + ty::UpvarCapture::ByRef(ty::BorrowKind::MutBorrow) => { for i in len..place.projections.len() { if place.projections[i].kind == ProjectionKind::Deref && is_mut_ref(place.ty_before_projection(i)) { - *curr_mode = ty::UpvarCapture::ByRef(ty::UpvarBorrow { - kind: ty::BorrowKind::UniqueImmBorrow, - region, - }); + *curr_mode = ty::UpvarCapture::ByRef(ty::BorrowKind::UniqueImmBorrow); break; } } @@ -2379,8 +2381,8 @@ fn determine_place_ancestry_relation<'tcx>( /// ``` fn truncate_capture_for_optimization<'tcx>( mut place: Place<'tcx>, - mut curr_mode: ty::UpvarCapture<'tcx>, -) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) { + mut curr_mode: ty::UpvarCapture, +) -> (Place<'tcx>, ty::UpvarCapture) { let is_shared_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not)); // Find the right-most deref (if any). All the projections that come after this diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 5b6e73ef5ee1e..352cdefc0b47b 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -803,7 +803,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.delegate.borrow( &place_with_id, place_with_id.hir_id, - upvar_borrow.kind, + upvar_borrow, ); } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 5ce68bc4d1d5c..2a06cf121ff01 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -970,7 +970,7 @@ pub fn can_move_expr_to_closure(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> if !self.locals.contains(&local_id) { let capture = match capture.info.capture_kind { UpvarCapture::ByValue => CaptureKind::Value, - UpvarCapture::ByRef(borrow) => match borrow.kind { + UpvarCapture::ByRef(kind) => match kind { BorrowKind::ImmBorrow => CaptureKind::Ref(Mutability::Not), BorrowKind::UniqueImmBorrow | BorrowKind::MutBorrow => { CaptureKind::Ref(Mutability::Mut) From 52db6b9d02a22eb1f54ea5f045d3744c98edd50f Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 13 Oct 2021 21:37:53 +0100 Subject: [PATCH 3/4] InferBorrowKind cleanup `adjust_upvar_deref` and friends are implemented so that they reuse existing region so new region vars don't have to be generated. Since now we don't have to generate region vars in `InferBorrowKind`, creating a new capture info would be cheap and we can just use `determine_capture_info`. syn is updated so that let_else syntax can be used in fn with `#[instrument]` attribute. `restrict_repr_packed_field_ref_capture` is changed to take place by value since cloning is needed anyway. --- compiler/rustc_typeck/src/check/upvar.rs | 229 +++++------------------ 1 file changed, 52 insertions(+), 177 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 591c2fc5a8145..470405babb379 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -207,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert_eq!(body_owner_def_id.to_def_id(), closure_def_id); let mut delegate = InferBorrowKind { fcx: self, - closure_def_id, + closure_def_id: local_def_id, capture_information: Default::default(), fake_reads: Default::default(), }; @@ -1648,7 +1648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn restrict_repr_packed_field_ref_capture<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - place: &Place<'tcx>, + mut place: Place<'tcx>, mut curr_borrow_kind: ty::UpvarCapture, ) -> (Place<'tcx>, ty::UpvarCapture) { let pos = place.projections.iter().enumerate().position(|(i, p)| { @@ -1681,8 +1681,6 @@ fn restrict_repr_packed_field_ref_capture<'tcx>( } }); - let mut place = place.clone(); - if let Some(pos) = pos { truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_borrow_kind, pos); } @@ -1729,7 +1727,7 @@ struct InferBorrowKind<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, // The def-id of the closure whose kind and upvar accesses are being inferred. - closure_def_id: DefId, + closure_def_id: LocalDefId, /// For each Place that is captured by the closure, we track the minimal kind of /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access. @@ -1762,170 +1760,51 @@ struct InferBorrowKind<'a, 'tcx> { } impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { - #[instrument(skip(self), level = "debug")] - fn adjust_upvar_borrow_kind_for_consume( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - ) { - let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { - return; - }; - - debug!(?upvar_id); - - let capture_info = ty::CaptureInfo { - capture_kind_expr_id: Some(diag_expr_id), - path_expr_id: Some(diag_expr_id), - capture_kind: ty::UpvarCapture::ByValue, - }; - - let curr_info = self.capture_information[&place_with_id.place]; - let updated_info = determine_capture_info(curr_info, capture_info); - - self.capture_information[&place_with_id.place] = updated_info; - } - - /// Indicates that `place_with_id` is being directly mutated (e.g., assigned - /// to). If the place is based on a by-ref upvar, this implies that - /// the upvar must be borrowed using an `&mut` borrow. - #[instrument(skip(self), level = "debug")] - fn adjust_upvar_borrow_kind_for_mut( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - ) { - if let PlaceBase::Upvar(_) = place_with_id.place.base { - // Raw pointers don't inherit mutability - if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { - return; + fn adjust_capture_info(&mut self, place: Place<'tcx>, capture_info: ty::CaptureInfo) { + match self.capture_information.get_mut(&place) { + Some(curr_info) => { + *curr_info = determine_capture_info(*curr_info, capture_info); } - self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::MutBorrow); - } - } - - #[instrument(skip(self), level = "debug")] - fn adjust_upvar_borrow_kind_for_unique( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - ) { - if let PlaceBase::Upvar(_) = place_with_id.place.base { - if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { - // Raw pointers don't inherit mutability. - return; + None => { + debug!("Capturing new place {:?}, capture_info={:?}", place, capture_info); + self.capture_information.insert(place, capture_info); } - // for a borrowed pointer to be unique, its base must be unique - self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::UniqueImmBorrow); - } - } - - fn adjust_upvar_deref( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - borrow_kind: ty::BorrowKind, - ) { - assert!(match borrow_kind { - ty::MutBorrow => true, - ty::UniqueImmBorrow => true, - - // imm borrows never require adjusting any kinds, so we don't wind up here - ty::ImmBorrow => false, - }); - - // if this is an implicit deref of an - // upvar, then we need to modify the - // borrow_kind of the upvar to make sure it - // is inferred to mutable if necessary - self.adjust_upvar_borrow_kind(place_with_id, diag_expr_id, borrow_kind); - } - - /// We infer the borrow_kind with which to borrow upvars in a stack closure. - /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`, - /// moving from left to right as needed (but never right to left). - /// Here the argument `mutbl` is the borrow_kind that is required by - /// some particular use. - #[instrument(skip(self), level = "debug")] - fn adjust_upvar_borrow_kind( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - kind: ty::BorrowKind, - ) { - let curr_capture_info = self.capture_information[&place_with_id.place]; - - debug!(?curr_capture_info); - - if let ty::UpvarCapture::ByValue = curr_capture_info.capture_kind { - // It's already captured by value, we don't need to do anything here - return; - } else if let ty::UpvarCapture::ByRef(_) = curr_capture_info.capture_kind { - let capture_info = ty::CaptureInfo { - capture_kind_expr_id: Some(diag_expr_id), - path_expr_id: Some(diag_expr_id), - capture_kind: ty::UpvarCapture::ByRef(kind), - }; - let updated_info = determine_capture_info(curr_capture_info, capture_info); - self.capture_information[&place_with_id.place] = updated_info; - }; - } - - #[instrument(skip(self, diag_expr_id), level = "debug")] - fn init_capture_info_for_place( - &mut self, - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: hir::HirId, - ) { - if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { - assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id); - - // Initialize to ImmBorrow - // We will escalate the CaptureKind based on any uses we see or in `process_collected_capture_information`. - let capture_kind = ty::UpvarCapture::ByRef(ty::ImmBorrow); - - let expr_id = Some(diag_expr_id); - let capture_info = ty::CaptureInfo { - capture_kind_expr_id: expr_id, - path_expr_id: expr_id, - capture_kind, - }; - - debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info); - - self.capture_information.insert(place_with_id.place.clone(), capture_info); - } else { - debug!("Not upvar"); } } } impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) { - if let PlaceBase::Upvar(_) = place.base { - // We need to restrict Fake Read precision to avoid fake reading unsafe code, - // such as deref of a raw pointer. - let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow); - - let (place, _) = restrict_capture_precision(place, dummy_capture_kind); - - let (place, _) = restrict_repr_packed_field_ref_capture( - self.fcx.tcx, - self.fcx.param_env, - &place, - dummy_capture_kind, - ); - self.fake_reads.push((place, cause, diag_expr_id)); - } + let PlaceBase::Upvar(_) = place.base else { return }; + + // We need to restrict Fake Read precision to avoid fake reading unsafe code, + // such as deref of a raw pointer. + let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow); + + let (place, _) = restrict_capture_precision(place, dummy_capture_kind); + + let (place, _) = restrict_repr_packed_field_ref_capture( + self.fcx.tcx, + self.fcx.param_env, + place, + dummy_capture_kind, + ); + self.fake_reads.push((place, cause, diag_expr_id)); } #[instrument(skip(self), level = "debug")] fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { - if !self.capture_information.contains_key(&place_with_id.place) { - self.init_capture_info_for_place(place_with_id, diag_expr_id); - } + let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return }; + assert_eq!(self.closure_def_id, upvar_id.closure_expr_id); - self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id); + self.adjust_capture_info( + place_with_id.place.clone(), + ty::CaptureInfo { + capture_kind_expr_id: Some(diag_expr_id), + path_expr_id: Some(diag_expr_id), + capture_kind: ty::UpvarCapture::ByValue, + }, + ); } #[instrument(skip(self), level = "debug")] @@ -1935,39 +1814,35 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { diag_expr_id: hir::HirId, bk: ty::BorrowKind, ) { + let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return }; + assert_eq!(self.closure_def_id, upvar_id.closure_expr_id); + // The region here will get discarded/ignored - let dummy_capture_kind = ty::UpvarCapture::ByRef(bk); + let capture_kind = ty::UpvarCapture::ByRef(bk); // We only want repr packed restriction to be applied to reading references into a packed // struct, and not when the data is being moved. Therefore we call this method here instead // of in `restrict_capture_precision`. - let (place, updated_kind) = restrict_repr_packed_field_ref_capture( + let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture( self.fcx.tcx, self.fcx.param_env, - &place_with_id.place, - dummy_capture_kind, + place_with_id.place.clone(), + capture_kind, ); - let place_with_id = PlaceWithHirId { place, ..*place_with_id }; - - if !self.capture_information.contains_key(&place_with_id.place) { - self.init_capture_info_for_place(&place_with_id, diag_expr_id); + // Raw pointers don't inherit mutability + if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { + capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow); } - match updated_kind { - ty::UpvarCapture::ByRef(kind) => match kind { - ty::ImmBorrow => {} - ty::UniqueImmBorrow => { - self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id); - } - ty::MutBorrow => { - self.adjust_upvar_borrow_kind_for_mut(&place_with_id, diag_expr_id); - } + self.adjust_capture_info( + place, + ty::CaptureInfo { + capture_kind_expr_id: Some(diag_expr_id), + path_expr_id: Some(diag_expr_id), + capture_kind, }, - - // Just truncating the place will never cause capture kind to be updated to ByValue - ty::UpvarCapture::ByValue => unreachable!(), - } + ); } #[instrument(skip(self), level = "debug")] From c84cea9c25e8db73b1b580ab9c7f72985a05da4d Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 13 Oct 2021 22:14:37 +0100 Subject: [PATCH 4/4] Flatten InferredCaptureInformation Min capture computation can already handle the same place appearing twice, and previous commits made CaptureInfo construction very cheap, so just delegate all work to min capture and let InferBorrowKind and process_collected_capture_information handle everything linearly. --- compiler/rustc_typeck/src/check/upvar.rs | 147 ++++++++---------- .../arrays-completely-captured.rs | 1 + .../arrays-completely-captured.stderr | 9 +- .../destructure_patterns.rs | 2 + .../destructure_patterns.stderr | 42 +++-- .../diagnostics/union.rs | 25 +++ .../diagnostics/union.stderr | 18 +++ .../2229_closure_analysis/nested-closure.rs | 1 + .../nested-closure.stderr | 9 +- .../2229_closure_analysis/repr_packed.rs | 1 + .../2229_closure_analysis/repr_packed.stderr | 21 ++- 11 files changed, 168 insertions(+), 108 deletions(-) create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs create mode 100644 src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 470405babb379..8d3c70b05734f 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -33,7 +33,6 @@ use super::FnCtxt; use crate::expr_use_visitor as euv; -use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -72,7 +71,7 @@ enum PlaceAncestryRelation { /// Intermediate format to store a captured `Place` and associated `ty::CaptureInfo` /// during capture analysis. Information in this map feeds into the minimum capture /// analysis pass. -type InferredCaptureInformation<'tcx> = FxIndexMap, ty::CaptureInfo>; +type InferredCaptureInformation<'tcx> = Vec<(Place<'tcx>, ty::CaptureInfo)>; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) { @@ -258,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { capture_kind, }; - capture_information.insert(place, fake_info); + capture_information.push((place, fake_info)); } } @@ -384,76 +383,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { capture_clause: hir::CaptureBy, capture_information: InferredCaptureInformation<'tcx>, ) -> (InferredCaptureInformation<'tcx>, ty::ClosureKind, Option<(Span, Place<'tcx>)>) { - let mut processed: InferredCaptureInformation<'tcx> = Default::default(); - let mut closure_kind = ty::ClosureKind::LATTICE_BOTTOM; let mut origin: Option<(Span, Place<'tcx>)> = None; - for (place, mut capture_info) in capture_information { - // Apply rules for safety before inferring closure kind - let (place, capture_kind) = - restrict_capture_precision(place, capture_info.capture_kind); - capture_info.capture_kind = capture_kind; + let processed = capture_information + .into_iter() + .map(|(place, mut capture_info)| { + // Apply rules for safety before inferring closure kind + let (place, capture_kind) = + restrict_capture_precision(place, capture_info.capture_kind); - let (place, capture_kind) = - truncate_capture_for_optimization(place, capture_info.capture_kind); - capture_info.capture_kind = capture_kind; + let (place, capture_kind) = truncate_capture_for_optimization(place, capture_kind); - let usage_span = if let Some(usage_expr) = capture_info.path_expr_id { - self.tcx.hir().span(usage_expr) - } else { - unreachable!() - }; + let usage_span = if let Some(usage_expr) = capture_info.path_expr_id { + self.tcx.hir().span(usage_expr) + } else { + unreachable!() + }; - let updated = match capture_info.capture_kind { - ty::UpvarCapture::ByValue => match closure_kind { - ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { - (ty::ClosureKind::FnOnce, Some((usage_span, place.clone()))) - } - // If closure is already FnOnce, don't update - ty::ClosureKind::FnOnce => (closure_kind, origin), - }, + let updated = match capture_kind { + ty::UpvarCapture::ByValue => match closure_kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { + (ty::ClosureKind::FnOnce, Some((usage_span, place.clone()))) + } + // If closure is already FnOnce, don't update + ty::ClosureKind::FnOnce => (closure_kind, origin.take()), + }, - ty::UpvarCapture::ByRef( - ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, - ) => { - match closure_kind { - ty::ClosureKind::Fn => { - (ty::ClosureKind::FnMut, Some((usage_span, place.clone()))) + ty::UpvarCapture::ByRef( + ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow, + ) => { + match closure_kind { + ty::ClosureKind::Fn => { + (ty::ClosureKind::FnMut, Some((usage_span, place.clone()))) + } + // Don't update the origin + ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => { + (closure_kind, origin.take()) + } } - // Don't update the origin - ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => (closure_kind, origin), } - } - - _ => (closure_kind, origin), - }; - closure_kind = updated.0; - origin = updated.1; + _ => (closure_kind, origin.take()), + }; - let (place, capture_kind) = match capture_clause { - hir::CaptureBy::Value => adjust_for_move_closure(place, capture_info.capture_kind), - hir::CaptureBy::Ref => { - adjust_for_non_move_closure(place, capture_info.capture_kind) - } - }; + closure_kind = updated.0; + origin = updated.1; - // This restriction needs to be applied after we have handled adjustments for `move` - // closures. We want to make sure any adjustment that might make us move the place into - // the closure gets handled. - let (place, capture_kind) = - restrict_precision_for_drop_types(self, place, capture_kind, usage_span); + let (place, capture_kind) = match capture_clause { + hir::CaptureBy::Value => adjust_for_move_closure(place, capture_kind), + hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind), + }; - capture_info.capture_kind = capture_kind; + // This restriction needs to be applied after we have handled adjustments for `move` + // closures. We want to make sure any adjustment that might make us move the place into + // the closure gets handled. + let (place, capture_kind) = + restrict_precision_for_drop_types(self, place, capture_kind, usage_span); - let capture_info = if let Some(existing) = processed.get(&place) { - determine_capture_info(*existing, capture_info) - } else { - capture_info - }; - processed.insert(place, capture_info); - } + capture_info.capture_kind = capture_kind; + (place, capture_info) + }) + .collect(); (processed, closure_kind, origin) } @@ -609,8 +600,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !descendant_found { for possible_ancestor in min_cap_list.iter_mut() { match determine_place_ancestry_relation(&place, &possible_ancestor.place) { + PlaceAncestryRelation::SamePlace => { + ancestor_found = true; + possible_ancestor.info = determine_capture_info( + possible_ancestor.info, + updated_capture_info, + ); + + // Only one related place will be in the list. + break; + } // current place is descendant of possible_ancestor - PlaceAncestryRelation::Descendant | PlaceAncestryRelation::SamePlace => { + PlaceAncestryRelation::Descendant => { ancestor_found = true; let backup_path_expr_id = possible_ancestor.info.path_expr_id; @@ -630,7 +631,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we need to keep the ancestor's `path_expr_id` possible_ancestor.info.path_expr_id = backup_path_expr_id; - // Only one ancestor of the current place will be in the list. + // Only one related place will be in the list. break; } _ => {} @@ -1532,7 +1533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn log_capture_analysis_first_pass( &self, closure_def_id: rustc_hir::def_id::DefId, - capture_information: &FxIndexMap, ty::CaptureInfo>, + capture_information: &InferredCaptureInformation<'tcx>, closure_span: Span, ) { if self.should_log_capture_analysis(closure_def_id) { @@ -1759,20 +1760,6 @@ struct InferBorrowKind<'a, 'tcx> { fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>, } -impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { - fn adjust_capture_info(&mut self, place: Place<'tcx>, capture_info: ty::CaptureInfo) { - match self.capture_information.get_mut(&place) { - Some(curr_info) => { - *curr_info = determine_capture_info(*curr_info, capture_info); - } - None => { - debug!("Capturing new place {:?}, capture_info={:?}", place, capture_info); - self.capture_information.insert(place, capture_info); - } - } - } -} - impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) { let PlaceBase::Upvar(_) = place.base else { return }; @@ -1797,14 +1784,14 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return }; assert_eq!(self.closure_def_id, upvar_id.closure_expr_id); - self.adjust_capture_info( + self.capture_information.push(( place_with_id.place.clone(), ty::CaptureInfo { capture_kind_expr_id: Some(diag_expr_id), path_expr_id: Some(diag_expr_id), capture_kind: ty::UpvarCapture::ByValue, }, - ); + )); } #[instrument(skip(self), level = "debug")] @@ -1835,14 +1822,14 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow); } - self.adjust_capture_info( + self.capture_information.push(( place, ty::CaptureInfo { capture_kind_expr_id: Some(diag_expr_id), path_expr_id: Some(diag_expr_id), capture_kind, }, - ); + )); } #[instrument(skip(self), level = "debug")] diff --git a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs index 7a4b21f022365..2bcbd792e3a83 100644 --- a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs +++ b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs @@ -15,6 +15,7 @@ fn main() { //~^ NOTE: Capturing m[] -> MutBorrow //~| NOTE: Min Capture m[] -> MutBorrow m[1] += 40; + //~^ NOTE: Capturing m[] -> MutBorrow }; c(); diff --git a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr index 69ec53447b8a6..129b26456ce1d 100644 --- a/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr +++ b/src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr @@ -15,7 +15,7 @@ LL | | LL | | LL | | m[0] += 10; ... | -LL | | m[1] += 40; +LL | | LL | | }; | |_____^ | @@ -24,6 +24,11 @@ note: Capturing m[] -> MutBorrow | LL | m[0] += 10; | ^ +note: Capturing m[] -> MutBorrow + --> $DIR/arrays-completely-captured.rs:17:9 + | +LL | m[1] += 40; + | ^ error: Min Capture analysis includes: --> $DIR/arrays-completely-captured.rs:11:5 @@ -33,7 +38,7 @@ LL | | LL | | LL | | m[0] += 10; ... | -LL | | m[1] += 40; +LL | | LL | | }; | |_____^ | diff --git a/src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs b/src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs index 9918802334ecc..6c65a7bf87b96 100644 --- a/src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs +++ b/src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs @@ -15,6 +15,8 @@ fn arrays() { //~| ERROR: Min Capture analysis includes: let [a, b, .., e] = arr; //~^ NOTE: Capturing arr[Index] -> ByValue + //~| NOTE: Capturing arr[Index] -> ByValue + //~| NOTE: Capturing arr[Index] -> ByValue //~| NOTE: Min Capture arr[] -> ByValue assert_eq!(a, "A"); assert_eq!(b, "B"); diff --git a/src/test/ui/closures/2229_closure_analysis/destructure_patterns.stderr b/src/test/ui/closures/2229_closure_analysis/destructure_patterns.stderr index b53adb5248161..44fbe6d8158f2 100644 --- a/src/test/ui/closures/2229_closure_analysis/destructure_patterns.stderr +++ b/src/test/ui/closures/2229_closure_analysis/destructure_patterns.stderr @@ -8,7 +8,7 @@ LL | let c = #[rustc_capture_analysis] = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable error[E0658]: attributes on expressions are experimental - --> $DIR/destructure_patterns.rs:36:13 + --> $DIR/destructure_patterns.rs:38:13 | LL | let c = #[rustc_capture_analysis] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let c = #[rustc_capture_analysis] = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable error[E0658]: attributes on expressions are experimental - --> $DIR/destructure_patterns.rs:56:13 + --> $DIR/destructure_patterns.rs:58:13 | LL | let c = #[rustc_capture_analysis] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,6 +42,16 @@ note: Capturing arr[Index] -> ByValue | LL | let [a, b, .., e] = arr; | ^^^ +note: Capturing arr[Index] -> ByValue + --> $DIR/destructure_patterns.rs:16:29 + | +LL | let [a, b, .., e] = arr; + | ^^^ +note: Capturing arr[Index] -> ByValue + --> $DIR/destructure_patterns.rs:16:29 + | +LL | let [a, b, .., e] = arr; + | ^^^ error: Min Capture analysis includes: --> $DIR/destructure_patterns.rs:13:5 @@ -62,7 +72,7 @@ LL | let [a, b, .., e] = arr; | ^^^ error: First Pass analysis includes: - --> $DIR/destructure_patterns.rs:39:5 + --> $DIR/destructure_patterns.rs:41:5 | LL | / || { LL | | @@ -74,18 +84,18 @@ LL | | }; | |_____^ | note: Capturing p[(0, 0)] -> MutBorrow - --> $DIR/destructure_patterns.rs:42:58 + --> $DIR/destructure_patterns.rs:44:58 | LL | let Point { x: ref mut x, y: _, id: moved_id } = p; | ^ note: Capturing p[(2, 0)] -> ByValue - --> $DIR/destructure_patterns.rs:42:58 + --> $DIR/destructure_patterns.rs:44:58 | LL | let Point { x: ref mut x, y: _, id: moved_id } = p; | ^ error: Min Capture analysis includes: - --> $DIR/destructure_patterns.rs:39:5 + --> $DIR/destructure_patterns.rs:41:5 | LL | / || { LL | | @@ -97,18 +107,18 @@ LL | | }; | |_____^ | note: Min Capture p[(0, 0)] -> MutBorrow - --> $DIR/destructure_patterns.rs:42:58 + --> $DIR/destructure_patterns.rs:44:58 | LL | let Point { x: ref mut x, y: _, id: moved_id } = p; | ^ note: Min Capture p[(2, 0)] -> ByValue - --> $DIR/destructure_patterns.rs:42:58 + --> $DIR/destructure_patterns.rs:44:58 | LL | let Point { x: ref mut x, y: _, id: moved_id } = p; | ^ error: First Pass analysis includes: - --> $DIR/destructure_patterns.rs:59:5 + --> $DIR/destructure_patterns.rs:61:5 | LL | / || { LL | | @@ -120,23 +130,23 @@ LL | | }; | |_____^ | note: Capturing t[(0, 0)] -> MutBorrow - --> $DIR/destructure_patterns.rs:62:54 + --> $DIR/destructure_patterns.rs:64:54 | LL | let (ref mut x, ref ref_str, (moved_s, _)) = t; | ^ note: Capturing t[(1, 0)] -> ImmBorrow - --> $DIR/destructure_patterns.rs:62:54 + --> $DIR/destructure_patterns.rs:64:54 | LL | let (ref mut x, ref ref_str, (moved_s, _)) = t; | ^ note: Capturing t[(2, 0),(0, 0)] -> ByValue - --> $DIR/destructure_patterns.rs:62:54 + --> $DIR/destructure_patterns.rs:64:54 | LL | let (ref mut x, ref ref_str, (moved_s, _)) = t; | ^ error: Min Capture analysis includes: - --> $DIR/destructure_patterns.rs:59:5 + --> $DIR/destructure_patterns.rs:61:5 | LL | / || { LL | | @@ -148,17 +158,17 @@ LL | | }; | |_____^ | note: Min Capture t[(0, 0)] -> MutBorrow - --> $DIR/destructure_patterns.rs:62:54 + --> $DIR/destructure_patterns.rs:64:54 | LL | let (ref mut x, ref ref_str, (moved_s, _)) = t; | ^ note: Min Capture t[(1, 0)] -> ImmBorrow - --> $DIR/destructure_patterns.rs:62:54 + --> $DIR/destructure_patterns.rs:64:54 | LL | let (ref mut x, ref ref_str, (moved_s, _)) = t; | ^ note: Min Capture t[(2, 0),(0, 0)] -> ByValue - --> $DIR/destructure_patterns.rs:62:54 + --> $DIR/destructure_patterns.rs:64:54 | LL | let (ref mut x, ref ref_str, (moved_s, _)) = t; | ^ diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs new file mode 100644 index 0000000000000..46b54846e32eb --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs @@ -0,0 +1,25 @@ +// edition:2021 + +// Test that we point to the correct location that results a union being captured. +// Union is special because it can't be disjointly captured. + +union A { + y: u32, + x: (), +} + +fn main() { + let mut a = A { y: 1 }; + let mut c = || { + //~^ borrow of `a.y` occurs here + let _ = unsafe { &a.y }; + let _ = &mut a; + //~^ borrow occurs due to use in closure + let _ = unsafe { &mut a.y }; + }; + a.y = 1; + //~^ cannot assign to `a.y` because it is borrowed [E0506] + //~| assignment to borrowed `a.y` occurs here + c(); + //~^ borrow later used here +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr new file mode 100644 index 0000000000000..7c34e2336c867 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr @@ -0,0 +1,18 @@ +error[E0506]: cannot assign to `a.y` because it is borrowed + --> $DIR/union.rs:20:5 + | +LL | let mut c = || { + | -- borrow of `a.y` occurs here +... +LL | let _ = &mut a; + | - borrow occurs due to use in closure +... +LL | a.y = 1; + | ^^^^^^^ assignment to borrowed `a.y` occurs here +... +LL | c(); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/closures/2229_closure_analysis/nested-closure.rs b/src/test/ui/closures/2229_closure_analysis/nested-closure.rs index f6775b3a3a5ac..22eae744b8080 100644 --- a/src/test/ui/closures/2229_closure_analysis/nested-closure.rs +++ b/src/test/ui/closures/2229_closure_analysis/nested-closure.rs @@ -40,6 +40,7 @@ fn main() { //~| NOTE: Min Capture p[(1, 0)] -> MutBorrow c2(); println!("{}", p.y); + //~^ NOTE: Capturing p[(1, 0)] -> ImmBorrow }; c1(); diff --git a/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr b/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr index 013bc74e67e1e..a50d0c6a182bc 100644 --- a/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr +++ b/src/test/ui/closures/2229_closure_analysis/nested-closure.stderr @@ -58,7 +58,7 @@ LL | | LL | | LL | | println!("{}", p.x); ... | -LL | | println!("{}", p.y); +LL | | LL | | }; | |_____^ | @@ -72,6 +72,11 @@ note: Capturing p[(1, 0)] -> MutBorrow | LL | || p.y += incr; | ^^^ +note: Capturing p[(1, 0)] -> ImmBorrow + --> $DIR/nested-closure.rs:42:24 + | +LL | println!("{}", p.y); + | ^^^ error: Min Capture analysis includes: --> $DIR/nested-closure.rs:22:5 @@ -81,7 +86,7 @@ LL | | LL | | LL | | println!("{}", p.x); ... | -LL | | println!("{}", p.y); +LL | | LL | | }; | |_____^ | diff --git a/src/test/ui/closures/2229_closure_analysis/repr_packed.rs b/src/test/ui/closures/2229_closure_analysis/repr_packed.rs index 7d472ad020f29..3ed780f51c73b 100644 --- a/src/test/ui/closures/2229_closure_analysis/repr_packed.rs +++ b/src/test/ui/closures/2229_closure_analysis/repr_packed.rs @@ -48,6 +48,7 @@ fn test_alignment_affected() { //~^ ERROR: First Pass analysis includes: //~| ERROR: Min Capture analysis includes: let z1: &String = &foo.x; + //~^ NOTE: Capturing foo[] -> ImmBorrow let z2: &mut u16 = &mut foo.y; //~^ NOTE: Capturing foo[] -> MutBorrow //~| NOTE: Min Capture foo[] -> MutBorrow diff --git a/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr b/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr index 405f66210aa55..580061ebc6ed9 100644 --- a/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr +++ b/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr @@ -17,7 +17,7 @@ LL | let mut c = #[rustc_capture_analysis] = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable error[E0658]: attributes on expressions are experimental - --> $DIR/repr_packed.rs:78:13 + --> $DIR/repr_packed.rs:79:13 | LL | let c = #[rustc_capture_analysis] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,8 +83,13 @@ LL | | println!("({}, {})", z1, z2); LL | | }; | |_____^ | +note: Capturing foo[] -> ImmBorrow + --> $DIR/repr_packed.rs:50:28 + | +LL | let z1: &String = &foo.x; + | ^^^^^ note: Capturing foo[] -> MutBorrow - --> $DIR/repr_packed.rs:51:33 + --> $DIR/repr_packed.rs:52:33 | LL | let z2: &mut u16 = &mut foo.y; | ^^^^^ @@ -102,13 +107,13 @@ LL | | }; | |_____^ | note: Min Capture foo[] -> MutBorrow - --> $DIR/repr_packed.rs:51:33 + --> $DIR/repr_packed.rs:52:33 | LL | let z2: &mut u16 = &mut foo.y; | ^^^^^ error: First Pass analysis includes: - --> $DIR/repr_packed.rs:81:5 + --> $DIR/repr_packed.rs:82:5 | LL | / || { LL | | @@ -120,18 +125,18 @@ LL | | }; | |_____^ | note: Capturing foo[] -> ImmBorrow - --> $DIR/repr_packed.rs:84:24 + --> $DIR/repr_packed.rs:85:24 | LL | println!("{}", foo.x); | ^^^^^ note: Capturing foo[(0, 0)] -> ByValue - --> $DIR/repr_packed.rs:88:18 + --> $DIR/repr_packed.rs:89:18 | LL | let _z = foo.x; | ^^^^^ error: Min Capture analysis includes: - --> $DIR/repr_packed.rs:81:5 + --> $DIR/repr_packed.rs:82:5 | LL | / || { LL | | @@ -143,7 +148,7 @@ LL | | }; | |_____^ | note: Min Capture foo[] -> ByValue - --> $DIR/repr_packed.rs:84:24 + --> $DIR/repr_packed.rs:85:24 | LL | println!("{}", foo.x); | ^^^^^ foo[] used here