Prevent registration inside references if target is !Freeze

This commit is contained in:
Jannis Christopher Köhl 2022-10-07 00:09:36 +02:00
parent 4478a87018
commit 111324e17c
3 changed files with 41 additions and 20 deletions

View file

@ -72,6 +72,7 @@ use rustc_index::vec::IndexVec;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::DUMMY_SP;
use rustc_target::abi::VariantIdx;
use crate::{
@ -550,7 +551,7 @@ pub struct Map {
}
impl Map {
pub fn new() -> Self {
fn new() -> Self {
Self {
locals: IndexVec::new(),
projections: FxHashMap::default(),
@ -559,16 +560,27 @@ impl Map {
}
}
/// Register all places with suitable types up to a certain derefence depth (to prevent cycles).
pub fn register_with_filter<'tcx>(
/// Register all suitable places with matching types (up to a certain depth).
pub fn from_filter<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
filter: impl FnMut(Ty<'tcx>) -> bool,
) -> Self {
let mut map = Self::new();
map.register_with_filter(tcx, body, 3, filter);
map
}
fn register_with_filter<'tcx>(
&mut self,
tcx: TyCtxt<'tcx>,
source: &impl HasLocalDecls<'tcx>,
body: &Body<'tcx>,
max_derefs: u32,
mut filter: impl FnMut(Ty<'tcx>) -> bool,
) {
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
let mut projection = Vec::new();
for (local, decl) in source.local_decls().iter_enumerated() {
for (local, decl) in body.local_decls.iter_enumerated() {
self.register_with_filter_rec(
tcx,
max_derefs,
@ -576,6 +588,7 @@ impl Map {
&mut projection,
decl.ty,
&mut filter,
param_env,
);
}
}
@ -588,16 +601,28 @@ impl Map {
projection: &mut Vec<PlaceElem<'tcx>>,
ty: Ty<'tcx>,
filter: &mut impl FnMut(Ty<'tcx>) -> bool,
param_env: ty::ParamEnv<'tcx>,
) {
if filter(ty) {
// This might fail if `ty` is not scalar.
let _ = self.register_with_ty(local, projection, ty);
}
if max_derefs > 0 {
if let Some(ty::TypeAndMut { ty, .. }) = ty.builtin_deref(false) {
projection.push(PlaceElem::Deref);
self.register_with_filter_rec(tcx, max_derefs - 1, local, projection, ty, filter);
projection.pop();
if let Some(ty::TypeAndMut { ty: deref_ty, .. }) = ty.builtin_deref(false) {
// References can only be tracked if the target is `!Freeze`.
if deref_ty.is_freeze(tcx.at(DUMMY_SP), param_env) {
projection.push(PlaceElem::Deref);
self.register_with_filter_rec(
tcx,
max_derefs - 1,
local,
projection,
deref_ty,
filter,
param_env,
);
projection.pop();
}
}
}
iter_fields(ty, tcx, |variant, field, ty| {
@ -606,7 +631,9 @@ impl Map {
return;
}
projection.push(PlaceElem::Field(field, ty));
self.register_with_filter_rec(tcx, max_derefs, local, projection, ty, filter);
self.register_with_filter_rec(
tcx, max_derefs, local, projection, ty, filter, param_env,
);
projection.pop();
});
}
@ -639,7 +666,8 @@ impl Map {
Ok(index)
}
pub fn register<'tcx>(
#[allow(unused)]
fn register<'tcx>(
&mut self,
local: Local,
projection: &[PlaceElem<'tcx>],
@ -671,12 +699,6 @@ impl Map {
return Err(());
}
if !ty.is_trivially_freeze() {
// Due to the way we deal with shared references, only `Freeze` types may be tracked.
// We are a little bit to restrictive here by only allowing trivially `Freeze` types.
return Err(());
}
let place = self.make_place(local, projection)?;
// Allocate a value slot if it doesn't have one.