Prevent registration inside references if target is !Freeze
This commit is contained in:
parent
4478a87018
commit
111324e17c
3 changed files with 41 additions and 20 deletions
|
@ -849,7 +849,7 @@ impl<'tcx> Ty<'tcx> {
|
||||||
///
|
///
|
||||||
/// Returning true means the type is known to be `Freeze`. Returning
|
/// Returning true means the type is known to be `Freeze`. Returning
|
||||||
/// `false` means nothing -- could be `Freeze`, might not be.
|
/// `false` means nothing -- could be `Freeze`, might not be.
|
||||||
pub fn is_trivially_freeze(self) -> bool {
|
fn is_trivially_freeze(self) -> bool {
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
ty::Int(_)
|
ty::Int(_)
|
||||||
| ty::Uint(_)
|
| ty::Uint(_)
|
||||||
|
|
|
@ -72,6 +72,7 @@ use rustc_index::vec::IndexVec;
|
||||||
use rustc_middle::mir::tcx::PlaceTy;
|
use rustc_middle::mir::tcx::PlaceTy;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
|
use rustc_span::DUMMY_SP;
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -550,7 +551,7 @@ pub struct Map {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl Map {
|
||||||
pub fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
locals: IndexVec::new(),
|
locals: IndexVec::new(),
|
||||||
projections: FxHashMap::default(),
|
projections: FxHashMap::default(),
|
||||||
|
@ -559,16 +560,27 @@ impl Map {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register all places with suitable types up to a certain derefence depth (to prevent cycles).
|
/// Register all suitable places with matching types (up to a certain depth).
|
||||||
pub fn register_with_filter<'tcx>(
|
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,
|
&mut self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
source: &impl HasLocalDecls<'tcx>,
|
body: &Body<'tcx>,
|
||||||
max_derefs: u32,
|
max_derefs: u32,
|
||||||
mut filter: impl FnMut(Ty<'tcx>) -> bool,
|
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();
|
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(
|
self.register_with_filter_rec(
|
||||||
tcx,
|
tcx,
|
||||||
max_derefs,
|
max_derefs,
|
||||||
|
@ -576,6 +588,7 @@ impl Map {
|
||||||
&mut projection,
|
&mut projection,
|
||||||
decl.ty,
|
decl.ty,
|
||||||
&mut filter,
|
&mut filter,
|
||||||
|
param_env,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -588,25 +601,39 @@ impl Map {
|
||||||
projection: &mut Vec<PlaceElem<'tcx>>,
|
projection: &mut Vec<PlaceElem<'tcx>>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
filter: &mut impl FnMut(Ty<'tcx>) -> bool,
|
filter: &mut impl FnMut(Ty<'tcx>) -> bool,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) {
|
) {
|
||||||
if filter(ty) {
|
if filter(ty) {
|
||||||
// This might fail if `ty` is not scalar.
|
// This might fail if `ty` is not scalar.
|
||||||
let _ = self.register_with_ty(local, projection, ty);
|
let _ = self.register_with_ty(local, projection, ty);
|
||||||
}
|
}
|
||||||
if max_derefs > 0 {
|
if max_derefs > 0 {
|
||||||
if let Some(ty::TypeAndMut { ty, .. }) = ty.builtin_deref(false) {
|
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);
|
projection.push(PlaceElem::Deref);
|
||||||
self.register_with_filter_rec(tcx, max_derefs - 1, local, projection, ty, filter);
|
self.register_with_filter_rec(
|
||||||
|
tcx,
|
||||||
|
max_derefs - 1,
|
||||||
|
local,
|
||||||
|
projection,
|
||||||
|
deref_ty,
|
||||||
|
filter,
|
||||||
|
param_env,
|
||||||
|
);
|
||||||
projection.pop();
|
projection.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
iter_fields(ty, tcx, |variant, field, ty| {
|
iter_fields(ty, tcx, |variant, field, ty| {
|
||||||
if variant.is_some() {
|
if variant.is_some() {
|
||||||
// Downcasts are currently not supported.
|
// Downcasts are currently not supported.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
projection.push(PlaceElem::Field(field, ty));
|
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();
|
projection.pop();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -639,7 +666,8 @@ impl Map {
|
||||||
Ok(index)
|
Ok(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register<'tcx>(
|
#[allow(unused)]
|
||||||
|
fn register<'tcx>(
|
||||||
&mut self,
|
&mut self,
|
||||||
local: Local,
|
local: Local,
|
||||||
projection: &[PlaceElem<'tcx>],
|
projection: &[PlaceElem<'tcx>],
|
||||||
|
@ -671,12 +699,6 @@ impl Map {
|
||||||
return Err(());
|
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)?;
|
let place = self.make_place(local, projection)?;
|
||||||
|
|
||||||
// Allocate a value slot if it doesn't have one.
|
// Allocate a value slot if it doesn't have one.
|
||||||
|
|
|
@ -21,8 +21,7 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
|
||||||
|
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
// Decide which places to track during the analysis.
|
// Decide which places to track during the analysis.
|
||||||
let mut map = Map::new();
|
let map = Map::from_filter(tcx, body, |ty| ty.is_scalar() && !ty.is_unsafe_ptr());
|
||||||
map.register_with_filter(tcx, body, 3, |ty| ty.is_scalar() && !ty.is_unsafe_ptr());
|
|
||||||
|
|
||||||
// Perform the actual dataflow analysis.
|
// Perform the actual dataflow analysis.
|
||||||
let analysis = ConstAnalysis::new(tcx, body, map);
|
let analysis = ConstAnalysis::new(tcx, body, map);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue