1
Fork 0

Allow references to interior mutable data behind a feature gate

This commit is contained in:
oli 2020-12-27 17:33:56 +00:00
parent a609fb45ef
commit 0b841846ba
23 changed files with 171 additions and 41 deletions

View file

@ -3,6 +3,7 @@
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorReported};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, HirId, LangItem};
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
@ -188,6 +189,9 @@ pub struct Validator<'mir, 'tcx> {
/// The span of the current statement.
span: Span,
/// A set that stores for each local whether it has a `StorageDead` for it somewhere.
local_has_storage_dead: Option<BitSet<Local>>,
error_emitted: Option<ErrorReported>,
secondary_errors: Vec<Diagnostic>,
}
@ -206,6 +210,7 @@ impl Validator<'mir, 'tcx> {
span: ccx.body.span,
ccx,
qualifs: Default::default(),
local_has_storage_dead: None,
error_emitted: None,
secondary_errors: Vec::new(),
}
@ -282,6 +287,27 @@ impl Validator<'mir, 'tcx> {
}
}
fn local_has_storage_dead(&mut self, local: Local) -> bool {
let ccx = self.ccx;
self.local_has_storage_dead
.get_or_insert_with(|| {
struct StorageDeads {
locals: BitSet<Local>,
}
impl Visitor<'tcx> for StorageDeads {
fn visit_statement(&mut self, stmt: &Statement<'tcx>, _: Location) {
if let StatementKind::StorageDead(l) = stmt.kind {
self.locals.insert(l);
}
}
}
let mut v = StorageDeads { locals: BitSet::new_empty(ccx.body.local_decls.len()) };
v.visit_body(ccx.body);
v.locals
})
.contains(local)
}
pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
self.qualifs.in_return_place(self.ccx, self.error_emitted)
}
@ -556,7 +582,13 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
);
if borrowed_place_has_mut_interior {
self.check_op(ops::CellBorrow);
// Locals without StorageDead follow the "trailing expression" rule, meaning
// they are essentially anonymous static items themselves.
if self.local_has_storage_dead(place.local) {
self.check_op(ops::CellBorrowBehindRef);
} else {
self.check_op(ops::CellBorrow);
}
}
}