Auto merge of #36353 - arielb1:union-drops, r=pnkfelix

a few move-checker improvements

This fixes moves out of unions and prohibits moves out of slices (see the individual commits).

r? @pnkfelix
This commit is contained in:
bors 2016-09-16 07:23:18 -07:00 committed by GitHub
commit c6673db58d
16 changed files with 576 additions and 743 deletions

View File

@ -1243,7 +1243,7 @@ impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> {
type Iter = IntoIter<BasicBlock>;
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct Location {
/// the location is within this block
pub block: BasicBlock,
@ -1253,3 +1253,8 @@ pub struct Location {
pub statement_index: usize,
}
impl fmt::Debug for Location {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{:?}[{}]", self.block, self.statement_index)
}
}

View File

@ -774,9 +774,6 @@ pub enum LvalueContext<'tcx> {
// Being borrowed
Borrow { region: &'tcx Region, kind: BorrowKind },
// Being sliced -- this should be same as being borrowed, probably
Slice { from_start: usize, from_end: usize },
// Used as base for another lvalue, e.g. `x` in `x.y`
Projection,

View File

@ -185,6 +185,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
check_and_get_illegal_move_origin(bccx, b)
}
}
ty::TySlice(..) => Some(cmt.clone()),
_ => {
check_and_get_illegal_move_origin(bccx, b)
}

View File

@ -16,7 +16,6 @@ use rustc::ty;
use syntax::ast;
use syntax_pos;
use errors::DiagnosticBuilder;
use rustc::hir;
pub struct MoveErrorCollector<'tcx> {
errors: Vec<MoveError<'tcx>>
@ -131,17 +130,20 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
err
}
Categorization::Interior(ref b, mc::InteriorElement(Kind::Index, _)) => {
let expr = bccx.tcx.map.expect_expr(move_from.id);
if let hir::ExprIndex(..) = expr.node {
let mut err = struct_span_err!(bccx, move_from.span, E0508,
"cannot move out of type `{}`, \
a non-copy fixed-size array",
b.ty);
err.span_label(move_from.span, &format!("cannot move out of here"));
err
} else {
span_bug!(move_from.span, "this path should not cause illegal move");
Categorization::Interior(ref b, mc::InteriorElement(ik, _)) => {
match (&b.ty.sty, ik) {
(&ty::TySlice(..), _) |
(_, Kind::Index) => {
let mut err = struct_span_err!(bccx, move_from.span, E0508,
"cannot move out of type `{}`, \
a non-copy array",
b.ty);
err.span_label(move_from.span, &format!("cannot move out of here"));
err
}
(_, Kind::Pattern) => {
span_bug!(move_from.span, "this path should not cause illegal move");
}
}
}

View File

@ -17,7 +17,7 @@ use super::super::MoveDataParamEnv;
use super::super::DropFlagState;
use super::super::drop_flag_effects_for_function_entry;
use super::super::drop_flag_effects_for_location;
use super::super::on_all_children_bits;
use super::super::on_lookup_result_bits;
use super::{BitDenotation, BlockSets, DataflowOperator};
@ -277,10 +277,9 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> {
dest_lval: &repr::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 1 (initialized).
let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval);
on_all_children_bits(self.tcx, self.mir, &ctxt.move_data,
move_path_index,
|mpi| { in_out.add(&mpi); });
on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
ctxt.move_data.rev_lookup.find(dest_lval),
|mpi| { in_out.add(&mpi); });
}
}
@ -338,11 +337,10 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> {
_dest_bb: repr::BasicBlock,
dest_lval: &repr::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 1 (initialized).
let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval);
on_all_children_bits(self.tcx, self.mir, &ctxt.move_data,
move_path_index,
|mpi| { in_out.remove(&mpi); });
// the bits for that dest_lval to 0 (initialized).
on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
ctxt.move_data.rev_lookup.find(dest_lval),
|mpi| { in_out.remove(&mpi); });
}
}
@ -400,10 +398,9 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> {
dest_lval: &repr::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 1 (initialized).
let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval);
on_all_children_bits(self.tcx, self.mir, &ctxt.move_data,
move_path_index,
|mpi| { in_out.add(&mpi); });
on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
ctxt.move_data.rev_lookup.find(dest_lval),
|mpi| { in_out.add(&mpi); });
}
}
@ -448,11 +445,10 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
// assigning into this `lvalue` kills all
// MoveOuts from it, and *also* all MoveOuts
// for children and associated fragment sets.
let move_path_index = rev_lookup.find(lvalue);
on_all_children_bits(tcx,
on_lookup_result_bits(tcx,
mir,
move_data,
move_path_index,
rev_lookup.find(lvalue),
|mpi| for moi in &path_map[mpi] {
assert!(moi.index() < bits_per_block);
sets.kill_set.add(&moi);
@ -489,18 +485,17 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
_dest_bb: repr::BasicBlock,
dest_lval: &repr::Lvalue) {
let move_data = &ctxt.move_data;
let move_path_index = move_data.rev_lookup.find(dest_lval);
let bits_per_block = self.bits_per_block(ctxt);
let path_map = &move_data.path_map;
on_all_children_bits(self.tcx,
self.mir,
move_data,
move_path_index,
|mpi| for moi in &path_map[mpi] {
assert!(moi.index() < bits_per_block);
in_out.remove(&moi);
});
on_lookup_result_bits(self.tcx,
self.mir,
move_data,
move_data.rev_lookup.find(dest_lval),
|mpi| for moi in &path_map[mpi] {
assert!(moi.index() < bits_per_block);
in_out.remove(&moi);
});
}
}

View File

@ -16,7 +16,7 @@ use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir};
use rustc_data_structures::indexed_vec::Idx;
use super::super::gather_moves::{MovePathIndex};
use super::super::gather_moves::{MovePathIndex, LookupResult};
use super::super::MoveDataParamEnv;
use super::BitDenotation;
use super::DataflowResults;
@ -116,20 +116,26 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
repr::BorrowKind::Shared,
ref peeking_at_lval) = *rvalue {
// Okay, our search is over.
let peek_mpi = move_data.rev_lookup.find(peeking_at_lval);
let bit_state = sets.on_entry.contains(&peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
lvalue, peeking_at_lval, bit_state);
if !bit_state {
tcx.sess.span_err(span, &format!("rustc_peek: bit not set"));
match move_data.rev_lookup.find(peeking_at_lval) {
LookupResult::Exact(peek_mpi) => {
let bit_state = sets.on_entry.contains(&peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
lvalue, peeking_at_lval, bit_state);
if !bit_state {
tcx.sess.span_err(span, "rustc_peek: bit not set");
}
}
LookupResult::Parent(..) => {
tcx.sess.span_err(span, "rustc_peek: argument untracked");
}
}
return;
} else {
// Our search should have been over, but the input
// does not match expectations of `rustc_peek` for
// this sanity_check.
let msg = &format!("rustc_peek: argument expression \
must be immediate borrow of form `&expr`");
let msg = "rustc_peek: argument expression \
must be immediate borrow of form `&expr`";
tcx.sess.span_err(span, msg);
}
}

View File

@ -9,10 +9,11 @@
// except according to those terms.
use indexed_set::IdxSetBuf;
use super::gather_moves::{MoveData, MovePathIndex, MovePathContent};
use super::gather_moves::{MoveData, MovePathIndex, LookupResult};
use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use super::dataflow::{DataflowResults};
use super::{drop_flag_effects_for_location, on_all_children_bits};
use super::on_lookup_result_bits;
use super::{DropFlagState, MoveDataParamEnv};
use super::patch::MirPatch;
use rustc::ty::{self, Ty, TyCtxt};
@ -42,7 +43,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
}
let id = src.item_id();
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let move_data = MoveData::gather_moves(mir, tcx);
let move_data = MoveData::gather_moves(mir, tcx, &param_env);
let elaborate_patch = {
let mir = &*mir;
let env = MoveDataParamEnv {
@ -184,31 +185,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
fn path_needs_drop(&self, path: MovePathIndex) -> bool
{
match self.move_data().move_paths[path].content {
MovePathContent::Lvalue(ref lvalue) => {
let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty);
let lvalue = &self.move_data().move_paths[path].lvalue;
let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty);
self.tcx.type_needs_drop_given_env(ty, self.param_env())
}
_ => false
}
}
/// Returns whether this lvalue is tracked by drop elaboration. This
/// includes all lvalues, except these (1.) behind references or arrays,
/// or (2.) behind ADT's with a Drop impl.
fn lvalue_is_tracked(&self, lv: &Lvalue<'tcx>) -> bool
{
// `lvalue_contents_drop_state_cannot_differ` only compares
// the `lv` to its immediate contents, while this recursively
// follows parent chain formed by `base` of each projection.
if let &Lvalue::Projection(ref data) = lv {
!super::lvalue_contents_drop_state_cannot_differ(self.tcx, self.mir, &data.base) &&
self.lvalue_is_tracked(&data.base)
} else {
true
}
self.tcx.type_needs_drop_given_env(ty, self.param_env())
}
fn collect_drop_flags(&mut self)
@ -221,19 +202,29 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
_ => continue
};
if !self.lvalue_is_tracked(location) {
continue
}
let init_data = self.initialization_data_at(Location {
block: bb,
statement_index: data.statements.len()
});
let path = self.move_data().rev_lookup.find(location);
debug!("collect_drop_flags: {:?}, lv {:?} (index {:?})",
debug!("collect_drop_flags: {:?}, lv {:?} ({:?})",
bb, location, path);
let path = match path {
LookupResult::Exact(e) => e,
LookupResult::Parent(None) => continue,
LookupResult::Parent(Some(parent)) => {
let (_maybe_live, maybe_dead) = init_data.state(parent);
if maybe_dead {
span_bug!(terminator.source_info.span,
"drop of untracked, uninitialized value {:?}, lv {:?} ({:?})",
bb, location, path);
}
continue
}
};
on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| {
if self.path_needs_drop(child) {
let (maybe_live, maybe_dead) = init_data.state(child);
@ -257,20 +248,27 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
match terminator.kind {
TerminatorKind::Drop { ref location, target, unwind } => {
let init_data = self.initialization_data_at(loc);
let path = self.move_data().rev_lookup.find(location);
self.elaborate_drop(&DropCtxt {
source_info: terminator.source_info,
is_cleanup: data.is_cleanup,
init_data: &init_data,
lvalue: location,
path: path,
succ: target,
unwind: if data.is_cleanup {
None
} else {
Some(Option::unwrap_or(unwind, resume_block))
match self.move_data().rev_lookup.find(location) {
LookupResult::Exact(path) => {
self.elaborate_drop(&DropCtxt {
source_info: terminator.source_info,
is_cleanup: data.is_cleanup,
init_data: &init_data,
lvalue: location,
path: path,
succ: target,
unwind: if data.is_cleanup {
None
} else {
Some(Option::unwrap_or(unwind, resume_block))
}
}, bb);
}
}, bb);
LookupResult::Parent(..) => {
span_bug!(terminator.source_info.span,
"drop of untracked value {:?}", bb);
}
}
}
TerminatorKind::DropAndReplace { ref location, ref value,
target, unwind } =>
@ -336,35 +334,37 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
is_cleanup: data.is_cleanup,
});
if !self.lvalue_is_tracked(location) {
// drop and replace behind a pointer/array/whatever. The location
// must be initialized.
debug!("elaborate_drop_and_replace({:?}) - untracked", terminator);
self.patch.patch_terminator(bb, TerminatorKind::Drop {
location: location.clone(),
target: target,
unwind: Some(unwind)
});
} else {
debug!("elaborate_drop_and_replace({:?}) - tracked", terminator);
let init_data = self.initialization_data_at(loc);
let path = self.move_data().rev_lookup.find(location);
match self.move_data().rev_lookup.find(location) {
LookupResult::Exact(path) => {
debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
let init_data = self.initialization_data_at(loc);
self.elaborate_drop(&DropCtxt {
source_info: terminator.source_info,
is_cleanup: data.is_cleanup,
init_data: &init_data,
lvalue: location,
path: path,
succ: target,
unwind: Some(unwind)
}, bb);
on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| {
self.set_drop_flag(Location { block: target, statement_index: 0 },
child, DropFlagState::Present);
self.set_drop_flag(Location { block: unwind, statement_index: 0 },
child, DropFlagState::Present);
});
self.elaborate_drop(&DropCtxt {
source_info: terminator.source_info,
is_cleanup: data.is_cleanup,
init_data: &init_data,
lvalue: location,
path: path,
succ: target,
unwind: Some(unwind)
}, bb);
on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| {
self.set_drop_flag(Location { block: target, statement_index: 0 },
child, DropFlagState::Present);
self.set_drop_flag(Location { block: unwind, statement_index: 0 },
child, DropFlagState::Present);
});
}
LookupResult::Parent(parent) => {
// drop and replace behind a pointer/array/whatever. The location
// must be initialized.
debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent);
self.patch.patch_terminator(bb, TerminatorKind::Drop {
location: location.clone(),
target: target,
unwind: Some(unwind)
});
}
}
}
@ -446,10 +446,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
substs: &'tcx Substs<'tcx>)
-> Vec<(Lvalue<'tcx>, Option<MovePathIndex>)>
{
let move_paths = &self.move_data().move_paths;
variant.fields.iter().enumerate().map(|(i, f)| {
let subpath =
super::move_path_children_matching(move_paths, variant_path, |p| {
super::move_path_children_matching(self.move_data(), variant_path, |p| {
match p {
&Projection {
elem: ProjectionElem::Field(idx, _), ..
@ -580,7 +579,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let fields = tys.iter().enumerate().map(|(i, &ty)| {
(c.lvalue.clone().field(Field::new(i), ty),
super::move_path_children_matching(
&self.move_data().move_paths, c.path, |proj| match proj {
self.move_data(), c.path, |proj| match proj {
&Projection {
elem: ProjectionElem::Field(f, _), ..
} => f.index() == i,
@ -598,7 +597,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
debug!("open_drop_for_box({:?}, {:?})", c, ty);
let interior_path = super::move_path_children_matching(
&self.move_data().move_paths, c.path, |proj| match proj {
self.move_data(), c.path, |proj| match proj {
&Projection { elem: ProjectionElem::Deref, .. } => true,
_ => false
}).unwrap();
@ -625,10 +624,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
variant_index: usize)
-> BasicBlock
{
let move_paths = &self.move_data().move_paths;
let subpath = super::move_path_children_matching(
move_paths, c.path, |proj| match proj {
self.move_data(), c.path, |proj| match proj {
&Projection {
elem: ProjectionElem::Downcast(_, idx), ..
} => idx == variant_index,
@ -942,7 +939,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let loc = Location { block: tgt, statement_index: 0 };
let path = self.move_data().rev_lookup.find(lv);
on_all_children_bits(
on_lookup_result_bits(
self.tcx, self.mir, self.move_data(), path,
|child| self.set_drop_flag(loc, child, DropFlagState::Present)
);
@ -1011,7 +1008,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let loc = Location { block: bb, statement_index: data.statements.len() };
let path = self.move_data().rev_lookup.find(lv);
on_all_children_bits(
on_lookup_result_bits(
self.tcx, self.mir, self.move_data(), path,
|child| self.set_drop_flag(loc, child, DropFlagState::Present)
);

File diff suppressed because it is too large Load Diff

View File

@ -34,8 +34,7 @@ use self::dataflow::{DataflowOperator};
use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults};
use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use self::dataflow::{DefinitelyInitializedLvals};
use self::gather_moves::{MoveData, MovePathIndex};
use self::gather_moves::{MovePathContent, MovePathData};
use self::gather_moves::{MoveData, MovePathIndex, LookupResult};
fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<P<MetaItem>> {
for attr in attrs {
@ -78,8 +77,8 @@ pub fn borrowck_mir<'a, 'tcx: 'a>(
let tcx = bcx.tcx;
let move_data = MoveData::gather_moves(mir, tcx);
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let move_data = MoveData::gather_moves(mir, tcx, &param_env);
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
let flow_inits =
do_dataflow(tcx, mir, id, attributes, &mdpe, MaybeInitializedLvals::new(tcx, mir));
@ -211,23 +210,23 @@ impl DropFlagState {
}
}
fn move_path_children_matching<'tcx, F>(move_paths: &MovePathData<'tcx>,
fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>,
path: MovePathIndex,
mut cond: F)
-> Option<MovePathIndex>
where F: FnMut(&repr::LvalueProjection<'tcx>) -> bool
{
let mut next_child = move_paths[path].first_child;
let mut next_child = move_data.move_paths[path].first_child;
while let Some(child_index) = next_child {
match move_paths[child_index].content {
MovePathContent::Lvalue(repr::Lvalue::Projection(ref proj)) => {
match move_data.move_paths[child_index].lvalue {
repr::Lvalue::Projection(ref proj) => {
if cond(proj) {
return Some(child_index)
}
}
_ => {}
}
next_child = move_paths[child_index].next_sibling;
next_child = move_data.move_paths[child_index].next_sibling;
}
None
@ -257,12 +256,12 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
let ty = lv.ty(mir, tcx).to_ty(tcx);
match ty.sty {
ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => false",
debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => true",
lv, ty);
true
}
ty::TyAdt(def, _) if def.has_dtor() => {
debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false",
ty::TyAdt(def, _) if def.has_dtor() || def.is_union() => {
debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true",
lv, ty);
true
}
@ -272,6 +271,24 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
}
}
fn on_lookup_result_bits<'a, 'tcx, F>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
move_data: &MoveData<'tcx>,
lookup_result: LookupResult,
each_child: F)
where F: FnMut(MovePathIndex)
{
match lookup_result {
LookupResult::Parent(..) => {
// access to untracked value - do not touch children
}
LookupResult::Exact(e) => {
on_all_children_bits(tcx, mir, move_data, e, each_child)
}
}
}
fn on_all_children_bits<'a, 'tcx, F>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
@ -286,12 +303,8 @@ fn on_all_children_bits<'a, 'tcx, F>(
move_data: &MoveData<'tcx>,
path: MovePathIndex) -> bool
{
match move_data.move_paths[path].content {
MovePathContent::Lvalue(ref lvalue) => {
lvalue_contents_drop_state_cannot_differ(tcx, mir, lvalue)
}
_ => true
}
lvalue_contents_drop_state_cannot_differ(
tcx, mir, &move_data.move_paths[path].lvalue)
}
fn on_all_children_bits<'a, 'tcx, F>(
@ -327,10 +340,10 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>(
let move_data = &ctxt.move_data;
for (arg, _) in mir.arg_decls.iter_enumerated() {
let lvalue = repr::Lvalue::Arg(arg);
let move_path_index = move_data.rev_lookup.find(&lvalue);
on_all_children_bits(tcx, mir, move_data,
move_path_index,
|moi| callback(moi, DropFlagState::Present));
let lookup_result = move_data.rev_lookup.find(&lvalue);
on_lookup_result_bits(tcx, mir, move_data,
lookup_result,
|moi| callback(moi, DropFlagState::Present));
}
}
@ -352,11 +365,10 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
debug!("moving out of path {:?}", move_data.move_paths[path]);
// don't move out of non-Copy things
if let MovePathContent::Lvalue(ref lvalue) = move_data.move_paths[path].content {
let ty = lvalue.ty(mir, tcx).to_ty(tcx);
if !ty.moves_by_default(tcx, param_env, DUMMY_SP) {
continue;
}
let lvalue = &move_data.move_paths[path].lvalue;
let ty = lvalue.ty(mir, tcx).to_ty(tcx);
if !ty.moves_by_default(tcx, param_env, DUMMY_SP) {
continue;
}
on_all_children_bits(tcx, mir, move_data,
@ -372,9 +384,9 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
}
repr::StatementKind::Assign(ref lvalue, _) => {
debug!("drop_flag_effects: assignment {:?}", stmt);
on_all_children_bits(tcx, mir, move_data,
move_data.rev_lookup.find(lvalue),
|moi| callback(moi, DropFlagState::Present))
on_lookup_result_bits(tcx, mir, move_data,
move_data.rev_lookup.find(lvalue),
|moi| callback(moi, DropFlagState::Present))
}
repr::StatementKind::StorageLive(_) |
repr::StatementKind::StorageDead(_) => {}
@ -383,9 +395,9 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
debug!("drop_flag_effects: replace {:?}", block.terminator());
match block.terminator().kind {
repr::TerminatorKind::DropAndReplace { ref location, .. } => {
on_all_children_bits(tcx, mir, move_data,
move_data.rev_lookup.find(location),
|moi| callback(moi, DropFlagState::Present))
on_lookup_result_bits(tcx, mir, move_data,
move_data.rev_lookup.find(location),
|moi| callback(moi, DropFlagState::Present))
}
_ => {
// other terminators do not contain move-ins

View File

@ -180,7 +180,6 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
LvalueContext::Store |
LvalueContext::Inspect |
LvalueContext::Borrow { .. } |
LvalueContext::Slice { .. } |
LvalueContext::Projection => {
self.mark_as_lvalue(index);
}

View File

@ -28,7 +28,7 @@ pub fn main() {
[_, ref tail..] => {
match tail {
&[Foo { string: a },
//~^ ERROR cannot move out of borrowed content
//~^ ERROR cannot move out of type `[Foo]`
//~| cannot move out
//~| to prevent move
Foo { string: b }] => {

View File

@ -40,7 +40,7 @@ fn c() {
let mut vec = vec!(box 1, box 2, box 3);
let vec: &mut [Box<isize>] = &mut vec;
match vec {
&mut [_a, //~ ERROR cannot move out of borrowed content
&mut [_a, //~ ERROR cannot move out
//~| cannot move out
//~| to prevent move
..

View File

@ -15,12 +15,12 @@ fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) {
(&[], &[]) => println!("both empty"),
(&[], &[hd, ..]) | (&[hd, ..], &[])
=> println!("one empty"),
//~^^ ERROR: cannot move out of borrowed content
//~^^^ ERROR: cannot move out of borrowed content
//~^^ ERROR: cannot move out of type `[T]`, a non-copy array
//~^^^ ERROR: cannot move out of type `[T]`, a non-copy array
(&[hd1, ..], &[hd2, ..])
=> println!("both nonempty"),
//~^^ ERROR: cannot move out of borrowed content
//~^^^ ERROR: cannot move out of borrowed content
//~^^ ERROR: cannot move out of type `[T]`, a non-copy array
//~^^^ ERROR: cannot move out of type `[T]`, a non-copy array
}
}

View File

@ -23,7 +23,7 @@ struct S(i32);
fn foo(x: &mut S) {
// `x` is initialized here, so maybe-uninit bit is 0.
unsafe { *rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set
unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set
::std::mem::drop(x);

View File

@ -0,0 +1,21 @@
// Copyright 2016 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.
#![feature(slice_patterns, box_patterns)]
struct A;
fn main() {
let a: Box<[A]> = Box::new([A]);
match a {
box [a] => {}, //~ ERROR cannot move out of type `[A]`
_ => {}
}
}

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_attrs)]
#![feature(untagged_unions)]
use std::cell::{Cell, RefCell};
use std::panic;
@ -111,6 +111,20 @@ fn assignment1(a: &Allocator, c0: bool) {
_v = _w;
}
#[allow(unions_with_drop_fields)]
union Boxy<T> {
a: T,
b: T,
}
fn union1(a: &Allocator) {
unsafe {
let mut u = Boxy { a: a.alloc() };
u.b = a.alloc();
drop(u.a);
}
}
fn run_test<F>(mut f: F)
where F: FnMut(&Allocator)
{
@ -136,6 +150,13 @@ fn run_test<F>(mut f: F)
}
}
fn run_test_nopanic<F>(mut f: F)
where F: FnMut(&Allocator)
{
let first_alloc = Allocator::new(usize::MAX);
f(&first_alloc);
}
fn main() {
run_test(|a| dynamic_init(a, false));
run_test(|a| dynamic_init(a, true));
@ -149,4 +170,6 @@ fn main() {
run_test(|a| assignment1(a, false));
run_test(|a| assignment1(a, true));
run_test_nopanic(|a| union1(a));
}