Auto merge of #55385 - davidtwco:issue-55288, r=oli-obk
NLL: cast causes failure to promote to static Fixes #55288. See commit messages for more details. r? @oli-obk cc @nikomatsakis cc @pnkfelix cc @RalfJung
This commit is contained in:
commit
b3b8760971
14 changed files with 356 additions and 194 deletions
|
@ -364,33 +364,54 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_assign(block, place, rvalue, location);
|
||||
}
|
||||
StatementKind::FakeRead(_, ref $($mutability)* place) => {
|
||||
self.visit_place(place,
|
||||
PlaceContext::Inspect,
|
||||
location);
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
|
||||
location
|
||||
);
|
||||
}
|
||||
StatementKind::EndRegion(_) => {}
|
||||
StatementKind::Validate(_, ref $($mutability)* places) => {
|
||||
for operand in places {
|
||||
self.visit_place(& $($mutability)* operand.place,
|
||||
PlaceContext::Validate, location);
|
||||
self.visit_place(
|
||||
& $($mutability)* operand.place,
|
||||
PlaceContext::NonUse(NonUseContext::Validate),
|
||||
location
|
||||
);
|
||||
self.visit_ty(& $($mutability)* operand.ty,
|
||||
TyContext::Location(location));
|
||||
}
|
||||
}
|
||||
StatementKind::SetDiscriminant{ ref $($mutability)* place, .. } => {
|
||||
self.visit_place(place, PlaceContext::Store, location);
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
location
|
||||
);
|
||||
}
|
||||
StatementKind::StorageLive(ref $($mutability)* local) => {
|
||||
self.visit_local(local, PlaceContext::StorageLive, location);
|
||||
self.visit_local(
|
||||
local,
|
||||
PlaceContext::NonUse(NonUseContext::StorageLive),
|
||||
location
|
||||
);
|
||||
}
|
||||
StatementKind::StorageDead(ref $($mutability)* local) => {
|
||||
self.visit_local(local, PlaceContext::StorageDead, location);
|
||||
self.visit_local(
|
||||
local,
|
||||
PlaceContext::NonUse(NonUseContext::StorageDead),
|
||||
location
|
||||
);
|
||||
}
|
||||
StatementKind::InlineAsm { ref $($mutability)* outputs,
|
||||
ref $($mutability)* inputs,
|
||||
asm: _ } => {
|
||||
for output in & $($mutability)* outputs[..] {
|
||||
self.visit_place(output, PlaceContext::AsmOutput, location);
|
||||
self.visit_place(
|
||||
output,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
|
||||
location
|
||||
);
|
||||
}
|
||||
for input in & $($mutability)* inputs[..] {
|
||||
self.visit_operand(input, location);
|
||||
|
@ -412,7 +433,11 @@ macro_rules! make_mir_visitor {
|
|||
place: &$($mutability)* Place<'tcx>,
|
||||
rvalue: &$($mutability)* Rvalue<'tcx>,
|
||||
location: Location) {
|
||||
self.visit_place(place, PlaceContext::Store, location);
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
location
|
||||
);
|
||||
self.visit_rvalue(rvalue, location);
|
||||
}
|
||||
|
||||
|
@ -459,7 +484,11 @@ macro_rules! make_mir_visitor {
|
|||
TerminatorKind::Drop { ref $($mutability)* location,
|
||||
target,
|
||||
unwind } => {
|
||||
self.visit_place(location, PlaceContext::Drop, source_location);
|
||||
self.visit_place(
|
||||
location,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop),
|
||||
source_location
|
||||
);
|
||||
self.visit_branch(block, target);
|
||||
unwind.map(|t| self.visit_branch(block, t));
|
||||
}
|
||||
|
@ -468,7 +497,11 @@ macro_rules! make_mir_visitor {
|
|||
ref $($mutability)* value,
|
||||
target,
|
||||
unwind } => {
|
||||
self.visit_place(location, PlaceContext::Drop, source_location);
|
||||
self.visit_place(
|
||||
location,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop),
|
||||
source_location
|
||||
);
|
||||
self.visit_operand(value, source_location);
|
||||
self.visit_branch(block, target);
|
||||
unwind.map(|t| self.visit_branch(block, t));
|
||||
|
@ -484,7 +517,11 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_operand(arg, source_location);
|
||||
}
|
||||
if let Some((ref $($mutability)* destination, target)) = *destination {
|
||||
self.visit_place(destination, PlaceContext::Call, source_location);
|
||||
self.visit_place(
|
||||
destination,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Call),
|
||||
source_location
|
||||
);
|
||||
self.visit_branch(block, target);
|
||||
}
|
||||
cleanup.map(|t| self.visit_branch(block, t));
|
||||
|
@ -552,14 +589,28 @@ macro_rules! make_mir_visitor {
|
|||
|
||||
Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => {
|
||||
self.visit_region(r, location);
|
||||
self.visit_place(path, PlaceContext::Borrow {
|
||||
region: *r,
|
||||
kind: bk
|
||||
}, location);
|
||||
let ctx = match bk {
|
||||
BorrowKind::Shared => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow(*r)
|
||||
),
|
||||
BorrowKind::Shallow => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::ShallowBorrow(*r)
|
||||
),
|
||||
BorrowKind::Unique => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::UniqueBorrow(*r)
|
||||
),
|
||||
BorrowKind::Mut { .. } =>
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow(*r)),
|
||||
};
|
||||
self.visit_place(path, ctx, location);
|
||||
}
|
||||
|
||||
Rvalue::Len(ref $($mutability)* path) => {
|
||||
self.visit_place(path, PlaceContext::Inspect, location);
|
||||
self.visit_place(
|
||||
path,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::Cast(_cast_kind,
|
||||
|
@ -584,7 +635,11 @@ macro_rules! make_mir_visitor {
|
|||
}
|
||||
|
||||
Rvalue::Discriminant(ref $($mutability)* place) => {
|
||||
self.visit_place(place, PlaceContext::Inspect, location);
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::NullaryOp(_op, ref $($mutability)* ty) => {
|
||||
|
@ -632,10 +687,18 @@ macro_rules! make_mir_visitor {
|
|||
location: Location) {
|
||||
match *operand {
|
||||
Operand::Copy(ref $($mutability)* place) => {
|
||||
self.visit_place(place, PlaceContext::Copy, location);
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
||||
location
|
||||
);
|
||||
}
|
||||
Operand::Move(ref $($mutability)* place) => {
|
||||
self.visit_place(place, PlaceContext::Move, location);
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
|
||||
location
|
||||
);
|
||||
}
|
||||
Operand::Constant(ref $($mutability)* constant) => {
|
||||
self.visit_constant(constant, location);
|
||||
|
@ -648,7 +711,11 @@ macro_rules! make_mir_visitor {
|
|||
_variance: & $($mutability)* ty::Variance,
|
||||
user_ty: & $($mutability)* UserTypeProjection<'tcx>,
|
||||
location: Location) {
|
||||
self.visit_place(place, PlaceContext::Validate, location);
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::NonUse(NonUseContext::AscribeUserTy),
|
||||
location
|
||||
);
|
||||
self.visit_user_type_projection(user_ty);
|
||||
}
|
||||
|
||||
|
@ -693,9 +760,9 @@ macro_rules! make_mir_visitor {
|
|||
ref $($mutability)* elem,
|
||||
} = *proj;
|
||||
let context = if context.is_mutating_use() {
|
||||
PlaceContext::Projection(Mutability::Mut)
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
||||
} else {
|
||||
PlaceContext::Projection(Mutability::Not)
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
|
||||
};
|
||||
self.visit_place(base, context, location);
|
||||
self.visit_projection_elem(elem, location);
|
||||
|
@ -713,7 +780,11 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_ty(ty, TyContext::Location(location));
|
||||
}
|
||||
ProjectionElem::Index(ref $($mutability)* local) => {
|
||||
self.visit_local(local, PlaceContext::Copy, location);
|
||||
self.visit_local(
|
||||
local,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
||||
location
|
||||
);
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset: _,
|
||||
min_length: _,
|
||||
|
@ -896,125 +967,146 @@ pub enum TyContext {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum PlaceContext<'tcx> {
|
||||
// Appears as LHS of an assignment
|
||||
Store,
|
||||
|
||||
// Can often be treated as a Store, but needs to be separate because
|
||||
// ASM is allowed to read outputs as well, so a Store-AsmOutput sequence
|
||||
// cannot be simplified the way a Store-Store can be.
|
||||
AsmOutput,
|
||||
|
||||
// Dest of a call
|
||||
Call,
|
||||
|
||||
// Being dropped
|
||||
Drop,
|
||||
|
||||
// Being inspected in some way, like loading a len
|
||||
pub enum NonMutatingUseContext<'tcx> {
|
||||
/// Being inspected in some way, like loading a len.
|
||||
Inspect,
|
||||
|
||||
// Being borrowed
|
||||
Borrow { region: Region<'tcx>, kind: BorrowKind },
|
||||
|
||||
// Used as base for another place, e.g. `x` in `x.y`.
|
||||
//
|
||||
// The `Mutability` argument specifies whether the projection is being performed in order to
|
||||
// (potentially) mutate the place. For example, the projection `x.y` is marked as a mutation
|
||||
// in these cases:
|
||||
//
|
||||
// x.y = ...;
|
||||
// f(&mut x.y);
|
||||
//
|
||||
// But not in these cases:
|
||||
//
|
||||
// z = x.y;
|
||||
// f(&x.y);
|
||||
Projection(Mutability),
|
||||
|
||||
// Consumed as part of an operand
|
||||
/// Consumed as part of an operand.
|
||||
Copy,
|
||||
/// Consumed as part of an operand.
|
||||
Move,
|
||||
/// Shared borrow.
|
||||
SharedBorrow(Region<'tcx>),
|
||||
/// Shallow borrow.
|
||||
ShallowBorrow(Region<'tcx>),
|
||||
/// Unique borrow.
|
||||
UniqueBorrow(Region<'tcx>),
|
||||
/// Used as base for another place, e.g. `x` in `x.y`. Will not mutate the place.
|
||||
/// For example, the projection `x.y` is not marked as a mutation in these cases:
|
||||
///
|
||||
/// z = x.y;
|
||||
/// f(&x.y);
|
||||
///
|
||||
Projection,
|
||||
}
|
||||
|
||||
// Starting and ending a storage live range
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum MutatingUseContext<'tcx> {
|
||||
/// Appears as LHS of an assignment.
|
||||
Store,
|
||||
/// Can often be treated as a `Store`, but needs to be separate because
|
||||
/// ASM is allowed to read outputs as well, so a `Store`-`AsmOutput` sequence
|
||||
/// cannot be simplified the way a `Store`-`Store` can be.
|
||||
AsmOutput,
|
||||
/// Destination of a call.
|
||||
Call,
|
||||
/// Being dropped.
|
||||
Drop,
|
||||
/// Mutable borrow.
|
||||
Borrow(Region<'tcx>),
|
||||
/// Used as base for another place, e.g. `x` in `x.y`. Could potentially mutate the place.
|
||||
/// For example, the projection `x.y` is marked as a mutation in these cases:
|
||||
///
|
||||
/// x.y = ...;
|
||||
/// f(&mut x.y);
|
||||
///
|
||||
Projection,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum NonUseContext {
|
||||
/// Starting a storage live range.
|
||||
StorageLive,
|
||||
/// Ending a storage live range.
|
||||
StorageDead,
|
||||
|
||||
// Validation command
|
||||
/// User type annotation assertions for NLL.
|
||||
AscribeUserTy,
|
||||
/// Validation command.
|
||||
Validate,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum PlaceContext<'tcx> {
|
||||
NonMutatingUse(NonMutatingUseContext<'tcx>),
|
||||
MutatingUse(MutatingUseContext<'tcx>),
|
||||
NonUse(NonUseContext),
|
||||
}
|
||||
|
||||
impl<'tcx> PlaceContext<'tcx> {
|
||||
/// Returns true if this place context represents a drop.
|
||||
/// Returns `true` if this place context represents a drop.
|
||||
pub fn is_drop(&self) -> bool {
|
||||
match *self {
|
||||
PlaceContext::Drop => true,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this place context represents a storage live or storage dead marker.
|
||||
/// Returns `true` if this place context represents a borrow.
|
||||
pub fn is_borrow(&self) -> bool {
|
||||
match *self {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow(..)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this place context represents a storage live or storage dead marker.
|
||||
pub fn is_storage_marker(&self) -> bool {
|
||||
match *self {
|
||||
PlaceContext::StorageLive | PlaceContext::StorageDead => true,
|
||||
PlaceContext::NonUse(NonUseContext::StorageLive) |
|
||||
PlaceContext::NonUse(NonUseContext::StorageDead) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this place context represents a storage live marker.
|
||||
/// Returns `true` if this place context represents a storage live marker.
|
||||
pub fn is_storage_live_marker(&self) -> bool {
|
||||
match *self {
|
||||
PlaceContext::StorageLive => true,
|
||||
PlaceContext::NonUse(NonUseContext::StorageLive) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this place context represents a storage dead marker.
|
||||
/// Returns `true` if this place context represents a storage dead marker.
|
||||
pub fn is_storage_dead_marker(&self) -> bool {
|
||||
match *self {
|
||||
PlaceContext::StorageDead => true,
|
||||
PlaceContext::NonUse(NonUseContext::StorageDead) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this place context represents a use that potentially changes the value.
|
||||
/// Returns `true` if this place context represents a use that potentially changes the value.
|
||||
pub fn is_mutating_use(&self) -> bool {
|
||||
match *self {
|
||||
PlaceContext::Store | PlaceContext::AsmOutput | PlaceContext::Call |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Mut { .. }, .. } |
|
||||
PlaceContext::Projection(Mutability::Mut) |
|
||||
PlaceContext::Drop => true,
|
||||
|
||||
PlaceContext::Inspect |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Shared, .. } |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Shallow, .. } |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Unique, .. } |
|
||||
PlaceContext::Projection(Mutability::Not) |
|
||||
PlaceContext::Copy | PlaceContext::Move |
|
||||
PlaceContext::StorageLive | PlaceContext::StorageDead |
|
||||
PlaceContext::Validate => false,
|
||||
PlaceContext::MutatingUse(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this place context represents a use that does not change the value.
|
||||
/// Returns `true` if this place context represents a use that does not change the value.
|
||||
pub fn is_nonmutating_use(&self) -> bool {
|
||||
match *self {
|
||||
PlaceContext::Inspect |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Shared, .. } |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Shallow, .. } |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Unique, .. } |
|
||||
PlaceContext::Projection(Mutability::Not) |
|
||||
PlaceContext::Copy | PlaceContext::Move => true,
|
||||
|
||||
PlaceContext::Borrow { kind: BorrowKind::Mut { .. }, .. } | PlaceContext::Store |
|
||||
PlaceContext::AsmOutput |
|
||||
PlaceContext::Call | PlaceContext::Projection(Mutability::Mut) |
|
||||
PlaceContext::Drop | PlaceContext::StorageLive | PlaceContext::StorageDead |
|
||||
PlaceContext::Validate => false,
|
||||
PlaceContext::NonMutatingUse(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this place context represents a use.
|
||||
pub fn is_use(&self) -> bool {
|
||||
self.is_mutating_use() || self.is_nonmutating_use()
|
||||
match *self {
|
||||
PlaceContext::NonUse(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this place context represents an assignment statement.
|
||||
pub fn is_place_assignment(&self) -> bool {
|
||||
match *self {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Call) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use rustc_data_structures::bit_set::BitSet;
|
|||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use rustc::mir::{self, Location, TerminatorKind};
|
||||
use rustc::mir::visit::{Visitor, PlaceContext};
|
||||
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
|
||||
use rustc::mir::traversal;
|
||||
use rustc::ty;
|
||||
use rustc::ty::layout::LayoutOf;
|
||||
|
@ -116,7 +116,11 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
|
|||
self.not_ssa(index);
|
||||
}
|
||||
} else {
|
||||
self.visit_place(place, PlaceContext::Store, location);
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
self.visit_rvalue(rvalue, location);
|
||||
|
@ -142,7 +146,11 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
|
|||
// is not guaranteed to be statically dominated by the
|
||||
// definition of x, so x must always be in an alloca.
|
||||
if let mir::Operand::Move(ref place) = args[0] {
|
||||
self.visit_place(place, PlaceContext::Drop, location);
|
||||
self.visit_place(
|
||||
place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop),
|
||||
location
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +168,8 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
|
|||
if let mir::Place::Projection(ref proj) = *place {
|
||||
// Allow uses of projections that are ZSTs or from scalar fields.
|
||||
let is_consume = match context {
|
||||
PlaceContext::Copy | PlaceContext::Move => true,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true,
|
||||
_ => false
|
||||
};
|
||||
if is_consume {
|
||||
|
@ -190,7 +199,11 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
|
|||
|
||||
// A deref projection only reads the pointer, never needs the place.
|
||||
if let mir::ProjectionElem::Deref = proj.elem {
|
||||
return self.visit_place(&proj.base, PlaceContext::Copy, location);
|
||||
return self.visit_place(
|
||||
&proj.base,
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
|
||||
location
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,16 +215,14 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
|
|||
context: PlaceContext<'tcx>,
|
||||
location: Location) {
|
||||
match context {
|
||||
PlaceContext::Call => {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Call) => {
|
||||
self.assign(local, location);
|
||||
}
|
||||
|
||||
PlaceContext::StorageLive |
|
||||
PlaceContext::StorageDead |
|
||||
PlaceContext::Validate => {}
|
||||
PlaceContext::NonUse(_) => {}
|
||||
|
||||
PlaceContext::Copy |
|
||||
PlaceContext::Move => {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => {
|
||||
// Reads from uninitialized variables (e.g. in dead code, after
|
||||
// optimizations) require locals to be in (uninitialized) memory.
|
||||
// NB: there can be uninitialized reads of a local visited after
|
||||
|
@ -227,15 +238,19 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
PlaceContext::Inspect |
|
||||
PlaceContext::Store |
|
||||
PlaceContext::AsmOutput |
|
||||
PlaceContext::Borrow { .. } |
|
||||
PlaceContext::Projection(..) => {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow(..)) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
|
||||
self.not_ssa(local);
|
||||
}
|
||||
|
||||
PlaceContext::Drop => {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
|
||||
let ty = mir::Place::Local(local).ty(self.fx.mir, self.fx.cx.tcx);
|
||||
let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx));
|
||||
|
||||
|
|
|
@ -12,7 +12,9 @@ use borrow_check::place_ext::PlaceExt;
|
|||
use dataflow::indexes::BorrowIndex;
|
||||
use dataflow::move_paths::MoveData;
|
||||
use rustc::mir::traversal;
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::visit::{
|
||||
PlaceContext, Visitor, NonUseContext, MutatingUseContext, NonMutatingUseContext
|
||||
};
|
||||
use rustc::mir::{self, Location, Mir, Place, Local};
|
||||
use rustc::ty::{Region, TyCtxt};
|
||||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
@ -116,7 +118,7 @@ impl LocalsStateAtExit {
|
|||
|
||||
impl<'tcx> Visitor<'tcx> for HasStorageDead {
|
||||
fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) {
|
||||
if ctx == PlaceContext::StorageDead {
|
||||
if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) {
|
||||
self.0.insert(*local);
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +268,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
|
|||
|
||||
// Watch out: the use of TMP in the borrow itself
|
||||
// doesn't count as an activation. =)
|
||||
if borrow_data.reserve_location == location && context == PlaceContext::Store {
|
||||
if borrow_data.reserve_location == location &&
|
||||
context == PlaceContext::MutatingUse(MutatingUseContext::Store)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -287,10 +291,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
|
|||
borrow_data.activation_location = match context {
|
||||
// The use of TMP in a shared borrow does not
|
||||
// count as an actual activation.
|
||||
PlaceContext::Borrow { kind: mir::BorrowKind::Shared, .. }
|
||||
| PlaceContext::Borrow { kind: mir::BorrowKind::Shallow, .. } => {
|
||||
TwoPhaseActivation::NotActivated
|
||||
}
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) =>
|
||||
TwoPhaseActivation::NotActivated,
|
||||
_ => {
|
||||
// Double check: This borrow is indeed a two-phase borrow (that is,
|
||||
// we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
|
||||
|
|
|
@ -35,7 +35,7 @@ use rustc::infer::outlives::env::RegionBoundPairs;
|
|||
use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
use rustc::mir::tcx::PlaceTy;
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
|
||||
use rustc::mir::*;
|
||||
use rustc::traits::query::type_op;
|
||||
use rustc::traits::query::type_op::custom::CustomTypeOp;
|
||||
|
@ -472,9 +472,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
}
|
||||
Place::Projection(ref proj) => {
|
||||
let base_context = if context.is_mutating_use() {
|
||||
PlaceContext::Projection(Mutability::Mut)
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection)
|
||||
} else {
|
||||
PlaceContext::Projection(Mutability::Not)
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
|
||||
};
|
||||
let base_ty = self.sanitize_place(&proj.base, location, base_context);
|
||||
if let PlaceTy::Ty { ty } = base_ty {
|
||||
|
@ -488,7 +488,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
self.sanitize_projection(base_ty, &proj.elem, place, location)
|
||||
}
|
||||
};
|
||||
if let PlaceContext::Copy = context {
|
||||
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
|
||||
let tcx = self.tcx();
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: tcx.lang_items().copy_trait().unwrap(),
|
||||
|
|
|
@ -14,7 +14,6 @@ use rustc::mir::{Local, Location, Place};
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
use borrow_check::MirBorrowckCtxt;
|
||||
use util::collect_writes::is_place_assignment;
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// Walks the MIR looking for assignments to a set of locals, as part of the unused mutable
|
||||
|
@ -46,7 +45,7 @@ impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'c
|
|||
return;
|
||||
}
|
||||
|
||||
if is_place_assignment(&place_context) {
|
||||
if place_context.is_place_assignment() {
|
||||
// Propagate the Local assigned at this Location as a used mutable local variable
|
||||
for moi in &self.mbcx.move_data.loc_map[location] {
|
||||
let mpi = &self.mbcx.move_data.moves[*moi].path;
|
||||
|
|
|
@ -19,7 +19,7 @@ use rustc::hir::Node;
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::lint::builtin::{SAFE_EXTERN_STATICS, SAFE_PACKED_BORROWS, UNUSED_UNSAFE};
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::symbol::Symbol;
|
||||
|
@ -152,7 +152,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
place: &Place<'tcx>,
|
||||
context: PlaceContext<'tcx>,
|
||||
location: Location) {
|
||||
if let PlaceContext::Borrow { .. } = context {
|
||||
if context.is_borrow() {
|
||||
if util::is_disaligned(self.tcx, self.mir, self.param_env, place) {
|
||||
let source_info = self.source_info;
|
||||
let lint_root =
|
||||
|
@ -193,9 +193,11 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
}
|
||||
ty::Adt(adt, _) => {
|
||||
if adt.is_union() {
|
||||
if context == PlaceContext::Store ||
|
||||
context == PlaceContext::AsmOutput ||
|
||||
context == PlaceContext::Drop
|
||||
if context == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
|
||||
context == PlaceContext::MutatingUse(MutatingUseContext::Drop) ||
|
||||
context == PlaceContext::MutatingUse(
|
||||
MutatingUseContext::AsmOutput
|
||||
)
|
||||
{
|
||||
let elem_ty = match elem {
|
||||
&ProjectionElem::Field(_, ty) => ty,
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc::hir::def::Def;
|
|||
use rustc::mir::{Constant, Location, Place, Mir, Operand, Rvalue, Local};
|
||||
use rustc::mir::{NullOp, UnOp, StatementKind, Statement, BasicBlock, LocalKind};
|
||||
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
|
||||
use rustc::mir::visit::{Visitor, PlaceContext};
|
||||
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
|
||||
use rustc::mir::interpret::{
|
||||
ConstEvalErr, EvalErrorKind, Scalar, GlobalId, EvalResult,
|
||||
};
|
||||
|
@ -533,17 +533,18 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
|
|||
// Constants must have at most one write
|
||||
// FIXME(oli-obk): we could be more powerful here, if the multiple writes
|
||||
// only occur in independent execution paths
|
||||
Store => if self.found_assignment[local] {
|
||||
MutatingUse(MutatingUseContext::Store) => if self.found_assignment[local] {
|
||||
self.can_const_prop[local] = false;
|
||||
} else {
|
||||
self.found_assignment[local] = true
|
||||
},
|
||||
// Reading constants is allowed an arbitrary number of times
|
||||
Copy | Move |
|
||||
StorageDead | StorageLive |
|
||||
Validate |
|
||||
Projection(_) |
|
||||
Inspect => {},
|
||||
NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||
NonMutatingUse(NonMutatingUseContext::Move) |
|
||||
NonMutatingUse(NonMutatingUseContext::Inspect) |
|
||||
NonMutatingUse(NonMutatingUseContext::Projection) |
|
||||
MutatingUse(MutatingUseContext::Projection) |
|
||||
NonUse(_) => {},
|
||||
_ => self.can_const_prop[local] = false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
//! move analysis runs after promotion on broken MIR.
|
||||
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
|
||||
use rustc::mir::visit::{PlaceContext, MutatingUseContext, MutVisitor, Visitor};
|
||||
use rustc::mir::traversal::ReversePostorder;
|
||||
use rustc::ty::TyCtxt;
|
||||
use syntax_pos::Span;
|
||||
|
@ -53,6 +53,7 @@ pub enum TempState {
|
|||
|
||||
impl TempState {
|
||||
pub fn is_promotable(&self) -> bool {
|
||||
debug!("is_promotable: self={:?}", self);
|
||||
if let TempState::Defined { uses, .. } = *self {
|
||||
uses > 0
|
||||
} else {
|
||||
|
@ -88,6 +89,7 @@ impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
|
|||
&index: &Local,
|
||||
context: PlaceContext<'tcx>,
|
||||
location: Location) {
|
||||
debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location);
|
||||
// We're only interested in temporaries
|
||||
if self.mir.local_kind(index) != LocalKind::Temp {
|
||||
return;
|
||||
|
@ -95,17 +97,22 @@ impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
|
|||
|
||||
// Ignore drops, if the temp gets promoted,
|
||||
// then it's constant and thus drop is noop.
|
||||
// Storage live ranges are also irrelevant.
|
||||
if context.is_drop() || context.is_storage_marker() {
|
||||
// Non-uses are also irrelevent.
|
||||
if context.is_drop() || !context.is_use() {
|
||||
debug!(
|
||||
"visit_local: context.is_drop={:?} context.is_use={:?}",
|
||||
context.is_drop(), context.is_use(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let temp = &mut self.temps[index];
|
||||
debug!("visit_local: temp={:?}", temp);
|
||||
if *temp == TempState::Undefined {
|
||||
match context {
|
||||
PlaceContext::Store |
|
||||
PlaceContext::AsmOutput |
|
||||
PlaceContext::Call => {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Call) => {
|
||||
*temp = TempState::Defined {
|
||||
location,
|
||||
uses: 0
|
||||
|
@ -117,10 +124,8 @@ impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
|
|||
} else if let TempState::Defined { ref mut uses, .. } = *temp {
|
||||
// We always allow borrows, even mutable ones, as we need
|
||||
// to promote mutable borrows of some ZSTs e.g. `&mut []`.
|
||||
let allowed_use = match context {
|
||||
PlaceContext::Borrow {..} => true,
|
||||
_ => context.is_nonmutating_use()
|
||||
};
|
||||
let allowed_use = context.is_borrow() || context.is_nonmutating_use();
|
||||
debug!("visit_local: allowed_use={:?}", allowed_use);
|
||||
if allowed_use {
|
||||
*uses += 1;
|
||||
return;
|
||||
|
|
|
@ -26,7 +26,7 @@ use rustc::ty::cast::CastTy;
|
|||
use rustc::ty::query::Providers;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::traversal::ReversePostorder;
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use syntax::ast::LitKind;
|
||||
|
@ -84,7 +84,7 @@ impl<'a, 'tcx> Qualif {
|
|||
}
|
||||
|
||||
/// What kind of item we are in.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum Mode {
|
||||
Const,
|
||||
Static,
|
||||
|
@ -271,7 +271,11 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||
// This must be an explicit assignment.
|
||||
_ => {
|
||||
// Catch more errors in the destination.
|
||||
self.visit_place(dest, PlaceContext::Store, location);
|
||||
self.visit_place(
|
||||
dest,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
location
|
||||
);
|
||||
self.statement_like();
|
||||
}
|
||||
}
|
||||
|
@ -383,6 +387,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||
// Collect all the temps we need to promote.
|
||||
let mut promoted_temps = BitSet::new_empty(self.temp_promotion_state.len());
|
||||
|
||||
debug!("qualify_const: promotion_candidates={:?}", self.promotion_candidates);
|
||||
for candidate in &self.promotion_candidates {
|
||||
match *candidate {
|
||||
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
|
||||
|
@ -414,6 +419,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
&local: &Local,
|
||||
_: PlaceContext<'tcx>,
|
||||
_: Location) {
|
||||
debug!("visit_local: local={:?}", local);
|
||||
let kind = self.mir.local_kind(local);
|
||||
match kind {
|
||||
LocalKind::ReturnPointer => {
|
||||
|
@ -435,6 +441,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
if !self.temp_promotion_state[local].is_promotable() {
|
||||
debug!("visit_local: (not promotable) local={:?}", local);
|
||||
self.add(Qualif::NOT_PROMOTABLE);
|
||||
}
|
||||
|
||||
|
@ -451,6 +458,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
place: &Place<'tcx>,
|
||||
context: PlaceContext<'tcx>,
|
||||
location: Location) {
|
||||
debug!("visit_place: place={:?} context={:?} location={:?}", place, context, location);
|
||||
match *place {
|
||||
Place::Local(ref local) => self.visit_local(local, context, location),
|
||||
Place::Promoted(_) => bug!("promoting already promoted MIR"),
|
||||
|
@ -557,6 +565,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
|
||||
debug!("visit_operand: operand={:?} location={:?}", operand, location);
|
||||
self.super_operand(operand, location);
|
||||
|
||||
match *operand {
|
||||
|
@ -591,6 +600,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
debug!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
|
||||
// Recurse through operands and places.
|
||||
if let Rvalue::Ref(region, kind, ref place) = *rvalue {
|
||||
let mut is_reborrow = false;
|
||||
|
@ -604,10 +614,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
if is_reborrow {
|
||||
self.super_place(place, PlaceContext::Borrow {
|
||||
region,
|
||||
kind
|
||||
}, location);
|
||||
let ctx = match kind {
|
||||
BorrowKind::Shared =>
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(region)),
|
||||
BorrowKind::Shallow =>
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(region)),
|
||||
BorrowKind::Unique =>
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(region)),
|
||||
BorrowKind::Mut { .. } =>
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow(region)),
|
||||
};
|
||||
self.super_place(place, ctx, location);
|
||||
} else {
|
||||
self.super_rvalue(rvalue, location);
|
||||
}
|
||||
|
@ -696,6 +713,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
debug!("visit_rvalue: forbidden_mut={:?}", forbidden_mut);
|
||||
if forbidden_mut {
|
||||
self.add(Qualif::NOT_CONST);
|
||||
} else {
|
||||
|
@ -709,15 +727,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
place = &proj.base;
|
||||
}
|
||||
debug!("visit_rvalue: place={:?}", place);
|
||||
if let Place::Local(local) = *place {
|
||||
if self.mir.local_kind(local) == LocalKind::Temp {
|
||||
debug!("visit_rvalue: local={:?}", local);
|
||||
if let Some(qualif) = self.local_qualif[local] {
|
||||
// `forbidden_mut` is false, so we can safely ignore
|
||||
// `MUTABLE_INTERIOR` from the local's qualifications.
|
||||
// This allows borrowing fields which don't have
|
||||
// `MUTABLE_INTERIOR`, from a type that does, e.g.:
|
||||
// `let _: &'static _ = &(Cell::new(1), 2).1;`
|
||||
debug!("visit_rvalue: qualif={:?}", qualif);
|
||||
if (qualif - Qualif::MUTABLE_INTERIOR).is_empty() {
|
||||
debug!("visit_rvalue: candidate={:?}", candidate);
|
||||
self.promotion_candidates.push(candidate);
|
||||
}
|
||||
}
|
||||
|
@ -815,6 +837,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
bb: BasicBlock,
|
||||
kind: &TerminatorKind<'tcx>,
|
||||
location: Location) {
|
||||
debug!("visit_terminator_kind: bb={:?} kind={:?} location={:?}", bb, kind, location);
|
||||
if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind {
|
||||
self.visit_operand(func, location);
|
||||
|
||||
|
@ -972,6 +995,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
let candidate = Candidate::Argument { bb, index: i };
|
||||
if is_shuffle && i == 2 {
|
||||
if this.qualif.is_empty() {
|
||||
debug!("visit_terminator_kind: candidate={:?}", candidate);
|
||||
this.promotion_candidates.push(candidate);
|
||||
} else {
|
||||
span_err!(this.tcx.sess, this.span, E0526,
|
||||
|
@ -998,6 +1022,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
// We can error out with a hard error if the argument is not
|
||||
// constant here.
|
||||
if (this.qualif - Qualif::NOT_PROMOTABLE).is_empty() {
|
||||
debug!("visit_terminator_kind: candidate={:?}", candidate);
|
||||
this.promotion_candidates.push(candidate);
|
||||
} else {
|
||||
this.tcx.sess.span_err(this.span,
|
||||
|
@ -1075,6 +1100,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
dest: &Place<'tcx>,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
location: Location) {
|
||||
debug!("visit_assign: dest={:?} rvalue={:?} location={:?}", dest, rvalue, location);
|
||||
self.visit_rvalue(rvalue, location);
|
||||
|
||||
// Check the allowed const fn argument forms.
|
||||
|
@ -1123,10 +1149,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_source_info(&mut self, source_info: &SourceInfo) {
|
||||
debug!("visit_source_info: source_info={:?}", source_info);
|
||||
self.span = source_info.span;
|
||||
}
|
||||
|
||||
fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, location: Location) {
|
||||
debug!("visit_statement: bb={:?} statement={:?} location={:?}", bb, statement, location);
|
||||
self.nest(|this| {
|
||||
this.visit_source_info(&statement.source_info);
|
||||
match statement.kind {
|
||||
|
@ -1150,6 +1178,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
bb: BasicBlock,
|
||||
terminator: &Terminator<'tcx>,
|
||||
location: Location) {
|
||||
debug!("visit_terminator: bb={:?} terminator={:?} location={:?}", bb, terminator, location);
|
||||
self.nest(|this| this.super_terminator(bb, terminator, location));
|
||||
}
|
||||
}
|
||||
|
@ -1216,6 +1245,7 @@ impl MirPass for QualifyAndPromoteConstants {
|
|||
hir::BodyOwnerKind::Static(hir::MutMutable) => Mode::StaticMut,
|
||||
};
|
||||
|
||||
debug!("run_pass: mode={:?}", mode);
|
||||
if mode == Mode::Fn || mode == Mode::ConstFn {
|
||||
// This is ugly because Qualifier holds onto mir,
|
||||
// which can't be mutated until its scope ends.
|
||||
|
@ -1258,6 +1288,7 @@ impl MirPass for QualifyAndPromoteConstants {
|
|||
// In `const` and `static` everything without `StorageDead`
|
||||
// is `'static`, we don't have to create promoted MIR fragments,
|
||||
// just remove `Drop` and `StorageDead` on "promoted" locals.
|
||||
debug!("run_pass: promoted_temps={:?}", promoted_temps);
|
||||
for block in mir.basic_blocks_mut() {
|
||||
block.statements.retain(|statement| {
|
||||
match statement.kind {
|
||||
|
|
|
@ -331,8 +331,10 @@ struct DeclMarker {
|
|||
|
||||
impl<'tcx> Visitor<'tcx> for DeclMarker {
|
||||
fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) {
|
||||
// ignore these altogether, they get removed along with their otherwise unused decls.
|
||||
if ctx != PlaceContext::StorageLive && ctx != PlaceContext::StorageDead {
|
||||
// Ignore storage markers altogether, they get removed along with their otherwise unused
|
||||
// decls.
|
||||
// FIXME: Extend this to all non-uses.
|
||||
if !ctx.is_storage_marker() {
|
||||
self.locals.insert(*local);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
use rustc::ty;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::visit::{Visitor, PlaceContext};
|
||||
use rustc::mir::visit::{Visitor, PlaceContext, NonUseContext};
|
||||
use transform::{MirPass, MirSource};
|
||||
use util::patch::MirPatch;
|
||||
use rustc_data_structures::indexed_vec::{IndexVec};
|
||||
|
@ -316,8 +316,8 @@ impl<'tcx> Visitor<'tcx> for RestoreDataCollector {
|
|||
location: Location) {
|
||||
let local_use = &mut self.locals_use[*local];
|
||||
match context {
|
||||
PlaceContext::StorageLive => local_use.alive = Some(location),
|
||||
PlaceContext::StorageDead => local_use.dead = Some(location),
|
||||
PlaceContext::NonUse(NonUseContext::StorageLive) => local_use.alive = Some(location),
|
||||
PlaceContext::NonUse(NonUseContext::StorageDead) => local_use.dead = Some(location),
|
||||
_ => {
|
||||
local_use.use_count += 1;
|
||||
if local_use.first_use.is_none() {
|
||||
|
|
|
@ -43,24 +43,8 @@ impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
|
|||
return;
|
||||
}
|
||||
|
||||
if is_place_assignment(&place_context) {
|
||||
if place_context.is_place_assignment() {
|
||||
self.locations.push(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this place context represents an assignment statement
|
||||
crate fn is_place_assignment(place_context: &PlaceContext) -> bool {
|
||||
match *place_context {
|
||||
PlaceContext::Store | PlaceContext::Call | PlaceContext::AsmOutput => true,
|
||||
PlaceContext::Drop
|
||||
| PlaceContext::Inspect
|
||||
| PlaceContext::Borrow { .. }
|
||||
| PlaceContext::Projection(..)
|
||||
| PlaceContext::Copy
|
||||
| PlaceContext::Move
|
||||
| PlaceContext::StorageLive
|
||||
| PlaceContext::StorageDead
|
||||
| PlaceContext::Validate => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,9 @@
|
|||
//! generator yield points, all pre-existing references are invalidated, so this
|
||||
//! doesn't matter).
|
||||
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::visit::{
|
||||
PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext, NonUseContext,
|
||||
};
|
||||
use rustc::mir::Local;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{item_path, TyCtxt};
|
||||
|
@ -161,10 +163,10 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option<DefUse> {
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// DEFS
|
||||
|
||||
PlaceContext::Store |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store) |
|
||||
|
||||
// This is potentially both a def and a use...
|
||||
PlaceContext::AsmOutput |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
|
||||
|
||||
// We let Call define the result in both the success and
|
||||
// unwind cases. This is not really correct, however it
|
||||
|
@ -172,12 +174,12 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option<DefUse> {
|
|||
// generate MIR. To do things properly, we would apply
|
||||
// the def in call only to the input from the success
|
||||
// path and not the unwind path. -nmatsakis
|
||||
PlaceContext::Call |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Call) |
|
||||
|
||||
// Storage live and storage dead aren't proper defines, but we can ignore
|
||||
// values that come before them.
|
||||
PlaceContext::StorageLive |
|
||||
PlaceContext::StorageDead => Some(DefUse::Def),
|
||||
PlaceContext::NonUse(NonUseContext::StorageLive) |
|
||||
PlaceContext::NonUse(NonUseContext::StorageDead) => Some(DefUse::Def),
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// REGULAR USES
|
||||
|
@ -186,18 +188,23 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option<DefUse> {
|
|||
// purposes of NLL, these are special in that **all** the
|
||||
// lifetimes appearing in the variable must be live for each regular use.
|
||||
|
||||
PlaceContext::Projection(..) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection) |
|
||||
|
||||
// Borrows only consider their local used at the point of the borrow.
|
||||
// This won't affect the results since we use this analysis for generators
|
||||
// and we only care about the result at suspension points. Borrows cannot
|
||||
// cross suspension points so this behavior is unproblematic.
|
||||
PlaceContext::Borrow { .. } |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow(..)) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) |
|
||||
|
||||
PlaceContext::Inspect |
|
||||
PlaceContext::Copy |
|
||||
PlaceContext::Move |
|
||||
PlaceContext::Validate =>
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
|
||||
PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
|
||||
PlaceContext::NonUse(NonUseContext::Validate) =>
|
||||
Some(DefUse::Use),
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -208,7 +215,7 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option<DefUse> {
|
|||
// uses in drop are special because `#[may_dangle]`
|
||||
// attributes can affect whether lifetimes must be live.
|
||||
|
||||
PlaceContext::Drop =>
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
|
||||
Some(DefUse::Drop),
|
||||
}
|
||||
}
|
||||
|
|
21
src/test/ui/nll/issue-55288.rs
Normal file
21
src/test/ui/nll/issue-55288.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
// 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.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
// run-pass
|
||||
|
||||
struct Slice(&'static [&'static [u8]]);
|
||||
|
||||
static MAP: Slice = Slice(&[
|
||||
b"CloseEvent" as &'static [u8],
|
||||
]);
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue