Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 6 pull requests #61151

Merged
merged 14 commits into from
May 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 78 additions & 75 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionV
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::mir::interpret::{InterpError::BoundsCheck, ConstValue};
use rustc::mir::tcx::PlaceTy;
use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
use rustc::mir::visit::{PlaceContext, Visitor, NonMutatingUseContext};
use rustc::mir::*;
use rustc::traits::query::type_op;
use rustc::traits::query::type_op::custom::CustomTypeOp;
Expand Down Expand Up @@ -447,92 +447,95 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
context: PlaceContext,
) -> PlaceTy<'tcx> {
debug!("sanitize_place: {:?}", place);
let place_ty = match place {
Place::Base(PlaceBase::Local(index)) =>
PlaceTy::from_ty(self.mir.local_decls[*index].ty),
Place::Base(PlaceBase::Static(box Static { kind, ty: sty })) => {
let sty = self.sanitize_type(place, sty);
let check_err =
|verifier: &mut TypeVerifier<'a, 'b, 'gcx, 'tcx>,
place: &Place<'tcx>,
ty,
sty| {
if let Err(terr) = verifier.cx.eq_types(
sty,
ty,
location.to_locations(),
ConstraintCategory::Boring,
) {
span_mirbug!(
verifier,
place,
"bad promoted type ({:?}: {:?}): {:?}",
ty,
sty,
terr
);

place.iterate(|place_base, place_projection| {
let mut place_ty = match place_base {
PlaceBase::Local(index) =>
PlaceTy::from_ty(self.mir.local_decls[*index].ty),
PlaceBase::Static(box Static { kind, ty: sty }) => {
let sty = self.sanitize_type(place, sty);
let check_err =
|verifier: &mut TypeVerifier<'a, 'b, 'gcx, 'tcx>,
place: &Place<'tcx>,
ty,
sty| {
if let Err(terr) = verifier.cx.eq_types(
sty,
ty,
location.to_locations(),
ConstraintCategory::Boring,
) {
span_mirbug!(
verifier,
place,
"bad promoted type ({:?}: {:?}): {:?}",
ty,
sty,
terr
);
};
};
};
match kind {
StaticKind::Promoted(promoted) => {
if !self.errors_reported {
let promoted_mir = &self.mir.promoted[*promoted];
self.sanitize_promoted(promoted_mir, location);

let promoted_ty = promoted_mir.return_ty();
check_err(self, place, promoted_ty, sty);
match kind {
StaticKind::Promoted(promoted) => {
if !self.errors_reported {
let promoted_mir = &self.mir.promoted[*promoted];
self.sanitize_promoted(promoted_mir, location);

let promoted_ty = promoted_mir.return_ty();
check_err(self, place, promoted_ty, sty);
}
}
}
StaticKind::Static(def_id) => {
let ty = self.tcx().type_of(*def_id);
let ty = self.cx.normalize(ty, location);
StaticKind::Static(def_id) => {
let ty = self.tcx().type_of(*def_id);
let ty = self.cx.normalize(ty, location);

check_err(self, place, ty, sty);
check_err(self, place, ty, sty);
}
}
PlaceTy::from_ty(sty)
}
};

// FIXME use place_projection.is_empty() when is available
if let Place::Base(_) = place {
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
let tcx = self.tcx();
let trait_ref = ty::TraitRef {
def_id: tcx.lang_items().copy_trait().unwrap(),
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
};

// In order to have a Copy operand, the type T of the
// value must be Copy. Note that we prove that T: Copy,
// rather than using the `is_copy_modulo_regions`
// test. This is important because
// `is_copy_modulo_regions` ignores the resulting region
// obligations and assumes they pass. This can result in
// bounds from Copy impls being unsoundly ignored (e.g.,
// #29149). Note that we decide to use Copy before knowing
// whether the bounds fully apply: in effect, the rule is
// that if a value of some type could implement Copy, then
// it must.
self.cx.prove_trait_ref(
trait_ref,
location.to_locations(),
ConstraintCategory::CopyBound,
);
}
PlaceTy::from_ty(sty)
}
Place::Projection(ref proj) => {
let base_context = if context.is_mutating_use() {
PlaceContext::MutatingUse(MutatingUseContext::Projection)
} else {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
};
let base_ty = self.sanitize_place(&proj.base, location, base_context);
if base_ty.variant_index.is_none() {
if base_ty.ty.references_error() {

for proj in place_projection {
if place_ty.variant_index.is_none() {
if place_ty.ty.references_error() {
assert!(self.errors_reported);
return PlaceTy::from_ty(self.tcx().types.err);
}
}
self.sanitize_projection(base_ty, &proj.elem, place, location)
place_ty = self.sanitize_projection(place_ty, &proj.elem, place, location)
}
};
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
let tcx = self.tcx();
let trait_ref = ty::TraitRef {
def_id: tcx.lang_items().copy_trait().unwrap(),
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
};

// In order to have a Copy operand, the type T of the
// value must be Copy. Note that we prove that T: Copy,
// rather than using the `is_copy_modulo_regions`
// test. This is important because
// `is_copy_modulo_regions` ignores the resulting region
// obligations and assumes they pass. This can result in
// bounds from Copy impls being unsoundly ignored (e.g.,
// #29149). Note that we decide to use Copy before knowing
// whether the bounds fully apply: in effect, the rule is
// that if a value of some type could implement Copy, then
// it must.
self.cx.prove_trait_ref(
trait_ref,
location.to_locations(),
ConstraintCategory::CopyBound,
);
}
place_ty
place_ty
})
}

fn sanitize_promoted(&mut self, promoted_mir: &'b Mir<'tcx>, location: Location) {
Expand Down
28 changes: 13 additions & 15 deletions src/librustc_mir/borrow_check/path_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,22 +131,20 @@ pub(super) fn is_active<'tcx>(
/// Determines if a given borrow is borrowing local data
/// This is called for all Yield statements on movable generators
pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
match place {
Place::Base(PlaceBase::Static(..)) => false,
Place::Base(PlaceBase::Local(..)) => true,
Place::Projection(box proj) => {
match proj.elem {
// Reborrow of already borrowed data is ignored
// Any errors will be caught on the initial borrow
ProjectionElem::Deref => false,
place.iterate(|place_base, place_projection| {
match place_base {
PlaceBase::Static(..) => return false,
PlaceBase::Local(..) => {},
}

// For interior references and downcasts, find out if the base is local
ProjectionElem::Field(..)
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..) => borrow_of_local_data(&proj.base),
for proj in place_projection {
// Reborrow of already borrowed data is ignored
// Any errors will be caught on the initial borrow
if proj.elem == ProjectionElem::Deref {
return false;
}
}
}

true
})
}
68 changes: 33 additions & 35 deletions src/librustc_mir/borrow_check/place_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,40 +25,36 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
mir: &Mir<'tcx>,
locals_state_at_exit: &LocalsStateAtExit,
) -> bool {
match self {
// If a local variable is immutable, then we only need to track borrows to guard
// against two kinds of errors:
// * The variable being dropped while still borrowed (e.g., because the fn returns
// a reference to a local variable)
// * The variable being moved while still borrowed
//
// In particular, the variable cannot be mutated -- the "access checks" will fail --
// so we don't have to worry about mutation while borrowed.
Place::Base(PlaceBase::Local(index)) => {
match locals_state_at_exit {
LocalsStateAtExit::AllAreInvalidated => false,
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
let ignore = !has_storage_dead_or_moved.contains(*index) &&
mir.local_decls[*index].mutability == Mutability::Not;
debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
ignore
self.iterate(|place_base, place_projection| {
let ignore = match place_base {
// If a local variable is immutable, then we only need to track borrows to guard
// against two kinds of errors:
// * The variable being dropped while still borrowed (e.g., because the fn returns
// a reference to a local variable)
// * The variable being moved while still borrowed
//
// In particular, the variable cannot be mutated -- the "access checks" will fail --
// so we don't have to worry about mutation while borrowed.
PlaceBase::Local(index) => {
match locals_state_at_exit {
LocalsStateAtExit::AllAreInvalidated => false,
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
let ignore = !has_storage_dead_or_moved.contains(*index) &&
mir.local_decls[*index].mutability == Mutability::Not;
debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
ignore
}
}
}
}
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
false,
Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
tcx.is_mutable_static(*def_id)
}
Place::Projection(proj) => match proj.elem {
ProjectionElem::Field(..)
| ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Index(_) => proj.base.ignore_borrow(
tcx, mir, locals_state_at_exit),
PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) =>
false,
PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
tcx.is_mutable_static(*def_id)
}
};

ProjectionElem::Deref => {
for proj in place_projection {
if proj.elem == ProjectionElem::Deref {
let ty = proj.base.ty(mir, tcx).ty;
match ty.sty {
// For both derefs of raw pointers and `&T`
Expand All @@ -71,11 +67,13 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
// original path into a new variable and
// borrowed *that* one, leaving the original
// path unborrowed.
ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => true,
_ => proj.base.ignore_borrow(tcx, mir, locals_state_at_exit),
ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true,
_ => {}
}
}
},
}
}

ignore
})
}
}
19 changes: 11 additions & 8 deletions src/librustc_mir/dataflow/impls/borrowed_locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,19 @@ struct BorrowedLocalsVisitor<'b, 'c: 'b> {
}

fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
match *place {
Place::Base(PlaceBase::Local(l)) => Some(l),
Place::Base(PlaceBase::Static(..)) => None,
Place::Projection(ref proj) => {
match proj.elem {
ProjectionElem::Deref => None,
_ => find_local(&proj.base)
place.iterate(|place_base, place_projection| {
for proj in place_projection {
if proj.elem == ProjectionElem::Deref {
return None;
}
}
}

if let PlaceBase::Local(local) = place_base {
Some(*local)
} else {
None
}
})
}

impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> {
Expand Down
27 changes: 14 additions & 13 deletions src/librustc_mir/dataflow/move_paths/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,21 +241,22 @@ impl MovePathLookup {
// unknown place, but will rather return the nearest available
// parent.
pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
match *place {
Place::Base(PlaceBase::Local(local)) => LookupResult::Exact(self.locals[local]),
Place::Base(PlaceBase::Static(..)) => LookupResult::Parent(None),
Place::Projection(ref proj) => {
match self.find(&proj.base) {
LookupResult::Exact(base_path) => {
match self.projections.get(&(base_path, proj.elem.lift())) {
Some(&subpath) => LookupResult::Exact(subpath),
None => LookupResult::Parent(Some(base_path))
}
}
inexact => inexact
place.iterate(|place_base, place_projection| {
let mut result = match place_base {
PlaceBase::Local(local) => self.locals[*local],
PlaceBase::Static(..) => return LookupResult::Parent(None),
};

for proj in place_projection {
if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) {
result = subpath;
} else {
return LookupResult::Parent(Some(result));
}
}
}

LookupResult::Exact(result)
})
}

pub fn find_local(&self, local: Local) -> MovePathIndex {
Expand Down
Loading