From 532080cfcccdfd853008c4452b283130b544c675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 17 Dec 2023 00:00:00 +0000 Subject: [PATCH] Stricter check for a use of locals without storage --- compiler/rustc_mir_transform/src/lint.rs | 28 ++++++++++++++-------- tests/ui/mir/lint/no-storage.rs | 30 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 tests/ui/mir/lint/no-storage.rs diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs index d7380b4e04b..3940d0ddbf3 100644 --- a/compiler/rustc_mir_transform/src/lint.rs +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -use rustc_mir_dataflow::impls::MaybeStorageLive; +use rustc_mir_dataflow::impls::{MaybeStorageDead, MaybeStorageLive}; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{Analysis, ResultsCursor}; use std::borrow::Cow; @@ -13,7 +13,13 @@ pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) { let reachable_blocks = traversal::reachable_as_bitset(body); let always_live_locals = &always_storage_live_locals(body); - let storage_liveness = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) + + let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) + .into_engine(tcx, body) + .iterate_to_fixpoint() + .into_results_cursor(body); + + let maybe_storage_dead = MaybeStorageDead::new(Cow::Borrowed(always_live_locals)) .into_engine(tcx, body) .iterate_to_fixpoint() .into_results_cursor(body); @@ -25,7 +31,8 @@ pub fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String) { is_fn_like: tcx.def_kind(body.source.def_id()).is_fn_like(), always_live_locals, reachable_blocks, - storage_liveness, + maybe_storage_live, + maybe_storage_dead, } .visit_body(body); } @@ -37,7 +44,8 @@ struct Lint<'a, 'tcx> { is_fn_like: bool, always_live_locals: &'a BitSet, reachable_blocks: BitSet, - storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'a>>, + maybe_storage_live: ResultsCursor<'a, 'tcx, MaybeStorageLive<'a>>, + maybe_storage_dead: ResultsCursor<'a, 'tcx, MaybeStorageDead<'a>>, } impl<'a, 'tcx> Lint<'a, 'tcx> { @@ -60,8 +68,8 @@ fn fail(&self, location: Location, msg: impl AsRef) { impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { if self.reachable_blocks.contains(location.block) && context.is_use() { - self.storage_liveness.seek_after_primary_effect(location); - if !self.storage_liveness.get().contains(local) { + self.maybe_storage_dead.seek_after_primary_effect(location); + if self.maybe_storage_dead.get().contains(local) { self.fail(location, format!("use of local {local:?}, which has no storage here")); } } @@ -71,8 +79,8 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { match statement.kind { StatementKind::StorageLive(local) => { if self.reachable_blocks.contains(location.block) { - self.storage_liveness.seek_before_primary_effect(location); - if self.storage_liveness.get().contains(local) { + self.maybe_storage_live.seek_before_primary_effect(location); + if self.maybe_storage_live.get().contains(local) { self.fail( location, format!("StorageLive({local:?}) which already has storage here"), @@ -90,8 +98,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location match terminator.kind { TerminatorKind::Return => { if self.is_fn_like && self.reachable_blocks.contains(location.block) { - self.storage_liveness.seek_after_primary_effect(location); - for local in self.storage_liveness.get().iter() { + self.maybe_storage_live.seek_after_primary_effect(location); + for local in self.maybe_storage_live.get().iter() { if !self.always_live_locals.contains(local) { self.fail( location, diff --git a/tests/ui/mir/lint/no-storage.rs b/tests/ui/mir/lint/no-storage.rs new file mode 100644 index 00000000000..246a0b34e5d --- /dev/null +++ b/tests/ui/mir/lint/no-storage.rs @@ -0,0 +1,30 @@ +// compile-flags: -Zlint-mir --crate-type=lib -Ztreat-err-as-bug +// failure-status: 101 +// dont-check-compiler-stderr +// regex-error-pattern: use of local .*, which has no storage here +#![feature(custom_mir, core_intrinsics)] +extern crate core; +use core::intrinsics::mir::*; + +#[custom_mir(dialect = "built")] +pub fn f(a: bool) { + mir!( + let b: (); + { + match a { true => bb1, _ => bb2 } + } + bb1 = { + StorageLive(b); + Goto(bb3) + } + bb2 = { + Goto(bb3) + } + bb3 = { + b = (); + RET = b; + StorageDead(b); + Return() + } + ) +}