X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustc_mir%2Fborrow_check%2Fmod.rs;h=f4071e02f558087e9c2a506918a529cb8118c291;hb=6f637da50c56a22f745fd056691da8c86824cd9b;hp=f96b9b8082fa799d2aee174bd92565d7b2cf0c1b;hpb=bfc3b20663e1abfff0499332f9168f60c3269c33;p=rust.git diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index f96b9b8082f..f4071e02f55 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -316,7 +316,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( } let span = local_decl.source_info.span; - let mut_span = tcx.sess.codemap().span_until_non_whitespace(span); + let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); let mut err = tcx.struct_span_lint_node( UNUSED_MUT, @@ -798,12 +798,6 @@ enum LocalMutationIsAllowed { No, } -struct AccessErrorsReported { - mutability_error: bool, - #[allow(dead_code)] - conflict_error: bool, -} - #[derive(Copy, Clone)] enum InitializationRequiringAction { Update, @@ -941,14 +935,14 @@ fn visit_terminator_drop( // individual fields instead. This way if `foo` has a // destructor but `bar` does not, we will only check for // borrows of `x.foo` and not `x.bar`. See #47703. - ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { + ty::Adt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { def.all_fields() .map(|field| field.ty(gcx, substs)) .enumerate() .for_each(|field| drop_field(self, field)); } // Same as above, but for tuples. - ty::TyTuple(tys) => { + ty::Tuple(tys) => { tys.iter() .cloned() .enumerate() @@ -956,7 +950,7 @@ fn visit_terminator_drop( } // Closures also have disjoint fields, but they are only // directly accessed in the body of the closure. - ty::TyClosure(def, substs) + ty::Closure(def, substs) if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() => { @@ -967,7 +961,7 @@ fn visit_terminator_drop( } // Generators also have disjoint fields, but they are only // directly accessed in the body of the generator. - ty::TyGenerator(def, substs, _) + ty::Generator(def, substs, _) if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() => { @@ -984,7 +978,7 @@ fn visit_terminator_drop( // the base case below, we would have a Deep Write due to // the box being `needs_drop`, and that Deep Write would // touch `&mut` data in the box. - ty::TyAdt(def, _) if def.is_box() => { + ty::Adt(def, _) if def.is_box() => { // When/if we add a `&own T` type, this action would // be like running the destructor of the `&own T`. // (And the owner of backing storage referenced by the @@ -1072,7 +1066,7 @@ fn access_place( kind: (ShallowOrDeep, ReadOrWrite), is_local_mutation_allowed: LocalMutationIsAllowed, flow_state: &Flows<'cx, 'gcx, 'tcx>, - ) -> AccessErrorsReported { + ) { let (sd, rw) = kind; if let Activation(_, borrow_index) = rw { @@ -1082,14 +1076,14 @@ fn access_place( place: {:?} borrow_index: {:?}", place_span.0, borrow_index ); - return AccessErrorsReported { - mutability_error: false, - conflict_error: true, - }; + return; } } - if self + // Check is_empty() first because it's the common case, and doing that + // way we avoid the clone() call. + if !self.access_place_error_reported.is_empty() && + self .access_place_error_reported .contains(&(place_span.0.clone(), place_span.1)) { @@ -1097,10 +1091,7 @@ fn access_place( "access_place: suppressing error place_span=`{:?}` kind=`{:?}`", place_span, kind ); - return AccessErrorsReported { - mutability_error: false, - conflict_error: true, - }; + return; } let mutability_error = @@ -1122,11 +1113,6 @@ fn access_place( self.access_place_error_reported .insert((place_span.0.clone(), place_span.1)); } - - AccessErrorsReported { - mutability_error, - conflict_error, - } } fn check_access_for_conflict( @@ -1275,23 +1261,30 @@ fn mutate_place( } } - let errors_reported = self.access_place( + // Special case: you can assign a immutable local variable + // (e.g., `x = ...`) so long as it has never been initialized + // before (at this point in the flow). + if let &Place::Local(local) = place_span.0 { + if let Mutability::Not = self.mir.local_decls[local].mutability { + // check for reassignments to immutable local variables + self.check_if_reassignment_to_immutable_state( + context, + local, + place_span, + flow_state, + ); + return; + } + } + + // Otherwise, use the normal access permission rules. + self.access_place( context, place_span, (kind, Write(WriteKind::Mutate)), - // We want immutable upvars to cause an "assignment to immutable var" - // error, not an "reassignment of immutable var" error, because the - // latter can't find a good previous assignment span. - // - // There's probably a better way to do this. - LocalMutationIsAllowed::ExceptUpvars, + LocalMutationIsAllowed::No, flow_state, ); - - if !errors_reported.mutability_error { - // check for reassignments to immutable local variables - self.check_if_reassignment_to_immutable_state(context, place_span, flow_state); - } } fn consume_rvalue( @@ -1519,7 +1512,7 @@ fn check_for_invalidation_at_exit( debug!("check_for_invalidation_at_exit({:?}): INVALID", place); // FIXME: should be talking about the region lifetime instead // of just a span here. - let span = self.tcx.sess.codemap().end_point(span); + let span = self.tcx.sess.source_map().end_point(span); self.report_borrowed_value_does_not_live_long_enough( context, borrow, @@ -1590,27 +1583,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn check_if_reassignment_to_immutable_state( &mut self, context: Context, - (place, span): (&Place<'tcx>, Span), + local: Local, + place_span: (&Place<'tcx>, Span), flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { - debug!("check_if_reassignment_to_immutable_state({:?})", place); - // determine if this path has a non-mut owner (and thus needs checking). - let err_place = match self.is_mutable(place, LocalMutationIsAllowed::No) { - Ok(..) => return, - Err(place) => place, - }; - debug!( - "check_if_reassignment_to_immutable_state({:?}) - is an imm local", - place - ); - - for i in flow_state.ever_inits.iter_incoming() { - let init = self.move_data.inits[i]; - let init_place = &self.move_data.move_paths[init.path].place; - if places_conflict::places_conflict(self.tcx, self.mir, &init_place, place, Deep) { - self.report_illegal_reassignment(context, (place, span), init.span, err_place); - break; - } + debug!("check_if_reassignment_to_immutable_state({:?})", local); + + // Check if any of the initializiations of `local` have happened yet: + let mpi = self.move_data.rev_lookup.find_local(local); + let init_indices = &self.move_data.init_path_map[mpi]; + let first_init_index = init_indices.iter().find(|ii| flow_state.ever_inits.contains(ii)); + if let Some(&init_index) = first_init_index { + // And, if so, report an error. + let init = &self.move_data.inits[init_index]; + self.report_illegal_reassignment(context, place_span, init.span, place_span.0); } } @@ -1832,7 +1818,7 @@ fn check_if_assigned_path_is_moved( // be already initialized let tcx = self.tcx; match base.ty(self.mir, tcx).to_ty(tcx).sty { - ty::TyAdt(def, _) if def.has_dtor(tcx) => { + ty::Adt(def, _) if def.has_dtor(tcx) => { // FIXME: analogous code in // check_loans.rs first maps @@ -2076,7 +2062,7 @@ fn is_mutable<'d>( // Check the kind of deref to decide match base_ty.sty { - ty::TyRef(_, _, mutbl) => { + ty::Ref(_, _, mutbl) => { match mutbl { // Shared borrowed data is never mutable hir::MutImmutable => Err(place), @@ -2100,7 +2086,7 @@ fn is_mutable<'d>( } } } - ty::TyRawPtr(tnm) => { + ty::RawPtr(tnm) => { match tnm.mutbl { // `*const` raw pointers are not mutable hir::MutImmutable => return Err(place),