Skip to content

Commit acf0615

Browse files
committed
Lint overlapping assignments in MIR.
1 parent b50f345 commit acf0615

File tree

4 files changed

+54
-28
lines changed

4 files changed

+54
-28
lines changed

compiler/rustc_middle/src/mir/visit.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,3 +1483,20 @@ impl PlaceContext {
14831483
}
14841484
}
14851485
}
1486+
1487+
/// Small utility to visit places and locals without manually implementing a full visitor.
1488+
pub struct VisitPlacesWith<F>(pub F);
1489+
1490+
impl<'tcx, F> Visitor<'tcx> for VisitPlacesWith<F>
1491+
where
1492+
F: FnMut(Place<'tcx>, PlaceContext),
1493+
{
1494+
fn visit_local(&mut self, local: Local, ctxt: PlaceContext, _: Location) {
1495+
(self.0)(local.into(), ctxt);
1496+
}
1497+
1498+
fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, location: Location) {
1499+
(self.0)(*place, ctxt);
1500+
self.visit_projection(place.as_ref(), ctxt, location);
1501+
}
1502+
}

compiler/rustc_mir_transform/src/dest_prop.rs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ use rustc_data_structures::union_find::UnionFind;
141141
use rustc_index::bit_set::DenseBitSet;
142142
use rustc_index::interval::SparseIntervalMatrix;
143143
use rustc_index::{IndexVec, newtype_index};
144-
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
144+
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, VisitPlacesWith, Visitor};
145145
use rustc_middle::mir::*;
146146
use rustc_middle::ty::TyCtxt;
147147
use rustc_mir_dataflow::impls::{DefUse, MaybeLiveLocals};
@@ -511,22 +511,6 @@ impl TwoStepIndex {
511511
}
512512
}
513513

514-
struct VisitPlacesWith<F>(F);
515-
516-
impl<'tcx, F> Visitor<'tcx> for VisitPlacesWith<F>
517-
where
518-
F: FnMut(Place<'tcx>, PlaceContext),
519-
{
520-
fn visit_local(&mut self, local: Local, ctxt: PlaceContext, _: Location) {
521-
(self.0)(local.into(), ctxt);
522-
}
523-
524-
fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, location: Location) {
525-
(self.0)(*place, ctxt);
526-
self.visit_projection(place.as_ref(), ctxt, location);
527-
}
528-
}
529-
530514
/// Add points depending on the result of the given dataflow analysis.
531515
fn save_as_intervals<'tcx>(
532516
elements: &DenseLocationMap,

compiler/rustc_mir_transform/src/lint.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::borrow::Cow;
66

77
use rustc_data_structures::fx::FxHashSet;
88
use rustc_index::bit_set::DenseBitSet;
9-
use rustc_middle::mir::visit::{PlaceContext, Visitor};
9+
use rustc_middle::mir::visit::{PlaceContext, VisitPlacesWith, Visitor};
1010
use rustc_middle::mir::*;
1111
use rustc_middle::ty::TyCtxt;
1212
use rustc_mir_dataflow::impls::{MaybeStorageDead, MaybeStorageLive, always_storage_live_locals};
@@ -79,15 +79,40 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
7979
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
8080
match &statement.kind {
8181
StatementKind::Assign(box (dest, rvalue)) => {
82-
if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue {
83-
// The sides of an assignment must not alias. Currently this just checks whether
84-
// the places are identical.
85-
if dest == src {
86-
self.fail(
87-
location,
88-
"encountered `Assign` statement with overlapping memory",
89-
);
90-
}
82+
let forbid_aliasing = match rvalue {
83+
Rvalue::Use(..)
84+
| Rvalue::CopyForDeref(..)
85+
| Rvalue::Repeat(..)
86+
| Rvalue::Aggregate(..)
87+
| Rvalue::Cast(..)
88+
| Rvalue::ShallowInitBox(..)
89+
| Rvalue::WrapUnsafeBinder(..) => true,
90+
Rvalue::ThreadLocalRef(..)
91+
| Rvalue::NullaryOp(..)
92+
| Rvalue::UnaryOp(..)
93+
| Rvalue::BinaryOp(..)
94+
| Rvalue::Ref(..)
95+
| Rvalue::RawPtr(..)
96+
| Rvalue::Len(..)
97+
| Rvalue::Discriminant(..) => false,
98+
};
99+
// The sides of an assignment must not alias.
100+
if forbid_aliasing {
101+
VisitPlacesWith(|src: Place<'tcx>, _| {
102+
if *dest == src
103+
|| (dest.local == src.local
104+
&& !dest.is_indirect()
105+
&& !src.is_indirect())
106+
{
107+
self.fail(
108+
location,
109+
format!(
110+
"encountered `{statement:?}` statement with overlapping memory"
111+
),
112+
);
113+
}
114+
})
115+
.visit_rvalue(rvalue, location);
91116
}
92117
}
93118
StatementKind::StorageLive(local) => {

tests/ui/mir/lint/assignment-overlap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub fn main() {
1313
let a: [u8; 1024];
1414
{
1515
a = a; //~ ERROR broken MIR
16-
//~^ ERROR encountered `Assign` statement with overlapping memory
16+
//~^ ERROR encountered `_1 = copy _1` statement with overlapping memory
1717
Return()
1818
}
1919
}

0 commit comments

Comments
 (0)