diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 425e62d6f61..00c03d75380 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -431,7 +431,29 @@ pub struct TypeckResults<'tcx> { /// see `MinCaptureInformationMap` for more details. pub closure_min_captures: ty::MinCaptureInformationMap<'tcx>, - pub closure_fake_reads: FxHashMap, FakeReadCause)>>, + /// Tracks the fake reads required for a closure and the reason for the fake read. + /// When performing pattern matching for closures, there are times we don't end up + /// reading places that are mentioned in a closure (because of _ patterns). However, + /// to ensure the places are initialized, we introduce fake reads. + /// Consider these two examples: + /// ``` (discriminant matching with only wildcard arm) + /// let x: u8; + /// let c = || match x { _ => () }; + /// ``` + /// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't + /// want to capture it. However, we do still want an error here, because `x` should have + /// to be initialized at the point where c is created. Therefore, we add a "fake read" + /// instead. + /// ``` (destructured assignments) + /// let c = || { + /// let (t1, t2) = t; + /// } + /// ``` + /// In the second example, we capture the disjoint fields of `t` (`t.0` & `t.1`), but + /// we never capture `t`. This becomes an issue when we build MIR as we require + /// information on `t` in order to create place `t.0` and `t.1`. We can solve this + /// issue by fake reading `t`. + pub closure_fake_reads: FxHashMap, FakeReadCause, hir::HirId)>>, /// Stores the type, expression, span and optional scope span of all types /// that are live across the yield of this generator (if a generator). 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 0e70cd36efb..fbc9c30fe53 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -90,15 +90,13 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( let hir_projection = match mir_projection { ProjectionElem::Deref => HirProjectionKind::Deref, ProjectionElem::Field(field, _) => { - // We will never encouter this for multivariant enums, - // read the comment for `Downcast`. let variant = variant.unwrap_or(VariantIdx::new(0)); HirProjectionKind::Field(field.index() as u32, variant) } ProjectionElem::Downcast(.., idx) => { - // This projections exist for enums that have - // single and multiple variants. - // For single variants, enums are not captured completely. + // We don't expect to see multi-variant enums here, as earlier + // phases will have truncated them already. However, there can + // still be downcasts, thanks to single-variant enums. // We keep track of VariantIdx so we can use this information // if the next ProjectionElem is a Field. variant = Some(*idx); @@ -200,7 +198,7 @@ fn find_capture_matching_projections<'a, 'tcx>( /// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the /// `PlaceBuilder` now starts from `PlaceBase::Local`. /// -/// Returns a Result with the error being the HirId of the Upvar that was not found. +/// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found. fn to_upvars_resolved_place_builder<'a, 'tcx>( from_builder: PlaceBuilder<'tcx>, tcx: TyCtxt<'tcx>, @@ -305,15 +303,23 @@ impl<'tcx> PlaceBuilder<'tcx> { to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() } + /// Attempts to resolve the `PlaceBuilder`. + /// On success, it will return the resolved `PlaceBuilder`. + /// On failure, it will return itself. + /// + /// Upvars resolve may fail for a `PlaceBuilder` when attempting to + /// resolve a disjoint field whose root variable is not captured + /// (destructured assignments) or when attempting to resolve a root + /// variable (discriminant matching with only wildcard arm) that is + /// not captured. This can happen because the final mir that will be + /// generated doesn't require a read for this place. Failures will only + /// happen inside closures. crate fn try_upvars_resolved<'a>( self, tcx: TyCtxt<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, ) -> Result, PlaceBuilder<'tcx>> { - match to_upvars_resolved_place_builder(self, tcx, typeck_results) { - Ok(upvars_resolved) => Ok(upvars_resolved), - Err(upvars_unresolved) => Err(upvars_unresolved), - } + to_upvars_resolved_place_builder(self, tcx, typeck_results) } crate fn base(&self) -> PlaceBase { @@ -662,7 +668,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, len, - Rvalue::Len(slice.clone().into_place(self.tcx, self.typeck_results)), + Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)), ); // lt = idx < len self.cfg.push_assign( diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c7f16fd4e40..53c87d71e13 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -165,13 +165,42 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields)) } - ExprKind::Closure { - closure_id, - substs, - upvars, - movability, - fake_reads: opt_fake_reads, - } => { + ExprKind::Closure { closure_id, substs, upvars, movability, fake_reads } => { + // Convert the closure fake reads, if any, from `ExprRef` to mir `Place` + // and push the fake reads. + // This must come before creating the operands. This is required in case + // there is a fake read and a borrow of the same path, since otherwise the + // fake read might interfere with the borrow. Consider an example like this + // one: + // ``` + // let mut x = 0; + // let c = || { + // &mut x; // mutable borrow of `x` + // match x { _ => () } // fake read of `x` + // }; + // ``` + + // FIXME(RFC2229): Remove feature gate once diagnostics are improved + if this.tcx.features().capture_disjoint_fields { + for (thir_place, cause, hir_id) in fake_reads.into_iter() { + let place_builder = + unpack!(block = this.as_place_builder(block, thir_place)); + + if let Ok(place_builder_resolved) = + place_builder.try_upvars_resolved(this.tcx, this.typeck_results) + { + let mir_place = + place_builder_resolved.into_place(this.tcx, this.typeck_results); + this.cfg.push_fake_read( + block, + this.source_info(this.tcx.hir().span(hir_id)), + cause, + mir_place, + ); + } + } + } + // see (*) above let operands: Vec<_> = upvars .into_iter() @@ -210,21 +239,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } }) .collect(); - if let Some(fake_reads) = opt_fake_reads { - for (thir_place, cause) in fake_reads.into_iter() { - let place_builder = - unpack!(block = this.as_place_builder(block, thir_place)); - - if let Ok(place_builder_resolved) = - place_builder.clone().try_upvars_resolved(this.tcx, this.typeck_results) - { - let mir_place = place_builder_resolved - .clone() - .into_place(this.tcx, this.typeck_results); - this.cfg.push_fake_read(block, source_info, cause, mir_place); - } - } - } let result = match substs { UpvarSubsts::Generator(substs) => { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 59b3fd86478..6e8b25c9162 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -146,8 +146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results) { - let scrutinee_place = - scrutinee_builder.clone().into_place(self.tcx, self.typeck_results); + let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results); self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place); } @@ -245,7 +244,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arm_source_info = self.source_info(arm.span); let arm_scope = (arm.scope, arm_source_info); self.in_scope(arm_scope, arm.lint_level, |this| { - let body = arm.body.clone(); + let body = arm.body; + + // `try_upvars_resolved` may fail if it is unable to resolve the given + // `PlaceBuilder` inside a closure. In this case, we don't want to include + // a scrutinee place. `scrutinee_place_builder` will fail to be resolved + // if the only match arm is a wildcard (`_`). + // Example: + // ``` + // let foo = (0, 1); + // let c = || { + // match foo { _ => () }; + // }; + // ``` let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None; let scrutinee_place: Place<'tcx>; if let Ok(scrutinee_builder) = scrutinee_place_builder @@ -496,6 +507,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, )))) = self.local_decls[local].local_info { + // `try_upvars_resolved` may fail if it is unable to resolve the given + // `PlaceBuilder` inside a closure. In this case, we don't want to include + // a scrutinee place. `scrutinee_place_builder` will fail for destructured + // assignments. This is because a closure only captures the precise places + // that it will read and as a result a closure may not capture the entire + // tuple/struct and rather have individual places that will be read in the + // final MIR. + // Example: + // ``` + // let foo = (0, 1); + // let c = || { + // let (v1, v2) = foo; + // }; + // ``` if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results) { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 02f1998f496..b13a0ef8201 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -160,7 +160,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Ok(test_place_builder) = place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results) { - place = test_place_builder.clone().into_place(self.tcx, self.typeck_results); + place = test_place_builder.into_place(self.tcx, self.typeck_results); } else { return; } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index dee69793f2a..2f58f2975b1 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -454,20 +454,20 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { .map(|(captured_place, ty)| self.capture_upvar(expr, captured_place, ty)), ); + // Convert the closure fake reads, if any, from hir `Place` to ExprRef let fake_reads = match self.typeck_results().closure_fake_reads.get(&def_id) { - Some(vals) => Some( - vals.iter() - .map(|(place, cause)| { - ( - self.arena.alloc( - self.convert_captured_hir_place(expr, place.clone()), - ), - *cause, - ) - }) - .collect(), - ), - None => None, + Some(fake_reads) => fake_reads + .iter() + .map(|(place, cause, hir_id)| { + ( + self.arena + .alloc(self.convert_captured_hir_place(expr, place.clone())), + *cause, + *hir_id, + ) + }) + .collect(), + None => Vec::new(), }; ExprKind::Closure { diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index a6ec3b7bdd2..71d3093854d 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -281,7 +281,7 @@ pub enum ExprKind<'thir, 'tcx> { substs: UpvarSubsts<'tcx>, upvars: &'thir [Expr<'thir, 'tcx>], movability: Option, - fake_reads: Option, FakeReadCause)>>, + fake_reads: Vec<(&'thir mut Expr<'thir, 'tcx>, FakeReadCause, hir::HirId)>, }, Literal { literal: &'tcx Const<'tcx>, diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 9a43eaa3f5d..e79349796d2 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -248,8 +248,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter()); self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type); - let fake_reads = - delegate.fake_reads.into_iter().map(|(place, cause)| (place, cause)).collect(); + let fake_reads = delegate + .fake_reads + .into_iter() + .map(|(place, cause, hir_id)| (place, cause, hir_id)) + .collect(); self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads); // If we are also inferred the closure kind here, @@ -1154,7 +1157,7 @@ struct InferBorrowKind<'a, 'tcx> { /// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow } /// ``` capture_information: InferredCaptureInformation<'tcx>, - fake_reads: Vec<(Place<'tcx>, FakeReadCause)>, + fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>, } impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { @@ -1416,9 +1419,9 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { - fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause) { + fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) { if let PlaceBase::Upvar(_) = place.base { - self.fake_reads.push((place, cause)); + self.fake_reads.push((place, cause, diag_expr_id)); } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 1be629ce9dc..b88a96de698 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -371,18 +371,18 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_fake_reads_map(&mut self) { let mut resolved_closure_fake_reads: FxHashMap< DefId, - Vec<(HirPlace<'tcx>, FakeReadCause)>, + Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>, > = Default::default(); for (closure_def_id, fake_reads) in self.fcx.typeck_results.borrow().closure_fake_reads.iter() { - let mut resolved_fake_reads = Vec::<(HirPlace<'tcx>, FakeReadCause)>::new(); - for (place, cause) in fake_reads.iter() { + let mut resolved_fake_reads = Vec::<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>::new(); + for (place, cause, hir_id) in fake_reads.iter() { let locatable = self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local()); let resolved_fake_read = self.resolve(place.clone(), &locatable); - resolved_fake_reads.push((resolved_fake_read, *cause)); + resolved_fake_reads.push((resolved_fake_read, *cause, *hir_id)); } resolved_closure_fake_reads.insert(*closure_def_id, resolved_fake_reads); } diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 0172f993c26..dced4aac049 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -7,11 +7,11 @@ pub use self::ConsumeMode::*; // Export these here so that Clippy can use them. pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; +use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::PatKind; -//use rustc_hir::QPath; use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::ProjectionKind; @@ -54,7 +54,8 @@ pub trait Delegate<'tcx> { // `diag_expr_id` is the id used for diagnostics (see `consume` for more details). fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId); - fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause); + // The `place` should be a fake read because of specified `cause`. + fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId); } #[derive(Copy, Clone, PartialEq, Debug)] @@ -241,20 +242,33 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self; let mut needs_to_be_read = false; for arm in arms.iter() { - return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |_place, pat| { + return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |place, pat| { match &pat.kind { - PatKind::Binding(_, _, _, opt_sub_pat) => { + PatKind::Binding(.., opt_sub_pat) => { // If the opt_sub_pat is None, than the binding does not count as - // a wildcard for the purpose of borrowing discr - if let None = opt_sub_pat { + // a wildcard for the purpose of borrowing discr. + if opt_sub_pat.is_none() { needs_to_be_read = true; } } - PatKind::TupleStruct(_, _, _) - | PatKind::Struct(_, _, _) - | PatKind::Lit(_) => { - // If the PatKind is a TupleStruct, Struct, or Lit then we want - // to borrow discr + PatKind::TupleStruct(..) + | PatKind::Path(..) + | PatKind::Struct(..) + | PatKind::Tuple(..) => { + // If the PatKind is a TupleStruct, Struct or Tuple then we want to check + // whether the Variant is a MultiVariant or a SingleVariant. We only want + // to borrow discr if it is a MultiVariant. + // If it is a SingleVariant and creates a binding we will handle that when + // this callback gets called again. + if let ty::Adt(def, _) = place.place.base_ty.kind() { + if def.variants.len() > 1 { + needs_to_be_read = true; + } + } + } + PatKind::Lit(_) => { + // If the PatKind is a Lit then we want + // to borrow discr. needs_to_be_read = true; } _ => {} @@ -264,6 +278,16 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { if needs_to_be_read { self.borrow_expr(&discr, ty::ImmBorrow); + } else { + self.delegate.fake_read( + discr_place.place.clone(), + FakeReadCause::ForMatchedPlace, + discr_place.hir_id, + ); + + // We always want to walk the discriminant. We want to make sure, for instance, + // that the discriminant has been initialized. + self.walk_expr(&discr); } // treatment of the discriminant is handled while walking the arms. @@ -553,7 +577,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) { - self.delegate.fake_read(discr_place.place.clone(), FakeReadCause::ForMatchedPlace); + self.delegate.fake_read( + discr_place.place.clone(), + FakeReadCause::ForMatchedPlace, + discr_place.hir_id, + ); self.walk_pat(discr_place, &arm.pat); if let Some(hir::Guard::If(ref e)) = arm.guard { @@ -566,7 +594,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or /// let binding, and *not* a match arm or nested pat.) fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { - self.delegate.fake_read(discr_place.place.clone(), FakeReadCause::ForLet); + self.delegate.fake_read( + discr_place.place.clone(), + FakeReadCause::ForLet, + discr_place.hir_id, + ); self.walk_pat(discr_place, pat); } @@ -634,6 +666,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing /// closure as the DefId. fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) { + fn upvar_is_local_variable( + upvars: Option<&'tcx FxIndexMap>, + upvar_id: &hir::HirId, + body_owner_is_closure: bool, + ) -> bool { + upvars.map(|upvars| !upvars.contains_key(upvar_id)).unwrap_or(body_owner_is_closure) + } + debug!("walk_captures({:?})", closure_expr); let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id(); @@ -645,16 +685,32 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ty::Closure(..) | ty::Generator(..) ); + // If we have a nested closure, we want to include the fake reads present in the nested closure. if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) { - for (fake_read, cause) in fake_reads.iter() { + for (fake_read, cause, hir_id) in fake_reads.iter() { match fake_read.base { PlaceBase::Upvar(upvar_id) => { - if upvars.map_or(body_owner_is_closure, |upvars| { - !upvars.contains_key(&upvar_id.var_path.hir_id) - }) { + if upvar_is_local_variable( + upvars, + &upvar_id.var_path.hir_id, + body_owner_is_closure, + ) { // The nested closure might be fake reading the current (enclosing) closure's local variables. - // We check if the root variable is ever mentioned within the enclosing closure, if not - // then for the current body (if it's a closure) these do not require fake_read, we will ignore them. + // The only places we want to fake read before creating the parent closure are the ones that + // are not local to it/ defined by it. + // + // ```rust,ignore(cannot-test-this-because-pseduo-code) + // let v1 = (0, 1); + // let c = || { // fake reads: v1 + // let v2 = (0, 1); + // let e = || { // fake reads: v1, v2 + // let (_, t1) = v1; + // let (_, t2) = v2; + // } + // } + // ``` + // This check is performed when visiting the body of the outermost closure (`c`) and ensures + // that we don't add a fake read of v2 in c. continue; } } @@ -665,7 +721,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ); } }; - self.delegate.fake_read(fake_read.clone(), *cause); + self.delegate.fake_read(fake_read.clone(), *cause, *hir_id); } } diff --git a/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.rs b/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.rs new file mode 100644 index 00000000000..609a11a578a --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.rs @@ -0,0 +1,84 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| `#[warn(incomplete_features)]` on by default +//~| see issue #53488 +#![feature(never_type)] + +// Should fake read the discriminant and throw an error +fn test1() { + let x: !; + let c1 = || match x { }; + //~^ ERROR: use of possibly-uninitialized variable: `x` +} + +// Should fake read the discriminant and throw an error +fn test2() { + let x: !; + let c2 = || match x { _ => () }; + //~^ ERROR: borrow of possibly-uninitialized variable: `x` +} + +// Testing single variant patterns +enum SingleVariant { + Points(u32) +} + +// Should fake read the discriminant and throw an error +fn test3() { + let variant: !; + let c = || { + //~^ ERROR: borrow of possibly-uninitialized variable: `variant` + match variant { + SingleVariant::Points(_) => {} + } + }; + c(); +} + +// Should fake read the discriminant and throw an error +fn test4() { + let variant: !; + let c = || { + //~^ ERROR: borrow of possibly-uninitialized variable: `variant` + match variant { + SingleVariant::Points(a) => { + println!("{:?}", a); + } + } + }; + c(); +} + +fn test5() { + let t: !; + let g: !; + + let a = || { + match g { }; + //~^ ERROR: use of possibly-uninitialized variable: `g` + let c = || { + match t { }; + //~^ ERROR: use of possibly-uninitialized variable: `t` + }; + + c(); + }; + +} + +// Should fake read the discriminant and throw an error +fn test6() { + let x: u8; + let c1 = || match x { }; + //~^ ERROR: use of possibly-uninitialized variable: `x` + //~| ERROR: non-exhaustive patterns: type `u8` is non-empty +} + +fn main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.stderr b/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.stderr new file mode 100644 index 00000000000..c225abb58b7 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/pattern-matching-should-fail.stderr @@ -0,0 +1,72 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/pattern-matching-should-fail.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0004]: non-exhaustive patterns: type `u8` is non-empty + --> $DIR/pattern-matching-should-fail.rs:72:23 + | +LL | let c1 = || match x { }; + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `u8` + +error[E0381]: use of possibly-uninitialized variable: `x` + --> $DIR/pattern-matching-should-fail.rs:10:23 + | +LL | let c1 = || match x { }; + | ^ use of possibly-uninitialized `x` + +error[E0381]: borrow of possibly-uninitialized variable: `x` + --> $DIR/pattern-matching-should-fail.rs:17:14 + | +LL | let c2 = || match x { _ => () }; + | ^^ - borrow occurs due to use in closure + | | + | use of possibly-uninitialized `x` + +error[E0381]: borrow of possibly-uninitialized variable: `variant` + --> $DIR/pattern-matching-should-fail.rs:29:13 + | +LL | let c = || { + | ^^ use of possibly-uninitialized `variant` +LL | +LL | match variant { + | ------- borrow occurs due to use in closure + +error[E0381]: borrow of possibly-uninitialized variable: `variant` + --> $DIR/pattern-matching-should-fail.rs:41:13 + | +LL | let c = || { + | ^^ use of possibly-uninitialized `variant` +LL | +LL | match variant { + | ------- borrow occurs due to use in closure + +error[E0381]: use of possibly-uninitialized variable: `g` + --> $DIR/pattern-matching-should-fail.rs:57:15 + | +LL | match g { }; + | ^ use of possibly-uninitialized `g` + +error[E0381]: use of possibly-uninitialized variable: `t` + --> $DIR/pattern-matching-should-fail.rs:60:19 + | +LL | match t { }; + | ^ use of possibly-uninitialized `t` + +error[E0381]: use of possibly-uninitialized variable: `x` + --> $DIR/pattern-matching-should-fail.rs:72:23 + | +LL | let c1 = || match x { }; + | ^ use of possibly-uninitialized `x` + +error: aborting due to 8 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0004, E0381. +For more information about an error, try `rustc --explain E0004`. diff --git a/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.rs b/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.rs new file mode 100644 index 00000000000..0a877dd366c --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.rs @@ -0,0 +1,139 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| NOTE: `#[warn(incomplete_features)]` on by default +//~| NOTE: see issue #53488 +#![feature(rustc_attrs)] + +// Should capture the discriminant since a variant of a multivariant enum is +// mentioned in the match arm; the discriminant is captured by the closure regardless +// of if it creates a binding +fn test_1_should_capture() { + let variant = Some(2229); + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + + || { + //~^ First Pass analysis includes: + //~| Min Capture analysis includes: + match variant { + //~^ NOTE: Capturing variant[] -> ImmBorrow + //~| NOTE: Min Capture variant[] -> ImmBorrow + Some(_) => {} + _ => {} + } + }; + c(); +} + +// Should not capture the discriminant since only a wildcard is mentioned in the +// match arm +fn test_2_should_not_capture() { + let variant = Some(2229); + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ First Pass analysis includes: + match variant { + _ => {} + } + }; + c(); +} + +// Testing single variant patterns +enum SingleVariant { + Points(u32) +} + +// Should not capture the discriminant since the single variant mentioned +// in the match arm does not trigger a binding +fn test_3_should_not_capture_single_variant() { + let variant = SingleVariant::Points(1); + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ First Pass analysis includes: + match variant { + SingleVariant::Points(_) => {} + } + }; + c(); +} + +// Should not capture the discriminant since the single variant mentioned +// in the match arm does not trigger a binding +fn test_6_should_capture_single_variant() { + let variant = SingleVariant::Points(1); + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ First Pass analysis includes: + //~| Min Capture analysis includes: + match variant { + //~^ NOTE: Capturing variant[] -> ImmBorrow + //~| NOTE: Capturing variant[(0, 0)] -> ImmBorrow + //~| NOTE: Min Capture variant[] -> ImmBorrow + SingleVariant::Points(a) => { + println!("{:?}", a); + } + } + }; + c(); +} + +// Should not capture the discriminant since only wildcards are mentioned in the +// match arm +fn test_4_should_not_capture_array() { + let array: [i32; 3] = [0; 3]; + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ First Pass analysis includes: + match array { + [_,_,_] => {} + } + }; + c(); +} + +// Testing MultiVariant patterns +enum MVariant { + A, + B, + C, +} + +// Should capture the discriminant since a variant of the multi variant enum is +// mentioned in the match arm; the discriminant is captured by the closure +// regardless of if it creates a binding +fn test_5_should_capture_multi_variant() { + let variant = MVariant::A; + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ First Pass analysis includes: + //~| Min Capture analysis includes: + match variant { + //~^ NOTE: Capturing variant[] -> ImmBorrow + //~| NOTE: Min Capture variant[] -> ImmBorrow + MVariant::A => {} + _ => {} + } + }; + c(); +} + +fn main() { + test_1_should_capture(); + test_2_should_not_capture(); + test_3_should_not_capture_single_variant(); + test_6_should_capture_single_variant(); + test_4_should_not_capture_array(); + test_5_should_capture_multi_variant(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.stderr b/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.stderr new file mode 100644 index 00000000000..ad3e96a5753 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/patterns-capture-analysis.stderr @@ -0,0 +1,212 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/patterns-capture-analysis.rs:12:14 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/patterns-capture-analysis.rs:33:14 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/patterns-capture-analysis.rs:54:14 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/patterns-capture-analysis.rs:70:14 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/patterns-capture-analysis.rs:92:14 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/patterns-capture-analysis.rs:116:14 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/patterns-capture-analysis.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error: First Pass analysis includes: + --> $DIR/patterns-capture-analysis.rs:16:5 + | +LL | / || { +LL | | +LL | | +LL | | match variant { +... | +LL | | } +LL | | }; + | |_____^ + | +note: Capturing variant[] -> ImmBorrow + --> $DIR/patterns-capture-analysis.rs:19:15 + | +LL | match variant { + | ^^^^^^^ + +error: Min Capture analysis includes: + --> $DIR/patterns-capture-analysis.rs:16:5 + | +LL | / || { +LL | | +LL | | +LL | | match variant { +... | +LL | | } +LL | | }; + | |_____^ + | +note: Min Capture variant[] -> ImmBorrow + --> $DIR/patterns-capture-analysis.rs:19:15 + | +LL | match variant { + | ^^^^^^^ + +error: First Pass analysis includes: + --> $DIR/patterns-capture-analysis.rs:36:5 + | +LL | / || { +LL | | +LL | | match variant { +LL | | _ => {} +LL | | } +LL | | }; + | |_____^ + +error: First Pass analysis includes: + --> $DIR/patterns-capture-analysis.rs:57:5 + | +LL | / || { +LL | | +LL | | match variant { +LL | | SingleVariant::Points(_) => {} +LL | | } +LL | | }; + | |_____^ + +error: First Pass analysis includes: + --> $DIR/patterns-capture-analysis.rs:73:5 + | +LL | / || { +LL | | +LL | | +LL | | match variant { +... | +LL | | } +LL | | }; + | |_____^ + | +note: Capturing variant[] -> ImmBorrow + --> $DIR/patterns-capture-analysis.rs:76:15 + | +LL | match variant { + | ^^^^^^^ +note: Capturing variant[(0, 0)] -> ImmBorrow + --> $DIR/patterns-capture-analysis.rs:76:15 + | +LL | match variant { + | ^^^^^^^ + +error: Min Capture analysis includes: + --> $DIR/patterns-capture-analysis.rs:73:5 + | +LL | / || { +LL | | +LL | | +LL | | match variant { +... | +LL | | } +LL | | }; + | |_____^ + | +note: Min Capture variant[] -> ImmBorrow + --> $DIR/patterns-capture-analysis.rs:76:15 + | +LL | match variant { + | ^^^^^^^ + +error: First Pass analysis includes: + --> $DIR/patterns-capture-analysis.rs:95:5 + | +LL | / || { +LL | | +LL | | match array { +LL | | [_,_,_] => {} +LL | | } +LL | | }; + | |_____^ + +error: First Pass analysis includes: + --> $DIR/patterns-capture-analysis.rs:119:5 + | +LL | / || { +LL | | +LL | | +LL | | match variant { +... | +LL | | } +LL | | }; + | |_____^ + | +note: Capturing variant[] -> ImmBorrow + --> $DIR/patterns-capture-analysis.rs:122:15 + | +LL | match variant { + | ^^^^^^^ + +error: Min Capture analysis includes: + --> $DIR/patterns-capture-analysis.rs:119:5 + | +LL | / || { +LL | | +LL | | +LL | | match variant { +... | +LL | | } +LL | | }; + | |_____^ + | +note: Min Capture variant[] -> ImmBorrow + --> $DIR/patterns-capture-analysis.rs:122:15 + | +LL | match variant { + | ^^^^^^^ + +error: aborting due to 15 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.rs similarity index 61% rename from src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.rs rename to src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.rs index 6b3835634c6..eaea0dbfb5e 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.rs @@ -3,20 +3,23 @@ //~^ WARNING: the feature `capture_disjoint_fields` is incomplete fn test1() { - let foo = [1, 2, 3]; + let foo : [Vec; 3] = ["String".into(), "String".into(), "String".into()]; let c = || { match foo { _ => () }; }; + drop(foo); + c(); } fn test2() { - let foo = Some([1, 2, 3]); + let foo : Option<[Vec; 3]> = Some(["String".into(), "String".into(), "String".into()]); let c = || { match foo { Some(_) => 1, _ => 2 }; }; + c(); } fn main() { diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.stderr similarity index 88% rename from src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.stderr rename to src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.stderr index 6f5b28aa6cf..2c17a189afb 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/no_capture_with_wildcard_match.stderr +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/capture_with_wildcard_match.stderr @@ -1,5 +1,5 @@ warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/no_capture_with_wildcard_match.rs:2:12 + --> $DIR/capture_with_wildcard_match.rs:2:12 | LL | #![feature(capture_disjoint_fields)] | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs index d91a28feae5..3ad083a92d5 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.rs @@ -4,7 +4,6 @@ #![warn(unused)] fn main() { - let _z = 9; let t = (String::from("Hello"), String::from("World")); let g = (String::from("Mr"), String::from("Goose")); diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr index d88c16567b7..c4abf934123 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure-pattern-closure-within-closure.stderr @@ -8,7 +8,7 @@ LL | #![feature(capture_disjoint_fields)] = note: see issue #53488 for more information warning: unused variable: `t2` - --> $DIR/destructure-pattern-closure-within-closure.rs:15:21 + --> $DIR/destructure-pattern-closure-within-closure.rs:14:21 | LL | let (_, t2) = t; | ^^ help: if this is intentional, prefix it with an underscore: `_t2` @@ -21,7 +21,7 @@ LL | #![warn(unused)] = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` warning: unused variable: `g2` - --> $DIR/destructure-pattern-closure-within-closure.rs:12:17 + --> $DIR/destructure-pattern-closure-within-closure.rs:11:17 | LL | let (_, g2) = g; | ^^ help: if this is intentional, prefix it with an underscore: `_g2` diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs index 7d2c573dddd..65527648b2c 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.rs @@ -80,7 +80,6 @@ fn test7() { }; } -// [FIXME] RFC2229 Add an explanation for test fn test8() { let x = 0; //~^ WARN unused variable: `x` @@ -90,10 +89,10 @@ fn test8() { let c = || { let _ = x; - let Point { x, y } = p; // 1 + let Point { x, y } = p; //~^ WARN unused variable: `x` println!("{}", y); - let (_, _) = tup; // 2 + let (_, _) = tup; }; c(); diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr index b92bf089e9e..fcfe9ee95f1 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/destructure_patterns.stderr @@ -45,19 +45,19 @@ LL | let t = (String::from("Hello"), String::from("World")); | ^ help: if this is intentional, prefix it with an underscore: `_t` warning: unused variable: `x` - --> $DIR/destructure_patterns.rs:93:21 + --> $DIR/destructure_patterns.rs:92:21 | -LL | let Point { x, y } = p; // 1 +LL | let Point { x, y } = p; | ^ help: try ignoring the field: `x: _` warning: unused variable: `x` - --> $DIR/destructure_patterns.rs:85:9 + --> $DIR/destructure_patterns.rs:84:9 | LL | let x = 0; | ^ help: if this is intentional, prefix it with an underscore: `_x` warning: unused variable: `tup` - --> $DIR/destructure_patterns.rs:87:9 + --> $DIR/destructure_patterns.rs:86:9 | LL | let tup = (1, 2); | ^^^ help: if this is intentional, prefix it with an underscore: `_tup` diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs new file mode 100644 index 00000000000..dae50854d82 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs @@ -0,0 +1,12 @@ +//check-pass +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +#![feature(rustc_attrs)] + +fn main() { + let mut x = 1; + let c = || { + drop(&mut x); + match x { _ => () } + }; +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.stderr similarity index 89% rename from src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.stderr rename to src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.stderr index 66171f35763..7f811875d13 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.stderr +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.stderr @@ -1,5 +1,5 @@ warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/struct_update_syntax.rs:2:12 + --> $DIR/drop_then_use_fake_reads.rs:2:12 | LL | #![feature(capture_disjoint_fields)] | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs index 97b56e7c4be..9c086fe4bdf 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs @@ -21,4 +21,11 @@ fn main() { assert!(matches!(result, Ok(None))); } + { + let mut it = map.drain_filter(|_, _| true); + catch_unwind(AssertUnwindSafe(|| while let Some(_) = it.next() {})).unwrap_err(); + let result = catch_unwind(AssertUnwindSafe(|| it.next())); + assert!(matches!(result, Ok(None))); + } + } diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs index 2f13590a2bd..d260a448926 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/struct-pattern-matching-with-methods.rs @@ -11,6 +11,7 @@ enum PointType { ThreeD{ x: u32, y: u32, z: u32 } } +// Testing struct patterns struct Points { points: Vec, } diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.rs deleted file mode 100644 index 34710e69b96..00000000000 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/struct_update_syntax.rs +++ /dev/null @@ -1,25 +0,0 @@ -//check-pass -#![feature(capture_disjoint_fields)] -//~^ WARNING: the feature `capture_disjoint_fields` is incomplete -#![feature(rustc_attrs)] - -struct S { - a: String, - b: String, -} - -fn main() { - let s = S { - a: String::new(), - b: String::new(), - }; - - let c = || { - let s2 = S { - a: format!("New a"), - ..s - }; - }; - - c(); -} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs index 0948039287b..b3bee79254e 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/tuple-struct-pattern-matching-with-methods.rs @@ -8,6 +8,7 @@ enum PointType { ThreeD(u32, u32, u32) } +// Testing tuple struct patterns struct Points { points: Vec, } diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs new file mode 100644 index 00000000000..0e6da8f4f18 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.rs @@ -0,0 +1,12 @@ +//check-pass +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +#![feature(rustc_attrs)] + +fn main() { + let mut x = 0; + let c = || { + &mut x; // mutable borrow of `x` + match x { _ => () } // fake read of `x` + }; +} diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.stderr b/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.stderr new file mode 100644 index 00000000000..7d16d77bf73 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/use_of_mutable_borrow_and_fake_reads.stderr @@ -0,0 +1,11 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/use_of_mutable_borrow_and_fake_reads.rs:2:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index a3469ee2114..285c203f382 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -189,19 +189,18 @@ LL | drop(_x3); error[E0382]: use of moved value: `tup` --> $DIR/borrowck-move-ref-pattern.rs:43:14 | -LL | let mut tup = (U, U, U); - | ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait -LL | let c1 = || { - | -- value moved into closure here -LL | let (ref _x0, _x1, _) = tup; - | --- variable moved due to use in closure -LL | }; -LL | let c2 = || { - | ______________^ -LL | | -LL | | let (ref mut _x0, _, _x2) = tup; -LL | | }; - | |_____^ value used here after move +LL | let mut tup = (U, U, U); + | ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait +LL | let c1 = || { + | -- value moved into closure here +LL | let (ref _x0, _x1, _) = tup; + | --- variable moved due to use in closure +LL | }; +LL | let c2 = || { + | ^^ value used here after move +LL | +LL | let (ref mut _x0, _, _x2) = tup; + | --- use occurs due to use in closure error: aborting due to 18 previous errors diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 6994e9f7d2e..97216757547 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } - fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause) { } + fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) { } } impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index d5a9d5e4e13..d439577f9c3 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -335,5 +335,5 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt { fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} - fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause) { } + fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) { } } diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 8aa8781f6be..0b1ab6b7ea1 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -79,7 +79,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { self.update(&cmt) } - fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause) { } + fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _:HirId) { } } pub struct ParamBindingIdCollector {