提交 a9cb25b2 编写于 作者: P Paul Daniel Faria 提交者: Niko Matsakis

inform constraint generation using maybe-init

In particular, if we see a variable is DROP-LIVE, but it is not
MAYBE-INIT, then we can ignore the drop. This leavess attempt to use
more complex refinements of the idea (e.g., for subpaths or subfields)
to future work.
上级 08c8d7e9
......@@ -18,7 +18,6 @@
use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Local, Location, Place};
use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
use transform::nll;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_set::{self, IdxSetBuf};
......@@ -39,6 +38,7 @@
use self::MutateMode::{JustWrite, WriteAndRead};
pub(crate) mod nll;
pub fn provide(providers: &mut Providers) {
*providers = Providers {
......@@ -77,7 +77,21 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
.as_local_node_id(def_id)
.expect("do_mir_borrowck: non-local DefId");
let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx) {
// Make our own copy of the MIR. This copy will be modified (in place) to
// contain non-lexical lifetimes. It will have a lifetime tied
// to the inference context.
let mut mir: Mir<'tcx> = input_mir.clone();
let free_regions = if !tcx.sess.opts.debugging_opts.nll {
None
} else {
let mir = &mut mir;
// Replace all regions with fresh inference variables.
Some(nll::replace_regions_in_mir(infcx, def_id, mir))
};
let mir = &mir;
let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) {
Ok(move_data) => move_data,
Err((move_data, move_errors)) => {
for move_error in move_errors {
......@@ -110,34 +124,12 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
}
};
// Make our own copy of the MIR. This copy will be modified (in place) to
// contain non-lexical lifetimes. It will have a lifetime tied
// to the inference context.
let mut mir: Mir<'tcx> = input_mir.clone();
let mir = &mut mir;
// If we are in non-lexical mode, compute the non-lexical lifetimes.
let opt_regioncx = if !tcx.sess.opts.debugging_opts.nll {
None
} else {
Some(nll::compute_regions(infcx, def_id, param_env, mir))
};
let mdpe = MoveDataParamEnv {
move_data: move_data,
param_env: param_env,
};
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
let flow_borrows = do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
Borrows::new(tcx, mir, opt_regioncx.as_ref()),
|bd, i| bd.location(i),
);
let flow_inits = do_dataflow(
let mut flow_inits = FlowInProgress::new(do_dataflow(
tcx,
mir,
id,
......@@ -145,8 +137,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
&dead_unwinds,
MaybeInitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i],
);
let flow_uninits = do_dataflow(
));
let flow_uninits = FlowInProgress::new(do_dataflow(
tcx,
mir,
id,
......@@ -154,8 +146,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
&dead_unwinds,
MaybeUninitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().move_paths[i],
);
let flow_move_outs = do_dataflow(
));
let flow_move_outs = FlowInProgress::new(do_dataflow(
tcx,
mir,
id,
......@@ -163,8 +155,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
&dead_unwinds,
MovingOutStatements::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().moves[i],
);
let flow_ever_inits = do_dataflow(
));
let flow_ever_inits = FlowInProgress::new(do_dataflow(
tcx,
mir,
id,
......@@ -172,7 +164,24 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
&dead_unwinds,
EverInitializedLvals::new(tcx, mir, &mdpe),
|bd, i| &bd.move_data().inits[i],
);
));
// If we are in non-lexical mode, compute the non-lexical lifetimes.
let opt_regioncx = if let Some(free_regions) = free_regions {
Some(nll::compute_regions(
infcx,
def_id,
free_regions,
mir,
param_env,
&mut flow_inits,
&mdpe.move_data,
))
} else {
assert!(!tcx.sess.opts.debugging_opts.nll);
None
};
let flow_inits = flow_inits; // remove mut
let mut mbcx = MirBorrowckCtxt {
tcx: tcx,
......@@ -183,6 +192,16 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
storage_dead_or_drop_error_reported: FxHashSet(),
};
let flow_borrows = FlowInProgress::new(do_dataflow(
tcx,
mir,
id,
&attributes,
&dead_unwinds,
Borrows::new(tcx, mir, opt_regioncx),
|bd, i| bd.location(i),
));
let mut state = InProgress::new(
flow_borrows,
flow_inits,
......@@ -2318,19 +2337,19 @@ fn new(self, loc: Location) -> Context {
}
impl<'b, 'gcx, 'tcx> InProgress<'b, 'gcx, 'tcx> {
pub(super) fn new(
borrows: DataflowResults<Borrows<'b, 'gcx, 'tcx>>,
inits: DataflowResults<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
uninits: DataflowResults<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
move_out: DataflowResults<MovingOutStatements<'b, 'gcx, 'tcx>>,
ever_inits: DataflowResults<EverInitializedLvals<'b, 'gcx, 'tcx>>,
fn new(
borrows: FlowInProgress<Borrows<'b, 'gcx, 'tcx>>,
inits: FlowInProgress<MaybeInitializedLvals<'b, 'gcx, 'tcx>>,
uninits: FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>>,
move_outs: FlowInProgress<MovingOutStatements<'b, 'gcx, 'tcx>>,
ever_inits: FlowInProgress<EverInitializedLvals<'b, 'gcx, 'tcx>>,
) -> Self {
InProgress {
borrows: FlowInProgress::new(borrows),
inits: FlowInProgress::new(inits),
uninits: FlowInProgress::new(uninits),
move_outs: FlowInProgress::new(move_out),
ever_inits: FlowInProgress::new(ever_inits),
borrows,
inits,
uninits,
move_outs,
ever_inits,
}
}
......@@ -2436,8 +2455,11 @@ fn summary(&self) -> String {
}
}
impl<'b, 'gcx, 'tcx> FlowInProgress<MaybeUninitializedLvals<'b, 'gcx, 'tcx>> {
fn has_any_child_of(&self, mpi: MovePathIndex) -> Option<MovePathIndex> {
impl<'tcx, T> FlowInProgress<T>
where
T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
{
fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
let move_data = self.base_results.operator().move_data();
let mut todo = vec![mpi];
......
......@@ -9,7 +9,7 @@
// except according to those terms.
use rustc::hir;
use rustc::mir::{Location, Place, Mir, Rvalue};
use rustc::mir::{Local, Location, Place, Mir, Rvalue};
use rustc::mir::visit::Visitor;
use rustc::mir::Place::Projection;
use rustc::mir::{PlaceProjection, ProjectionElem};
......@@ -20,17 +20,22 @@
use rustc::util::common::ErrorReported;
use rustc_data_structures::fx::FxHashSet;
use syntax::codemap::DUMMY_SP;
use borrow_check::FlowInProgress;
use dataflow::MaybeInitializedLvals;
use dataflow::move_paths::{MoveData, HasMoveData};
use super::LivenessResults;
use super::ToRegionVid;
use super::region_infer::RegionInferenceContext;
pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
regioncx: &mut RegionInferenceContext<'tcx>,
mir: &Mir<'tcx>,
param_env: ty::ParamEnv<'tcx>,
liveness: &LivenessResults,
flow_inits: &mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) {
ConstraintGeneration {
infcx,
......@@ -38,18 +43,23 @@ pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
mir,
liveness,
param_env,
flow_inits,
move_data,
}.add_constraints();
}
struct ConstraintGeneration<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
regioncx: &'cx mut RegionInferenceContext<'tcx>,
mir: &'cx Mir<'tcx>,
liveness: &'cx LivenessResults,
/// 'cg = the duration of the constraint generation process itself.
struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> {
infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
regioncx: &'cg mut RegionInferenceContext<'tcx>,
mir: &'cg Mir<'tcx>,
liveness: &'cg LivenessResults,
param_env: ty::ParamEnv<'tcx>,
flow_inits: &'cg mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
move_data: &'cg MoveData<'tcx>,
}
impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
fn add_constraints(&mut self) {
self.add_liveness_constraints();
self.add_borrow_constraints();
......@@ -73,14 +83,51 @@ fn add_liveness_constraints(&mut self) {
}
});
self.liveness
.drop
.simulate_block(self.mir, bb, |location, live_locals| {
for live_local in live_locals.iter() {
let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
self.liveness.drop.simulate_block(self.mir, bb, |location, live_locals| {
all_live_locals.push((location, live_locals.iter().collect()));
});
debug!("add_liveness_constraints: all_live_locals={:#?}", all_live_locals);
let terminator_index = self.mir.basic_blocks()[bb].statements.len();
self.flow_inits.reset_to_entry_of(bb);
while let Some((location, live_locals)) = all_live_locals.pop() {
for live_local in live_locals {
debug!("add_liveness_constraints: location={:?} live_local={:?}", location,
live_local);
self.flow_inits.each_state_bit(|mpi_init| {
debug!("add_liveness_constraints: location={:?} initialized={:?}",
location,
&self.flow_inits
.base_results
.operator()
.move_data()
.move_paths[mpi_init]);
});
let mpi = self.move_data.rev_lookup.find_local(live_local);
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
debug!("add_liveness_constraints: mpi={:?} has initialized child {:?}",
self.move_data.move_paths[mpi],
self.move_data.move_paths[initialized_child]);
let live_local_ty = self.mir.local_decls[live_local].ty;
self.add_drop_live_constraint(live_local_ty, location);
}
});
}
if location.statement_index == terminator_index {
debug!("add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
location);
self.flow_inits.reconstruct_terminator_effect(location);
} else {
debug!("add_liveness_constraints: reconstruct_statement_effect from {:#?}",
location);
self.flow_inits.reconstruct_statement_effect(location);
}
self.flow_inits.apply_local_effect();
}
}
}
......@@ -219,7 +266,7 @@ fn add_reborrow_constraint(
}
}
impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cx, 'gcx, 'tcx> {
impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
fn visit_rvalue(&mut self,
rvalue: &Rvalue<'tcx>,
location: Location) {
......
......@@ -17,6 +17,9 @@
use transform::MirSource;
use transform::type_check;
use util::liveness::{self, LivenessMode, LivenessResult, LocalSet};
use borrow_check::FlowInProgress;
use dataflow::MaybeInitializedLvals;
use dataflow::move_paths::MoveData;
use util as mir_util;
use self::mir_util::PassWhere;
......@@ -24,27 +27,43 @@
mod constraint_generation;
mod subtype_constraint_generation;
mod free_regions;
use self::free_regions::FreeRegions;
pub(crate) mod region_infer;
use self::region_infer::RegionInferenceContext;
mod renumber;
/// Computes the (non-lexical) regions from the input MIR.
///
/// This may result in errors being reported.
pub fn compute_regions<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
/// Rewrites the regions in the MIR to use NLL variables, also
/// scraping out the set of free regions (e.g., region parameters)
/// declared on the function. That set will need to be given to
/// `compute_regions`.
pub(in borrow_check) fn replace_regions_in_mir<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
def_id: DefId,
param_env: ty::ParamEnv<'gcx>,
mir: &mut Mir<'tcx>,
) -> RegionInferenceContext<'tcx> {
) -> FreeRegions<'tcx> {
// Compute named region information.
let free_regions = &free_regions::free_regions(infcx, def_id);
let free_regions = free_regions::free_regions(infcx, def_id);
// Replace all regions with fresh inference variables.
renumber::renumber_mir(infcx, free_regions, mir);
renumber::renumber_mir(infcx, &free_regions, mir);
free_regions
}
/// Computes the (non-lexical) regions from the input MIR.
///
/// This may result in errors being reported.
pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
def_id: DefId,
free_regions: FreeRegions<'tcx>,
mir: &Mir<'tcx>,
param_env: ty::ParamEnv<'gcx>,
flow_inits: &mut FlowInProgress<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) -> RegionInferenceContext<'tcx> {
// Run the MIR type-checker.
let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
let constraint_sets = &type_check::type_check(infcx, mir_node_id, param_env, mir);
......@@ -52,8 +71,8 @@ pub fn compute_regions<'a, 'gcx, 'tcx>(
// Create the region inference context, taking ownership of the region inference
// data that was contained in `infcx`.
let var_origins = infcx.take_region_var_origins();
let mut regioncx = RegionInferenceContext::new(var_origins, free_regions, mir);
subtype_constraint_generation::generate(&mut regioncx, free_regions, mir, constraint_sets);
let mut regioncx = RegionInferenceContext::new(var_origins, &free_regions, mir);
subtype_constraint_generation::generate(&mut regioncx, &free_regions, mir, constraint_sets);
// Compute what is live where.
let liveness = &LivenessResults {
......@@ -75,7 +94,15 @@ pub fn compute_regions<'a, 'gcx, 'tcx>(
};
// Generate non-subtyping constraints.
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir, param_env, liveness);
constraint_generation::generate_constraints(
infcx,
&mut regioncx,
&mir,
param_env,
liveness,
flow_inits,
move_data,
);
// Solve the region constraints.
regioncx.solve(infcx, &mir);
......
......@@ -21,8 +21,8 @@
use dataflow::{BitDenotation, BlockSets, DataflowOperator};
pub use dataflow::indexes::BorrowIndex;
use transform::nll::region_infer::RegionInferenceContext;
use transform::nll::ToRegionVid;
use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::ToRegionVid;
use syntax_pos::Span;
......@@ -38,7 +38,7 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
location_map: FxHashMap<Location, BorrowIndex>,
region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
region_span_map: FxHashMap<RegionKind, Span>,
nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>,
nonlexical_regioncx: Option<RegionInferenceContext<'tcx>>,
}
// temporarily allow some dead fields: `kind` and `region` will be
......@@ -69,7 +69,7 @@ fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
mir: &'a Mir<'tcx>,
nonlexical_regioncx: Option<&'a RegionInferenceContext<'tcx>>)
nonlexical_regioncx: Option<RegionInferenceContext<'tcx>>)
-> Self {
let mut visitor = GatherBorrows {
tcx,
......@@ -156,7 +156,7 @@ pub fn opt_region_end_span(&self, region: &Region) -> Option<Span> {
fn kill_loans_out_of_scope_at_location(&self,
sets: &mut BlockSets<BorrowIndex>,
location: Location) {
if let Some(regioncx) = self.nonlexical_regioncx {
if let Some(ref regioncx) = self.nonlexical_regioncx {
for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
let borrow_region = borrow_data.region.to_region_vid();
if !regioncx.region_contains_point(borrow_region, location) {
......
......@@ -263,6 +263,10 @@ pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
}
}
}
pub fn find_local(&self, local: Local) -> MovePathIndex {
self.locals[local]
}
}
#[derive(Debug)]
......
......@@ -43,7 +43,6 @@
pub mod copy_prop;
pub mod generator;
pub mod inline;
pub mod nll;
pub mod lower_128bit;
pub(crate) fn provide(providers: &mut Providers) {
......
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
#![allow(warnings)]
struct Wrap<'p> { p: &'p mut i32 }
impl<'p> Drop for Wrap<'p> {
fn drop(&mut self) {
*self.p += 1;
}
}
struct Foo<'p> { a: String, b: Wrap<'p> }
fn main() {
let mut x = 0;
let wrap = Wrap { p: &mut x };
let s = String::from("str");
let foo = Foo { a: s, b: wrap };
std::mem::drop(foo.b);
x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
// FIXME ^ Should not error in the future with implicit dtors, only manually implemented ones
}
error[E0506]: cannot assign to `x` because it is borrowed
--> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:31:5
|
27 | let wrap = Wrap { p: &mut x };
| ------ borrow of `x` occurs here
...
31 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
| ^^^^^ assignment to borrowed `x` occurs here
error: aborting due to previous error
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
#![allow(warnings)]
struct Wrap<'p> { p: &'p mut i32 }
impl<'p> Drop for Wrap<'p> {
fn drop(&mut self) {
*self.p += 1;
}
}
fn main() {
let mut x = 0;
let wrap = Wrap { p: &mut x };
std::mem::drop(wrap);
x = 1; // OK, drop is inert
}
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
#![allow(warnings)]
struct Wrap<'p> { p: &'p mut i32 }
impl<'p> Drop for Wrap<'p> {
fn drop(&mut self) {
*self.p += 1;
}
}
struct Foo<'p> { a: String, b: Wrap<'p> }
fn main() {
let mut x = 0;
let wrap = Wrap { p: &mut x };
let s = String::from("str");
let foo = Foo { a: s, b: wrap };
std::mem::drop(foo.a);
x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
}
error[E0506]: cannot assign to `x` because it is borrowed
--> $DIR/maybe-initialized-drop-with-fragment.rs:31:5
|
27 | let wrap = Wrap { p: &mut x };
| ------ borrow of `x` occurs here
...
31 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
| ^^^^^ assignment to borrowed `x` occurs here
error: aborting due to previous error
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
#![allow(warnings)]
struct Wrap<'p> { p: &'p mut i32 }
impl<'p> Drop for Wrap<'p> {
fn drop(&mut self) {
*self.p += 1;
}
}
struct Foo<'p> { a: String, b: Wrap<'p> }
fn main() {
let mut x = 0;
let wrap = Wrap { p: &mut x };
let s = String::from("str");
let foo = Foo { a: s, b: wrap };
std::mem::drop(foo.a);
std::mem::drop(foo.b);
x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
// FIXME ^ This currently errors and it should not.
}
error[E0506]: cannot assign to `x` because it is borrowed
--> $DIR/maybe-initialized-drop-with-uninitialized-fragments.rs:32:5
|
27 | let wrap = Wrap { p: &mut x };
| ------ borrow of `x` occurs here
...
32 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
| ^^^^^ assignment to borrowed `x` occurs here
error: aborting due to previous error
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
#![allow(warnings)]
struct Wrap<'p> { p: &'p mut i32 }
impl<'p> Drop for Wrap<'p> {
fn drop(&mut self) {
*self.p += 1;
}
}
fn main() {
let mut x = 0;
let wrap = Wrap { p: &mut x };
x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
}
error[E0506]: cannot assign to `x` because it is borrowed
--> $DIR/maybe-initialized-drop.rs:26:5
|
25 | let wrap = Wrap { p: &mut x };
| ------ borrow of `x` occurs here
26 | x = 1; //~ ERROR cannot assign to `x` because it is borrowed [E0506]
| ^^^^^ assignment to borrowed `x` occurs here
error: aborting due to previous error
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册