Lint overlapping assignments in MIR.
This commit is contained in:
parent
ce6daf3d5a
commit
912785d966
4 changed files with 53 additions and 28 deletions
|
|
@ -1475,3 +1475,20 @@ impl PlaceContext {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Small utility to visit places and locals without manually implementing a full visitor.
|
||||
pub struct VisitPlacesWith<F>(pub F);
|
||||
|
||||
impl<'tcx, F> Visitor<'tcx> for VisitPlacesWith<F>
|
||||
where
|
||||
F: FnMut(Place<'tcx>, PlaceContext),
|
||||
{
|
||||
fn visit_local(&mut self, local: Local, ctxt: PlaceContext, _: Location) {
|
||||
(self.0)(local.into(), ctxt);
|
||||
}
|
||||
|
||||
fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, location: Location) {
|
||||
(self.0)(*place, ctxt);
|
||||
self.visit_projection(place.as_ref(), ctxt, location);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ use rustc_data_structures::union_find::UnionFind;
|
|||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_index::interval::SparseIntervalMatrix;
|
||||
use rustc_index::{IndexVec, newtype_index};
|
||||
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, VisitPlacesWith, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_mir_dataflow::impls::{DefUse, MaybeLiveLocals};
|
||||
|
|
@ -503,22 +503,6 @@ impl TwoStepIndex {
|
|||
}
|
||||
}
|
||||
|
||||
struct VisitPlacesWith<F>(F);
|
||||
|
||||
impl<'tcx, F> Visitor<'tcx> for VisitPlacesWith<F>
|
||||
where
|
||||
F: FnMut(Place<'tcx>, PlaceContext),
|
||||
{
|
||||
fn visit_local(&mut self, local: Local, ctxt: PlaceContext, _: Location) {
|
||||
(self.0)(local.into(), ctxt);
|
||||
}
|
||||
|
||||
fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, location: Location) {
|
||||
(self.0)(*place, ctxt);
|
||||
self.visit_projection(place.as_ref(), ctxt, location);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add points depending on the result of the given dataflow analysis.
|
||||
fn save_as_intervals<'tcx>(
|
||||
elements: &DenseLocationMap,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::borrow::Cow;
|
|||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc_middle::mir::visit::{PlaceContext, VisitPlacesWith, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_mir_dataflow::impls::{MaybeStorageDead, MaybeStorageLive, always_storage_live_locals};
|
||||
|
|
@ -79,15 +79,39 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
|
|||
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box (dest, rvalue)) => {
|
||||
if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue {
|
||||
// The sides of an assignment must not alias. Currently this just checks whether
|
||||
// the places are identical.
|
||||
if dest == src {
|
||||
self.fail(
|
||||
location,
|
||||
"encountered `Assign` statement with overlapping memory",
|
||||
);
|
||||
}
|
||||
let forbid_aliasing = match rvalue {
|
||||
Rvalue::Use(..)
|
||||
| Rvalue::CopyForDeref(..)
|
||||
| Rvalue::Repeat(..)
|
||||
| Rvalue::Aggregate(..)
|
||||
| Rvalue::Cast(..)
|
||||
| Rvalue::ShallowInitBox(..)
|
||||
| Rvalue::WrapUnsafeBinder(..) => true,
|
||||
Rvalue::ThreadLocalRef(..)
|
||||
| Rvalue::NullaryOp(..)
|
||||
| Rvalue::UnaryOp(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::Ref(..)
|
||||
| Rvalue::RawPtr(..)
|
||||
| Rvalue::Discriminant(..) => false,
|
||||
};
|
||||
// The sides of an assignment must not alias.
|
||||
if forbid_aliasing {
|
||||
VisitPlacesWith(|src: Place<'tcx>, _| {
|
||||
if *dest == src
|
||||
|| (dest.local == src.local
|
||||
&& !dest.is_indirect()
|
||||
&& !src.is_indirect())
|
||||
{
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"encountered `{statement:?}` statement with overlapping memory"
|
||||
),
|
||||
);
|
||||
}
|
||||
})
|
||||
.visit_rvalue(rvalue, location);
|
||||
}
|
||||
}
|
||||
StatementKind::StorageLive(local) => {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ pub fn main() {
|
|||
let a: [u8; 1024];
|
||||
{
|
||||
a = a; //~ ERROR broken MIR
|
||||
//~^ ERROR encountered `Assign` statement with overlapping memory
|
||||
//~^ ERROR encountered `_1 = copy _1` statement with overlapping memory
|
||||
Return()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue