1use std::fmt::Debug;
2use std::rc::Rc;
34use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
5use rustc_index::Idx;
6use rustc_index::bit_set::SparseBitMatrix;
7use rustc_index::interval::{IntervalSet, SparseIntervalMatrix};
8use rustc_middle::mir::{BasicBlock, Location};
9use rustc_middle::ty::{self, RegionVid};
10use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
11use rustc_span::bug;
12use tracing::{debug, instrument};
1314use crate::BorrowIndex;
15use crate::polonius::LiveLoans;
1617#[automatically_derived]
impl ::core::marker::Copy for PlaceholderIndex { }
impl PlaceholderIndex {
#[doc = r" Maximum value the index can take, as a `u32`."]
pub(crate) const MAX_AS_U32: u32 = 0xFFFF_FF00;
#[doc = r" Maximum value the index can take."]
pub(crate) const MAX: Self = Self::from_u32(0xFFFF_FF00);
#[doc = r" Zero value of the index."]
pub(crate) const ZERO: Self = Self::from_u32(0);
#[doc = r" Creates a new index from a given `usize`."]
#[doc = r""]
#[doc = r" # Panics"]
#[doc = r""]
#[doc = r" Will panic if `value` exceeds `MAX`."]
#[inline]
pub(crate) const fn from_usize(value: usize) -> Self {
if !(value <= (0xFFFF_FF00 as usize)) {
::core::panicking::panic("assertion failed: value <= (0xFFFF_FF00 as usize)")
};
unsafe { Self::from_u32_unchecked(value as u32) }
}
#[doc = r" Creates a new index from a given `u32`."]
#[doc = r""]
#[doc = r" # Panics"]
#[doc = r""]
#[doc = r" Will panic if `value` exceeds `MAX`."]
#[inline]
pub(crate) const fn from_u32(value: u32) -> Self {
if !(value <= 0xFFFF_FF00) {
::core::panicking::panic("assertion failed: value <= 0xFFFF_FF00")
};
unsafe { Self::from_u32_unchecked(value) }
}
#[doc = r" Creates a new index from a given `u16`."]
#[doc = r""]
#[doc = r" # Panics"]
#[doc = r""]
#[doc = r" Will panic if `value` exceeds `MAX`."]
#[inline]
pub(crate) const fn from_u16(value: u16) -> Self {
let value = value as u32;
if !(value <= 0xFFFF_FF00) {
::core::panicking::panic("assertion failed: value <= 0xFFFF_FF00")
};
unsafe { Self::from_u32_unchecked(value) }
}
#[doc = r" Creates a new index from a given `u32`."]
#[doc = r""]
#[doc = r" # Safety"]
#[doc = r""]
#[doc =
r" The provided value must be less than or equal to the maximum value for the newtype."]
#[doc =
r" Providing a value outside this range is undefined due to layout restrictions."]
#[doc = r""]
#[doc = r" Prefer using `from_u32`."]
#[inline]
pub(crate) const unsafe fn from_u32_unchecked(value: u32) -> Self {
Self {
private_use_as_methods_instead: unsafe {
std::mem::transmute(value)
},
}
}
#[doc = r" Extracts the value of this index as a `usize`."]
#[inline]
pub(crate) const fn index(self) -> usize { self.as_usize() }
#[doc = r" Extracts the value of this index as a `u32`."]
#[inline]
pub(crate) const fn as_u32(self) -> u32 {
unsafe { std::mem::transmute(self.private_use_as_methods_instead) }
}
#[doc = r" Extracts the value of this index as a `usize`."]
#[inline]
pub(crate) const fn as_usize(self) -> usize { self.as_u32() as usize }
}
impl std::ops::Add<usize> for PlaceholderIndex {
type Output = Self;
#[inline]
fn add(self, other: usize) -> Self {
Self::from_usize(self.index() + other)
}
}
impl std::ops::AddAssign<usize> for PlaceholderIndex {
#[inline]
fn add_assign(&mut self, other: usize) { *self = *self + other; }
}
impl rustc_index::Idx for PlaceholderIndex {
#[inline]
fn new(value: usize) -> Self { Self::from_usize(value) }
#[inline]
fn index(self) -> usize { self.as_usize() }
}
impl From<PlaceholderIndex> for u32 {
#[inline]
fn from(v: PlaceholderIndex) -> u32 { v.as_u32() }
}
impl From<PlaceholderIndex> for usize {
#[inline]
fn from(v: PlaceholderIndex) -> usize { v.as_usize() }
}
impl From<usize> for PlaceholderIndex {
#[inline]
fn from(value: usize) -> Self { Self::from_usize(value) }
}
impl From<u32> for PlaceholderIndex {
#[inline]
fn from(value: u32) -> Self { Self::from_u32(value) }
}
impl ::std::cmp::Eq for PlaceholderIndex {}
impl ::std::cmp::PartialEq for PlaceholderIndex {
fn eq(&self, other: &Self) -> bool { self.as_u32().eq(&other.as_u32()) }
}
impl ::std::marker::StructuralPartialEq for PlaceholderIndex {}
impl ::std::hash::Hash for PlaceholderIndex {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
self.as_u32().hash(state)
}
}
impl ::std::fmt::Debug for PlaceholderIndex {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_fmt(format_args!("PlaceholderIndex({0})", self.as_u32()))
}
}rustc_index::newtype_index! {
18/// A single integer representing a `ty::Placeholder`.
19#[debug_format = "PlaceholderIndex({})"]
20pub(crate) struct PlaceholderIndex {}
21}2223/// An individual element in a region value -- the value of a
24/// particular region variable consists of a set of these elements.
25#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for RegionElement<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::Location(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Location", &__self_0),
Self::RootUniversalRegion(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"RootUniversalRegion", &__self_0),
Self::PlaceholderRegion(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"PlaceholderRegion", &__self_0),
}
}
}Debug, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for RegionElement<'tcx> {
#[inline]
fn clone(&self) -> Self {
match self {
Self::Location(__self_0) =>
RegionElement::Location(::core::clone::Clone::clone(__self_0)),
Self::RootUniversalRegion(__self_0) =>
RegionElement::RootUniversalRegion(::core::clone::Clone::clone(__self_0)),
Self::PlaceholderRegion(__self_0) =>
RegionElement::PlaceholderRegion(::core::clone::Clone::clone(__self_0)),
}
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::StructuralPartialEq for RegionElement<'tcx> { }
#[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for RegionElement<'tcx> {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other) &&
match (self, other) {
(Self::Location(__self_0), Self::Location(__arg1_0)) =>
__self_0 == __arg1_0,
(Self::RootUniversalRegion(__self_0),
Self::RootUniversalRegion(__arg1_0)) =>
__self_0 == __arg1_0,
(Self::PlaceholderRegion(__self_0),
Self::PlaceholderRegion(__arg1_0)) => __self_0 == __arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() }
}
}
}PartialEq)]
26pub(crate) enum RegionElement<'tcx> {
27/// A point in the control-flow graph.
28Location(Location),
2930/// A universally quantified region from the root universe (e.g.,
31 /// a lifetime parameter).
32RootUniversalRegion(RegionVid),
3334/// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)`
35 /// type).
36PlaceholderRegion(ty::PlaceholderRegion<'tcx>),
37}
3839/// Either a mapping of which points a region is live at (for regular bodies),
40/// or which regions are live in the body somewhere (for promoteds, which do
41/// not care about where they are live, only that they are).
42#[derive(#[automatically_derived]
impl ::core::clone::Clone for LiveRegions {
#[inline]
fn clone(&self) -> Self {
match self {
Self::AtPoints(__self_0) =>
LiveRegions::AtPoints(::core::clone::Clone::clone(__self_0)),
Self::InBody(__self_0) =>
LiveRegions::InBody(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)] // FIXME(#146079)
43enum LiveRegions {
44/// region `'r` is live at locations `L`.
45AtPoints(SparseIntervalMatrix<RegionVid, PointIndex>),
46/// Region `'r` is live in function body.
47InBody(FxHashSet<RegionVid>),
48}
4950/// Records the CFG locations where each region is live. When we initially compute liveness, we use
51/// an interval matrix storing liveness ranges for each region-vid.
52#[derive(#[automatically_derived]
impl ::core::clone::Clone for LivenessValues {
#[inline]
fn clone(&self) -> Self {
LivenessValues {
location_map: ::core::clone::Clone::clone(&self.location_map),
live_regions: ::core::clone::Clone::clone(&self.live_regions),
live_loans: ::core::clone::Clone::clone(&self.live_loans),
}
}
}Clone)] // FIXME(#146079)
53pub(crate) struct LivenessValues {
54/// The map from locations to points.
55location_map: Rc<DenseLocationMap>,
5657/// Where a region is live.
58live_regions: LiveRegions,
5960/// When using `-Zpolonius=next`, the set of loans that are live at a given point in the CFG.
61live_loans: Option<LiveLoans>,
62}
6364impl LivenessValues {
65/// Create an empty map of regions to locations where they're live.
66pub(crate) fn with_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
67LivenessValues {
68 live_regions: LiveRegions::AtPoints(SparseIntervalMatrix::new(
69location_map.num_points(),
70 )),
71location_map,
72 live_loans: None,
73 }
74 }
7576/// Create an empty map of regions to locations where they're live.
77 ///
78 /// Unlike `with_specific_points`, does not track exact locations where something is live, only
79 /// which regions are live.
80pub(crate) fn without_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
81LivenessValues {
82 live_regions: LiveRegions::InBody(Default::default()),
83location_map,
84 live_loans: None,
85 }
86 }
8788/// Returns the liveness matrix of points where each region is live. Panics if the liveness
89 /// values have been created without any per-point data (that is, for promoteds).
90#[inline]
91pub(crate) fn points(&self) -> &SparseIntervalMatrix<RegionVid, PointIndex> {
92if let LiveRegions::AtPoints(points) = &self.live_regions {
93points94 } else {
95::rustc_span::macros::bug_impl(None,
format_args!("this `LivenessValues` wasn\'t created using `with_specific_points`"),
Location::caller())bug!("this `LivenessValues` wasn't created using `with_specific_points`")96 }
97 }
9899/// Get the liveness status of a region `r`, if any.
100 /// Panics if liveness data is not tracked for any region.
101pub(crate) fn point_liveness(&self, region: RegionVid) -> Option<&IntervalSet<PointIndex>> {
102self.points().row(region)
103 }
104105/// Iterate through each region that has a value in this set.
106// We are passing query instability implications to the caller.
107#[rustc_lint_query_instability]
108 #[allow(rustc::potential_query_instability)]
109pub(crate) fn live_regions_unordered(&self) -> impl Iterator<Item = RegionVid> {
110if let LiveRegions::InBody(live_regions) = &self.live_regions {
111live_regions.iter().copied()
112 } else {
113::rustc_span::macros::bug_impl(None,
format_args!("this `LivenessValues` wasn\'t created using `without_specific_points`"),
Location::caller())bug!("this `LivenessValues` wasn't created using `without_specific_points`")114 }
115 }
116117/// Records `region` as being live at the given `location`.
118pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
119let point = self.location_map.point_from_location(location);
120// This is a debug assert despite being cheap because it drops
121 // the current `point_in_range()` uses to 0 when debugging is off.
122if true {
if !self.location_map.point_in_range(point) {
{
::core::panicking::panic_fmt(format_args!("Tried inserting region {0:?} whose location {1:?} does not belong to this body!",
region, location));
}
};
};debug_assert!(
123self.location_map.point_in_range(point),
124"Tried inserting region {region:?} whose location {location:?} does not belong to this body!"
125);
126{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_borrowck/src/region_infer/values.rs:126",
"rustc_borrowck::region_infer::values",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_borrowck/src/region_infer/values.rs"),
::tracing_core::__macro_support::Option::Some(126u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::region_infer::values"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("LivenessValues::add_location(region={0:?}, location={1:?})",
region, location) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
127match &mut self.live_regions {
128 LiveRegions::AtPoints(points) => {
129points.insert(region, point);
130 }
131132 LiveRegions::InBody(live_regions) => {
133live_regions.insert(region);
134 }
135 };
136 }
137138/// Records `region` as being live at all the given `points`.
139pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) {
140if true {
if !points.iter().all(|point| self.location_map.point_in_range(point)) {
{
::core::panicking::panic_fmt(format_args!("Tried inserting region {0:?} with some points not belonging to this body!",
region));
}
};
};debug_assert!(
141 points.iter().all(|point| self.location_map.point_in_range(point)),
142"Tried inserting region {region:?} with some points not belonging to this body!"
143);
144{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_borrowck/src/region_infer/values.rs:144",
"rustc_borrowck::region_infer::values",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_borrowck/src/region_infer/values.rs"),
::tracing_core::__macro_support::Option::Some(144u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::region_infer::values"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("LivenessValues::add_points(region={0:?}, points={1:?})",
region, points) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
145match &mut self.live_regions {
146 LiveRegions::AtPoints(these_points) => {
147these_points.union_row(region, points);
148 }
149 LiveRegions::InBody(live_regions) => {
150live_regions.insert(region);
151 }
152 };
153 }
154155/// Records `region` as being live at all the control-flow points.
156{}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("add_all_points",
"rustc_borrowck::region_infer::values",
::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("/rustc-dev/5d8fec0669a64607db9ccbf663e7c23125bf4748/compiler/rustc_borrowck/src/region_infer/values.rs"),
::tracing_core::__macro_support::Option::Some(156u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::region_infer::values"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("region")
}> =
::tracing::__macro_support::FieldName::new("region");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::INFO <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(®ion)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
match &mut self.live_regions {
LiveRegions::AtPoints(points) =>
points.insert_all_into_row(region),
LiveRegions::InBody(live_regions) => {
live_regions.insert(region);
}
}
}
}
}#[instrument(skip(self))]157pub(crate) fn add_all_points(&mut self, region: RegionVid) {
158match &mut self.live_regions {
159 LiveRegions::AtPoints(points) => points.insert_all_into_row(region),
160 LiveRegions::InBody(live_regions) => {
161 live_regions.insert(region);
162 }
163 }
164 }
165166/// Returns whether `region` is marked live at the given
167 /// [`location`][rustc_middle::mir::Location].
168pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
169let point = self.location_map.point_from_location(location);
170self.is_live_at_point(region, point)
171 }
172173/// Returns whether `region` is marked live at the given
174 /// [`point`][rustc_mir_dataflow::points::PointIndex].
175#[inline]
176pub(crate) fn is_live_at_point(&self, region: RegionVid, point: PointIndex) -> bool {
177self.point_liveness(region).is_some_and(|r| r.contains(point))
178 }
179180/// Returns an iterator of all the points where `region` is live.
181fn live_points(&self, region: RegionVid) -> impl Iterator<Item = PointIndex> {
182self.point_liveness(region).map(|set| set.iter()).into_flat_iter()
183 }
184185/// For debugging purposes, returns a pretty-printed string of the points where the `region` is
186 /// live.
187pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
188pretty_print_region_elements(
189self.live_points(region)
190 .map(|p| RegionElement::Location(self.location_map.to_location(p))),
191 )
192 }
193194/// When using `-Zpolonius=next`, records the given live loans for the loan scopes and active
195 /// loans dataflow computations.
196pub(crate) fn record_live_loans(&mut self, live_loans: LiveLoans) {
197self.live_loans = Some(live_loans);
198 }
199200/// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
201pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool {
202self.live_loans
203 .as_ref()
204 .expect("Accessing live loans requires `-Zpolonius=next`")
205 .contains(point, loan_idx)
206 }
207208#[inline]
209pub(crate) fn location_map(&self) -> &DenseLocationMap {
210&self.location_map
211 }
212}
213214/// Maps from `ty::PlaceholderRegion` values that are used in the rest of
215/// rustc to the internal `PlaceholderIndex` values that are used in
216/// NLL.
217#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for PlaceholderIndices<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"PlaceholderIndices", "indices", &&self.indices)
}
}Debug, #[automatically_derived]
impl<'tcx> ::core::default::Default for PlaceholderIndices<'tcx> {
#[inline]
fn default() -> Self {
PlaceholderIndices { indices: ::core::default::Default::default() }
}
}Default)]
218#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for PlaceholderIndices<'tcx> {
#[inline]
fn clone(&self) -> Self {
PlaceholderIndices {
indices: ::core::clone::Clone::clone(&self.indices),
}
}
}Clone)] // FIXME(#146079)
219pub(crate) struct PlaceholderIndices<'tcx> {
220 indices: FxIndexSet<ty::PlaceholderRegion<'tcx>>,
221}
222223impl<'tcx> PlaceholderIndices<'tcx> {
224/// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion`
225pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion<'tcx>) -> PlaceholderIndex {
226let (index, _) = self.indices.insert_full(placeholder);
227index.into()
228 }
229230pub(crate) fn lookup_index(
231&self,
232 placeholder: ty::PlaceholderRegion<'tcx>,
233 ) -> PlaceholderIndex {
234self.indices.get_index_of(&placeholder).unwrap().into()
235 }
236237pub(crate) fn lookup_placeholder(
238&self,
239 placeholder: PlaceholderIndex,
240 ) -> ty::PlaceholderRegion<'tcx> {
241self.indices[placeholder.index()]
242 }
243244pub(crate) fn len(&self) -> usize {
245self.indices.len()
246 }
247}
248249/// Stores the full values for a set of regions (in contrast to
250/// `LivenessValues`, which only stores those points in the where a
251/// region is live). The full value for a region may contain points in
252/// the CFG, but also free regions as well as bound universe
253/// placeholders.
254///
255/// Example:
256///
257/// ```text
258/// fn foo(x: &'a u32) -> &'a u32 {
259/// let y: &'0 u32 = x; // let's call this `'0`
260/// y
261/// }
262/// ```
263///
264/// Here, the variable `'0` would contain the free region `'a`,
265/// because (since it is returned) it must live for at least `'a`. But
266/// it would also contain various points from within the function.
267pub(crate) struct RegionValues<'tcx, N: Idx> {
268 location_map: Rc<DenseLocationMap>,
269 placeholder_indices: PlaceholderIndices<'tcx>,
270 points: SparseIntervalMatrix<N, PointIndex>,
271 free_regions: SparseBitMatrix<N, RegionVid>,
272273/// Placeholders represent bound regions -- so something like `'a`
274 /// in `for<'a> fn(&'a u32)`.
275placeholders: SparseBitMatrix<N, PlaceholderIndex>,
276}
277278impl<'tcx, N: Idx> RegionValues<'tcx, N> {
279/// Creates a new set of "region values" that tracks causal information.
280 /// Each of the regions in num_region_variables will be initialized with an
281 /// empty set of points and no causal information.
282pub(crate) fn new(
283 location_map: Rc<DenseLocationMap>,
284 num_universal_regions: usize,
285 placeholder_indices: PlaceholderIndices<'tcx>,
286 ) -> Self {
287let num_points = location_map.num_points();
288let num_placeholders = placeholder_indices.len();
289Self {
290location_map,
291 points: SparseIntervalMatrix::new(num_points),
292placeholder_indices,
293 free_regions: SparseBitMatrix::new(num_universal_regions),
294 placeholders: SparseBitMatrix::new(num_placeholders),
295 }
296 }
297298/// Adds all elements in `r_from` to `r_to` (because e.g., `r_to:
299 /// r_from`).
300pub(crate) fn add_region(&mut self, r_to: N, r_from: N) -> bool {
301self.points.union_rows(r_from, r_to)
302 | self.free_regions.union_rows(r_from, r_to)
303 | self.placeholders.union_rows(r_from, r_to)
304 }
305306/// Returns the lowest statement index in `start..=end` which is not contained by `r`.
307pub(crate) fn first_non_contained_inclusive(
308&self,
309 r: N,
310 block: BasicBlock,
311 start: usize,
312 end: usize,
313 ) -> Option<usize> {
314let row = self.points.row(r)?;
315let block = self.location_map.entry_point(block);
316let start = block.plus(start);
317let end = block.plus(end);
318let first_unset = row.first_unset_in(start..=end)?;
319Some(first_unset.index() - block.index())
320 }
321322/// Merge a row of liveness into our points.
323pub(crate) fn merge_liveness(&mut self, to: N, liveness: &IntervalSet<PointIndex>) {
324self.points.union_row(to, liveness);
325 }
326327/// Returns `true` if `sup_region` contains all the CFG points that
328 /// `sub_region` contains. Ignores universal regions.
329pub(crate) fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
330if let Some(sub_row) = self.points.row(sub_region) {
331if let Some(sup_row) = self.points.row(sup_region) {
332sup_row.superset(sub_row)
333 } else {
334// sup row is empty, so sub row must be empty
335sub_row.is_empty()
336 }
337 } else {
338// sub row is empty, always true
339true
340}
341 }
342343/// Returns the locations contained within a given region `r`.
344pub(crate) fn locations_outlived_by(&self, r: N) -> impl Iterator<Item = Location> {
345self.points
346 .row(r)
347 .map(move |set| set.iter().map(move |p| self.location_map.to_location(p)))
348 .into_flat_iter()
349 }
350351/// Returns just the universal regions that are contained in a given region's value.
352pub(crate) fn universal_regions_outlived_by(&self, r: N) -> impl Iterator<Item = RegionVid> {
353self.free_regions.row(r).map(|set| set.iter()).into_flat_iter()
354 }
355356/// Returns all the elements contained in a given region's value.
357pub(crate) fn placeholders_contained_in(
358&self,
359 r: N,
360 ) -> impl Iterator<Item = ty::PlaceholderRegion<'tcx>> {
361self.placeholders
362 .row(r)
363 .map(|set| set.iter())
364 .into_flat_iter()
365 .map(move |p| self.placeholder_indices.lookup_placeholder(p))
366 }
367368/// Returns all the elements contained in a given region's value.
369pub(crate) fn elements_contained_in(&self, r: N) -> impl Iterator<Item = RegionElement<'tcx>> {
370let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
371372let free_regions_iter =
373self.universal_regions_outlived_by(r).map(RegionElement::RootUniversalRegion);
374375let placeholder_universes_iter =
376self.placeholders_contained_in(r).map(RegionElement::PlaceholderRegion);
377378points_iter.chain(free_regions_iter).chain(placeholder_universes_iter)
379 }
380381/// Returns a "pretty" string value of the region. Meant for debugging.
382pub(crate) fn region_value_str(&self, r: N) -> String {
383pretty_print_region_elements(self.elements_contained_in(r))
384 }
385386/// Add a the free region with rvid `region` to SCC `scc`
387pub(crate) fn add_free_region(&mut self, scc: N, region: RegionVid) {
388self.free_regions.insert(scc, region);
389 }
390391pub(crate) fn add_placeholder(&mut self, scc: N, placeholder: ty::PlaceholderRegion<'tcx>) {
392let index = self.placeholder_indices.lookup_index(placeholder);
393self.placeholders.insert(scc, index);
394 }
395396/// Determine if `scc` contains the CFG point `p`.
397pub(crate) fn contains_point(&self, scc: N, p: Location) -> bool {
398let index = self.location_map.point_from_location(p);
399self.points.contains(scc, index)
400 }
401402/// Determine if `scc` contains the free region `free_region`.
403pub(crate) fn contains_free_region(&self, scc: N, free_region: RegionVid) -> bool {
404self.free_regions.contains(scc, free_region)
405 }
406}
407408/// For debugging purposes, returns a pretty-printed string of the given region elements.
409fn pretty_print_region_elements<'tcx>(
410 elements: impl IntoIterator<Item = RegionElement<'tcx>>,
411) -> String {
412let mut result = String::new();
413result.push('{');
414415// Set to Some(l1, l2) when we have observed all the locations
416 // from l1..=l2 (inclusive) but not yet printed them. This
417 // gets extended if we then see l3 where l3 is the successor
418 // to l2.
419let mut open_location: Option<(Location, Location)> = None;
420421let mut sep = "";
422let mut push_sep = |s: &mut String| {
423s.push_str(sep);
424sep = ", ";
425 };
426427for element in elements {
428match element {
429 RegionElement::Location(l) => {
430if let Some((location1, location2)) = open_location {
431if location2.block == l.block
432 && location2.statement_index == l.statement_index - 1
433{
434 open_location = Some((location1, l));
435continue;
436 }
437438 push_sep(&mut result);
439 push_location_range(&mut result, location1, location2);
440 }
441442 open_location = Some((l, l));
443 }
444445 RegionElement::RootUniversalRegion(fr) => {
446if let Some((location1, location2)) = open_location {
447 push_sep(&mut result);
448 push_location_range(&mut result, location1, location2);
449 open_location = None;
450 }
451452 push_sep(&mut result);
453 result.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", fr))
})format!("{fr:?}"));
454 }
455456 RegionElement::PlaceholderRegion(placeholder) => {
457if let Some((location1, location2)) = open_location {
458 push_sep(&mut result);
459 push_location_range(&mut result, location1, location2);
460 open_location = None;
461 }
462463 push_sep(&mut result);
464 result.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", placeholder))
})format!("{placeholder:?}"));
465 }
466 }
467 }
468469if let Some((location1, location2)) = open_location {
470push_sep(&mut result);
471push_location_range(&mut result, location1, location2);
472 }
473474result.push('}');
475476return result;
477478fn push_location_range(s: &mut String, location1: Location, location2: Location) {
479if location1 == location2 {
480s.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", location1))
})format!("{location1:?}"));
481 } else {
482{
match (&location1.block, &location2.block) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(location1.block, location2.block);
483s.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}[{1}..={2}]", location1.block,
location1.statement_index, location2.statement_index))
})format!(
484"{:?}[{}..={}]",
485 location1.block, location1.statement_index, location2.statement_index
486 ));
487 }
488 }
489}