Auto merge of #120068 - matthiaskrgr:rollup-vxugut5, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - #115291 (Save liveness results for DestinationPropagation) - #119855 (Enable Static Builds for FreeBSD) - #119975 (Don't ICE if TAIT-defining fn contains a closure with `_` in return type) - #120001 (Consistently unset RUSTC_BOOTSTRAP when compiling bootstrap) - #120020 (Gracefully handle missing typeck information if typeck errored) - #120031 (Construct closure type eagerly) - #120032 (Fix `rustc_abi` build on stable) - #120039 (pat_analysis: Don't rely on contiguous `VariantId`s outside of rustc) - #120044 (Fix typo in comments (in_place_collect)) - #120056 (Use FnOnceOutput instead of FnOnce where expected) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
2457c028c9
34 changed files with 567 additions and 271 deletions
|
|
@ -4355,6 +4355,7 @@ name = "rustc_pattern_analysis"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"derivative",
|
||||
"rustc-hash",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_data_structures",
|
||||
|
|
|
|||
|
|
@ -49,7 +49,14 @@ bitflags! {
|
|||
| ReprFlags::IS_LINEAR.bits();
|
||||
}
|
||||
}
|
||||
rustc_data_structures::external_bitflags_debug! { ReprFlags }
|
||||
|
||||
// This is the same as `rustc_data_structures::external_bitflags_debug` but without the
|
||||
// `rustc_data_structures` to make it build on stable.
|
||||
impl std::fmt::Debug for ReprFlags {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
bitflags::parser::to_writer(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
|||
use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
|
||||
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
||||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
use rustc_span::symbol::sym;
|
||||
use std::env;
|
||||
|
|
@ -27,7 +28,7 @@ use crate::{
|
|||
facts::{AllFacts, AllFactsExt, RustcFacts},
|
||||
location::LocationTable,
|
||||
polonius,
|
||||
region_infer::{values::RegionValueElements, RegionInferenceContext},
|
||||
region_infer::RegionInferenceContext,
|
||||
renumber,
|
||||
type_check::{self, MirTypeckRegionConstraints, MirTypeckResults},
|
||||
universal_regions::UniversalRegions,
|
||||
|
|
@ -98,7 +99,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
|||
|
||||
let universal_regions = Rc::new(universal_regions);
|
||||
|
||||
let elements = &Rc::new(RegionValueElements::new(body));
|
||||
let elements = &Rc::new(DenseLocationMap::new(body));
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use rustc_middle::mir::{
|
|||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
|
||||
|
|
@ -30,8 +31,7 @@ use crate::{
|
|||
nll::PoloniusOutput,
|
||||
region_infer::reverse_sccs::ReverseSccGraph,
|
||||
region_infer::values::{
|
||||
LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
|
||||
ToElementIndex,
|
||||
LivenessValues, PlaceholderIndices, RegionElement, RegionValues, ToElementIndex,
|
||||
},
|
||||
type_check::{free_region_relations::UniversalRegionRelations, Locations},
|
||||
universal_regions::UniversalRegions,
|
||||
|
|
@ -330,7 +330,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
|
||||
type_tests: Vec<TypeTest<'tcx>>,
|
||||
liveness_constraints: LivenessValues,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
) -> Self {
|
||||
debug!("universal_regions: {:#?}", universal_regions);
|
||||
debug!("outlives constraints: {:#?}", outlives_constraints);
|
||||
|
|
|
|||
|
|
@ -5,97 +5,13 @@ use rustc_index::bit_set::SparseBitMatrix;
|
|||
use rustc_index::interval::IntervalSet;
|
||||
use rustc_index::interval::SparseIntervalMatrix;
|
||||
use rustc_index::Idx;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::{BasicBlock, Body, Location};
|
||||
use rustc_middle::mir::{BasicBlock, Location};
|
||||
use rustc_middle::ty::{self, RegionVid};
|
||||
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
|
||||
use std::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::dataflow::BorrowIndex;
|
||||
|
||||
/// Maps between a `Location` and a `PointIndex` (and vice versa).
|
||||
pub(crate) struct RegionValueElements {
|
||||
/// For each basic block, how many points are contained within?
|
||||
statements_before_block: IndexVec<BasicBlock, usize>,
|
||||
|
||||
/// Map backward from each point to the basic block that it
|
||||
/// belongs to.
|
||||
basic_blocks: IndexVec<PointIndex, BasicBlock>,
|
||||
|
||||
num_points: usize,
|
||||
}
|
||||
|
||||
impl RegionValueElements {
|
||||
pub(crate) fn new(body: &Body<'_>) -> Self {
|
||||
let mut num_points = 0;
|
||||
let statements_before_block: IndexVec<BasicBlock, usize> = body
|
||||
.basic_blocks
|
||||
.iter()
|
||||
.map(|block_data| {
|
||||
let v = num_points;
|
||||
num_points += block_data.statements.len() + 1;
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
debug!("RegionValueElements: statements_before_block={:#?}", statements_before_block);
|
||||
debug!("RegionValueElements: num_points={:#?}", num_points);
|
||||
|
||||
let mut basic_blocks = IndexVec::with_capacity(num_points);
|
||||
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
||||
basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
|
||||
}
|
||||
|
||||
Self { statements_before_block, basic_blocks, num_points }
|
||||
}
|
||||
|
||||
/// Total number of point indices
|
||||
pub(crate) fn num_points(&self) -> usize {
|
||||
self.num_points
|
||||
}
|
||||
|
||||
/// Converts a `Location` into a `PointIndex`. O(1).
|
||||
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
|
||||
let Location { block, statement_index } = location;
|
||||
let start_index = self.statements_before_block[block];
|
||||
PointIndex::new(start_index + statement_index)
|
||||
}
|
||||
|
||||
/// Converts a `Location` into a `PointIndex`. O(1).
|
||||
pub(crate) fn entry_point(&self, block: BasicBlock) -> PointIndex {
|
||||
let start_index = self.statements_before_block[block];
|
||||
PointIndex::new(start_index)
|
||||
}
|
||||
|
||||
/// Return the PointIndex for the block start of this index.
|
||||
pub(crate) fn to_block_start(&self, index: PointIndex) -> PointIndex {
|
||||
PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
|
||||
}
|
||||
|
||||
/// Converts a `PointIndex` back to a location. O(1).
|
||||
pub(crate) fn to_location(&self, index: PointIndex) -> Location {
|
||||
assert!(index.index() < self.num_points);
|
||||
let block = self.basic_blocks[index];
|
||||
let start_index = self.statements_before_block[block];
|
||||
let statement_index = index.index() - start_index;
|
||||
Location { block, statement_index }
|
||||
}
|
||||
|
||||
/// Sometimes we get point-indices back from bitsets that may be
|
||||
/// out of range (because they round up to the nearest 2^N number
|
||||
/// of bits). Use this function to filter such points out if you
|
||||
/// like.
|
||||
pub(crate) fn point_in_range(&self, index: PointIndex) -> bool {
|
||||
index.index() < self.num_points
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A single integer representing a `Location` in the MIR control-flow
|
||||
/// graph. Constructed efficiently from `RegionValueElements`.
|
||||
#[orderable]
|
||||
#[debug_format = "PointIndex({})"]
|
||||
pub struct PointIndex {}
|
||||
}
|
||||
use crate::BorrowIndex;
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A single integer representing a `ty::Placeholder`.
|
||||
|
|
@ -123,7 +39,7 @@ pub(crate) enum RegionElement {
|
|||
/// an interval matrix storing liveness ranges for each region-vid.
|
||||
pub(crate) struct LivenessValues {
|
||||
/// The map from locations to points.
|
||||
elements: Rc<RegionValueElements>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
|
||||
/// For each region: the points where it is live.
|
||||
points: SparseIntervalMatrix<RegionVid, PointIndex>,
|
||||
|
|
@ -155,9 +71,9 @@ impl LiveLoans {
|
|||
|
||||
impl LivenessValues {
|
||||
/// Create an empty map of regions to locations where they're live.
|
||||
pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
|
||||
pub(crate) fn new(elements: Rc<DenseLocationMap>) -> Self {
|
||||
LivenessValues {
|
||||
points: SparseIntervalMatrix::new(elements.num_points),
|
||||
points: SparseIntervalMatrix::new(elements.num_points()),
|
||||
elements,
|
||||
loans: None,
|
||||
}
|
||||
|
|
@ -298,7 +214,7 @@ impl PlaceholderIndices {
|
|||
/// it would also contain various points from within the function.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct RegionValues<N: Idx> {
|
||||
elements: Rc<RegionValueElements>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
placeholder_indices: Rc<PlaceholderIndices>,
|
||||
points: SparseIntervalMatrix<N, PointIndex>,
|
||||
free_regions: SparseBitMatrix<N, RegionVid>,
|
||||
|
|
@ -313,14 +229,14 @@ impl<N: Idx> RegionValues<N> {
|
|||
/// Each of the regions in num_region_variables will be initialized with an
|
||||
/// empty set of points and no causal information.
|
||||
pub(crate) fn new(
|
||||
elements: &Rc<RegionValueElements>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
num_universal_regions: usize,
|
||||
placeholder_indices: &Rc<PlaceholderIndices>,
|
||||
) -> Self {
|
||||
let num_placeholders = placeholder_indices.len();
|
||||
Self {
|
||||
elements: elements.clone(),
|
||||
points: SparseIntervalMatrix::new(elements.num_points),
|
||||
points: SparseIntervalMatrix::new(elements.num_points()),
|
||||
placeholder_indices: placeholder_indices.clone(),
|
||||
free_regions: SparseBitMatrix::new(num_universal_regions),
|
||||
placeholders: SparseBitMatrix::new(num_placeholders),
|
||||
|
|
@ -486,7 +402,7 @@ impl ToElementIndex for ty::PlaceholderRegion {
|
|||
|
||||
/// For debugging purposes, returns a pretty-printed string of the given points.
|
||||
pub(crate) fn pretty_print_points(
|
||||
elements: &RegionValueElements,
|
||||
elements: &DenseLocationMap,
|
||||
points: impl IntoIterator<Item = PointIndex>,
|
||||
) -> String {
|
||||
pretty_print_region_elements(
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ use rustc_data_structures::vec_linked_list as vll;
|
|||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{Body, Local, Location};
|
||||
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
|
||||
|
||||
use crate::def_use::{self, DefUse};
|
||||
use crate::region_infer::values::{PointIndex, RegionValueElements};
|
||||
|
||||
/// A map that cross references each local with the locations where it
|
||||
/// is defined (assigned), used, or dropped. Used during liveness
|
||||
|
|
@ -60,7 +60,7 @@ impl vll::LinkElem for Appearance {
|
|||
impl LocalUseMap {
|
||||
pub(crate) fn build(
|
||||
live_locals: &[Local],
|
||||
elements: &RegionValueElements,
|
||||
elements: &DenseLocationMap,
|
||||
body: &Body<'_>,
|
||||
) -> Self {
|
||||
let nones = IndexVec::from_elem(None, &body.local_decls);
|
||||
|
|
@ -103,7 +103,7 @@ impl LocalUseMap {
|
|||
|
||||
struct LocalUseMapBuild<'me> {
|
||||
local_use_map: &'me mut LocalUseMap,
|
||||
elements: &'me RegionValueElements,
|
||||
elements: &'me DenseLocationMap,
|
||||
|
||||
// Vector used in `visit_local` to signal which `Local`s do we need
|
||||
// def/use/drop information on, constructed from `live_locals` (that
|
||||
|
|
@ -144,7 +144,7 @@ impl LocalUseMapBuild<'_> {
|
|||
}
|
||||
|
||||
fn insert(
|
||||
elements: &RegionValueElements,
|
||||
elements: &DenseLocationMap,
|
||||
first_appearance: &mut Option<AppearanceIndex>,
|
||||
appearances: &mut IndexVec<AppearanceIndex, Appearance>,
|
||||
location: Location,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_middle::ty::visit::TypeVisitable;
|
|||
use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt};
|
||||
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
||||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -13,7 +14,7 @@ use crate::{
|
|||
constraints::OutlivesConstraintSet,
|
||||
facts::{AllFacts, AllFactsExt},
|
||||
location::LocationTable,
|
||||
region_infer::values::{LivenessValues, RegionValueElements},
|
||||
region_infer::values::LivenessValues,
|
||||
universal_regions::UniversalRegions,
|
||||
};
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ mod trace;
|
|||
pub(super) fn generate<'mir, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use rustc_infer::infer::outlives::for_liveness;
|
|||
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
|
||||
use rustc_middle::traits::query::DropckOutlivesResult;
|
||||
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
|
||||
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
|
||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||
|
|
@ -17,7 +18,7 @@ use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
|
|||
use rustc_mir_dataflow::ResultsCursor;
|
||||
|
||||
use crate::{
|
||||
region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements},
|
||||
region_infer::values::{self, LiveLoans},
|
||||
type_check::liveness::local_use_map::LocalUseMap,
|
||||
type_check::liveness::polonius,
|
||||
type_check::NormalizeLocation,
|
||||
|
|
@ -41,7 +42,7 @@ use crate::{
|
|||
pub(super) fn trace<'mir, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
relevant_live_locals: Vec<Local>,
|
||||
|
|
@ -105,7 +106,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
|
|||
typeck: &'me mut TypeChecker<'typeck, 'tcx>,
|
||||
|
||||
/// Defines the `PointIndex` mapping
|
||||
elements: &'me RegionValueElements,
|
||||
elements: &'me DenseLocationMap,
|
||||
|
||||
/// MIR we are analyzing.
|
||||
body: &'me Body<'tcx>,
|
||||
|
|
@ -570,7 +571,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
|||
}
|
||||
|
||||
fn make_all_regions_live(
|
||||
elements: &RegionValueElements,
|
||||
elements: &DenseLocationMap,
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
value: impl TypeVisitable<TyCtxt<'tcx>>,
|
||||
live_at: &IntervalSet<PointIndex>,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ use rustc_middle::ty::{
|
|||
OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArgsRef, UserArgs};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::sym;
|
||||
|
|
@ -59,9 +60,7 @@ use crate::{
|
|||
location::LocationTable,
|
||||
member_constraints::MemberConstraintSet,
|
||||
path_utils,
|
||||
region_infer::values::{
|
||||
LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
|
||||
},
|
||||
region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices},
|
||||
region_infer::TypeTest,
|
||||
type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
|
||||
universal_regions::{DefiningTy, UniversalRegions},
|
||||
|
|
@ -134,7 +133,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||
all_facts: &mut Option<AllFacts>,
|
||||
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
elements: &Rc<DenseLocationMap>,
|
||||
upvars: &[&ty::CapturedPlace<'tcx>],
|
||||
use_polonius: bool,
|
||||
) -> MirTypeckResults<'tcx> {
|
||||
|
|
@ -556,7 +555,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
let all_facts = &mut None;
|
||||
let mut constraints = Default::default();
|
||||
let mut liveness_constraints =
|
||||
LivenessValues::new(Rc::new(RegionValueElements::new(promoted_body)));
|
||||
LivenessValues::new(Rc::new(DenseLocationMap::new(promoted_body)));
|
||||
// Don't try to add borrow_region facts for the promoted MIR
|
||||
|
||||
let mut swap_constraints = |this: &mut Self| {
|
||||
|
|
|
|||
|
|
@ -135,18 +135,25 @@ impl TaitConstraintLocator<'_> {
|
|||
return;
|
||||
}
|
||||
|
||||
if let Some(hir_sig) = self.tcx.hir_node_by_def_id(item_def_id).fn_decl() {
|
||||
if hir_sig.output.get_infer_ret_ty().is_some() {
|
||||
let guar = self.tcx.dcx().span_delayed_bug(
|
||||
hir_sig.output.span(),
|
||||
"inferring return types and opaque types do not mix well",
|
||||
);
|
||||
self.found = Some(ty::OpaqueHiddenType {
|
||||
span: DUMMY_SP,
|
||||
ty: Ty::new_error(self.tcx, guar),
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Function items with `_` in their return type already emit an error, skip any
|
||||
// "non-defining use" errors for them.
|
||||
// Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former
|
||||
// excludes closures, which are allowed to have `_` in their return type.
|
||||
let hir_node = self.tcx.hir_node_by_def_id(item_def_id);
|
||||
debug_assert!(
|
||||
!matches!(hir_node, Node::ForeignItem(..)),
|
||||
"foreign items cannot constrain opaque types",
|
||||
);
|
||||
if let Some(hir_sig) = hir_node.fn_sig()
|
||||
&& hir_sig.decl.output.get_infer_ret_ty().is_some()
|
||||
{
|
||||
let guar = self.tcx.dcx().span_delayed_bug(
|
||||
hir_sig.decl.output.span(),
|
||||
"inferring return types and opaque types do not mix well",
|
||||
);
|
||||
self.found =
|
||||
Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
|
||||
return;
|
||||
}
|
||||
|
||||
// Calling `mir_borrowck` can lead to cycle errors through
|
||||
|
|
|
|||
|
|
@ -68,12 +68,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
debug!(?bound_sig, ?liberated_sig);
|
||||
|
||||
let parent_args =
|
||||
GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
|
||||
|
||||
let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||
span: expr_span,
|
||||
});
|
||||
|
||||
// FIXME: We could probably actually just unify this further --
|
||||
// instead of having a `FnSig` and a `Option<CoroutineTypes>`,
|
||||
// we can have a `ClosureSignature { Coroutine { .. }, Closure { .. } }`,
|
||||
// similar to how `ty::GenSig` is a distinct data structure.
|
||||
let coroutine_types = match closure.kind {
|
||||
hir::ClosureKind::Closure => None,
|
||||
let (closure_ty, coroutine_types) = match closure.kind {
|
||||
hir::ClosureKind::Closure => {
|
||||
// Tuple up the arguments and insert the resulting function type into
|
||||
// the `closures` table.
|
||||
let sig = bound_sig.map_bound(|sig| {
|
||||
tcx.mk_fn_sig(
|
||||
[Ty::new_tup(tcx, sig.inputs())],
|
||||
sig.output(),
|
||||
sig.c_variadic,
|
||||
sig.unsafety,
|
||||
sig.abi,
|
||||
)
|
||||
});
|
||||
|
||||
debug!(?sig, ?expected_kind);
|
||||
|
||||
let closure_kind_ty = match expected_kind {
|
||||
Some(kind) => Ty::from_closure_kind(tcx, kind),
|
||||
|
||||
// Create a type variable (for now) to represent the closure kind.
|
||||
// It will be unified during the upvar inference phase (`upvar.rs`)
|
||||
None => self.next_root_ty_var(TypeVariableOrigin {
|
||||
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
|
||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||
span: expr_span,
|
||||
}),
|
||||
};
|
||||
|
||||
let closure_args = ty::ClosureArgs::new(
|
||||
tcx,
|
||||
ty::ClosureArgsParts {
|
||||
parent_args,
|
||||
closure_kind_ty,
|
||||
closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig),
|
||||
tupled_upvars_ty,
|
||||
},
|
||||
);
|
||||
|
||||
(Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args), None)
|
||||
}
|
||||
hir::ClosureKind::Coroutine(kind) => {
|
||||
let yield_ty = match kind {
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
||||
|
|
@ -119,74 +165,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Resume type defaults to `()` if the coroutine has no argument.
|
||||
let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
|
||||
|
||||
Some(CoroutineTypes { resume_ty, yield_ty })
|
||||
}
|
||||
};
|
||||
|
||||
check_fn(
|
||||
&mut FnCtxt::new(self, self.param_env, closure.def_id),
|
||||
liberated_sig,
|
||||
coroutine_types,
|
||||
closure.fn_decl,
|
||||
expr_def_id,
|
||||
body,
|
||||
// Closure "rust-call" ABI doesn't support unsized params
|
||||
false,
|
||||
);
|
||||
|
||||
let parent_args =
|
||||
GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
|
||||
|
||||
let tupled_upvars_ty = self.next_root_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||
span: expr_span,
|
||||
});
|
||||
|
||||
match closure.kind {
|
||||
hir::ClosureKind::Closure => {
|
||||
assert_eq!(coroutine_types, None);
|
||||
// Tuple up the arguments and insert the resulting function type into
|
||||
// the `closures` table.
|
||||
let sig = bound_sig.map_bound(|sig| {
|
||||
tcx.mk_fn_sig(
|
||||
[Ty::new_tup(tcx, sig.inputs())],
|
||||
sig.output(),
|
||||
sig.c_variadic,
|
||||
sig.unsafety,
|
||||
sig.abi,
|
||||
)
|
||||
});
|
||||
|
||||
debug!(?sig, ?expected_kind);
|
||||
|
||||
let closure_kind_ty = match expected_kind {
|
||||
Some(kind) => Ty::from_closure_kind(tcx, kind),
|
||||
|
||||
// Create a type variable (for now) to represent the closure kind.
|
||||
// It will be unified during the upvar inference phase (`upvar.rs`)
|
||||
None => self.next_root_ty_var(TypeVariableOrigin {
|
||||
// FIXME(eddyb) distinguish closure kind inference variables from the rest.
|
||||
kind: TypeVariableOriginKind::ClosureSynthetic,
|
||||
span: expr_span,
|
||||
}),
|
||||
};
|
||||
|
||||
let closure_args = ty::ClosureArgs::new(
|
||||
tcx,
|
||||
ty::ClosureArgsParts {
|
||||
parent_args,
|
||||
closure_kind_ty,
|
||||
closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(tcx, sig),
|
||||
tupled_upvars_ty,
|
||||
},
|
||||
);
|
||||
|
||||
Ty::new_closure(tcx, expr_def_id.to_def_id(), closure_args.args)
|
||||
}
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
let Some(CoroutineTypes { resume_ty, yield_ty }) = coroutine_types else {
|
||||
bug!("expected coroutine to have yield/resume types");
|
||||
};
|
||||
let interior = self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: body.value.span,
|
||||
|
|
@ -209,9 +187,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
},
|
||||
);
|
||||
|
||||
Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args)
|
||||
(
|
||||
Ty::new_coroutine(tcx, expr_def_id.to_def_id(), coroutine_args.args),
|
||||
Some(CoroutineTypes { resume_ty, yield_ty }),
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
check_fn(
|
||||
&mut FnCtxt::new(self, self.param_env, closure.def_id),
|
||||
liberated_sig,
|
||||
coroutine_types,
|
||||
closure.fn_decl,
|
||||
expr_def_id,
|
||||
body,
|
||||
// Closure "rust-call" ABI doesn't support unsized params
|
||||
false,
|
||||
);
|
||||
|
||||
closure_ty
|
||||
}
|
||||
|
||||
/// Given the expected type, figures out what it can about this closure we
|
||||
|
|
@ -683,10 +677,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
})
|
||||
}
|
||||
// All `gen {}` and `async gen {}` must return unit.
|
||||
hir::ClosureKind::Coroutine(
|
||||
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
|
||||
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _),
|
||||
) => self.tcx.types.unit,
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen,
|
||||
_,
|
||||
)) => self.tcx.types.unit,
|
||||
|
||||
// For async blocks, we just fall back to `_` here.
|
||||
// For closures/coroutines, we know nothing about the return
|
||||
|
|
|
|||
|
|
@ -1526,13 +1526,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
self.check_repeat_element_needs_copy_bound(element, count, element_ty);
|
||||
|
||||
self.register_wf_obligation(
|
||||
Ty::new_array_with_const_len(tcx, t, count).into(),
|
||||
expr.span,
|
||||
traits::WellFormed(None),
|
||||
);
|
||||
let ty = Ty::new_array_with_const_len(tcx, t, count);
|
||||
|
||||
Ty::new_array_with_const_len(tcx, t, count)
|
||||
self.register_wf_obligation(ty.into(), expr.span, traits::WellFormed(None));
|
||||
|
||||
ty
|
||||
}
|
||||
|
||||
fn check_repeat_element_needs_copy_bound(
|
||||
|
|
|
|||
|
|
@ -1013,7 +1013,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
.extend(
|
||||
// Group the return ty with its def id, if we had one.
|
||||
entry.return_ty.map(|ty| {
|
||||
(tcx.require_lang_item(LangItem::FnOnce, None), ty)
|
||||
(tcx.require_lang_item(LangItem::FnOnceOutput, None), ty)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ mod errors;
|
|||
mod framework;
|
||||
pub mod impls;
|
||||
pub mod move_paths;
|
||||
pub mod points;
|
||||
pub mod rustc_peek;
|
||||
pub mod storage;
|
||||
pub mod un_derefer;
|
||||
|
|
|
|||
156
compiler/rustc_mir_dataflow/src/points.rs
Normal file
156
compiler/rustc_mir_dataflow/src/points.rs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
use crate::framework::{visit_results, ResultsVisitable, ResultsVisitor};
|
||||
use rustc_index::bit_set::ChunkedBitSet;
|
||||
use rustc_index::interval::SparseIntervalMatrix;
|
||||
use rustc_index::Idx;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::{self, BasicBlock, Body, Location};
|
||||
|
||||
/// Maps between a `Location` and a `PointIndex` (and vice versa).
|
||||
pub struct DenseLocationMap {
|
||||
/// For each basic block, how many points are contained within?
|
||||
statements_before_block: IndexVec<BasicBlock, usize>,
|
||||
|
||||
/// Map backward from each point to the basic block that it
|
||||
/// belongs to.
|
||||
basic_blocks: IndexVec<PointIndex, BasicBlock>,
|
||||
|
||||
num_points: usize,
|
||||
}
|
||||
|
||||
impl DenseLocationMap {
|
||||
#[inline]
|
||||
pub fn new(body: &Body<'_>) -> Self {
|
||||
let mut num_points = 0;
|
||||
let statements_before_block: IndexVec<BasicBlock, usize> = body
|
||||
.basic_blocks
|
||||
.iter()
|
||||
.map(|block_data| {
|
||||
let v = num_points;
|
||||
num_points += block_data.statements.len() + 1;
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut basic_blocks = IndexVec::with_capacity(num_points);
|
||||
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
||||
basic_blocks.extend((0..=bb_data.statements.len()).map(|_| bb));
|
||||
}
|
||||
|
||||
Self { statements_before_block, basic_blocks, num_points }
|
||||
}
|
||||
|
||||
/// Total number of point indices
|
||||
#[inline]
|
||||
pub fn num_points(&self) -> usize {
|
||||
self.num_points
|
||||
}
|
||||
|
||||
/// Converts a `Location` into a `PointIndex`. O(1).
|
||||
#[inline]
|
||||
pub fn point_from_location(&self, location: Location) -> PointIndex {
|
||||
let Location { block, statement_index } = location;
|
||||
let start_index = self.statements_before_block[block];
|
||||
PointIndex::new(start_index + statement_index)
|
||||
}
|
||||
|
||||
/// Returns the `PointIndex` for the first statement in the given `BasicBlock`. O(1).
|
||||
#[inline]
|
||||
pub fn entry_point(&self, block: BasicBlock) -> PointIndex {
|
||||
let start_index = self.statements_before_block[block];
|
||||
PointIndex::new(start_index)
|
||||
}
|
||||
|
||||
/// Return the PointIndex for the block start of this index.
|
||||
#[inline]
|
||||
pub fn to_block_start(&self, index: PointIndex) -> PointIndex {
|
||||
PointIndex::new(self.statements_before_block[self.basic_blocks[index]])
|
||||
}
|
||||
|
||||
/// Converts a `PointIndex` back to a location. O(1).
|
||||
#[inline]
|
||||
pub fn to_location(&self, index: PointIndex) -> Location {
|
||||
assert!(index.index() < self.num_points);
|
||||
let block = self.basic_blocks[index];
|
||||
let start_index = self.statements_before_block[block];
|
||||
let statement_index = index.index() - start_index;
|
||||
Location { block, statement_index }
|
||||
}
|
||||
|
||||
/// Sometimes we get point-indices back from bitsets that may be
|
||||
/// out of range (because they round up to the nearest 2^N number
|
||||
/// of bits). Use this function to filter such points out if you
|
||||
/// like.
|
||||
#[inline]
|
||||
pub fn point_in_range(&self, index: PointIndex) -> bool {
|
||||
index.index() < self.num_points
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A single integer representing a `Location` in the MIR control-flow
|
||||
/// graph. Constructed efficiently from `DenseLocationMap`.
|
||||
#[orderable]
|
||||
#[debug_format = "PointIndex({})"]
|
||||
pub struct PointIndex {}
|
||||
}
|
||||
|
||||
/// Add points depending on the result of the given dataflow analysis.
|
||||
pub fn save_as_intervals<'tcx, N, R>(
|
||||
elements: &DenseLocationMap,
|
||||
body: &mir::Body<'tcx>,
|
||||
mut results: R,
|
||||
) -> SparseIntervalMatrix<N, PointIndex>
|
||||
where
|
||||
N: Idx,
|
||||
R: ResultsVisitable<'tcx, FlowState = ChunkedBitSet<N>>,
|
||||
{
|
||||
let values = SparseIntervalMatrix::new(elements.num_points());
|
||||
let mut visitor = Visitor { elements, values };
|
||||
visit_results(
|
||||
body,
|
||||
body.basic_blocks.reverse_postorder().iter().copied(),
|
||||
&mut results,
|
||||
&mut visitor,
|
||||
);
|
||||
visitor.values
|
||||
}
|
||||
|
||||
struct Visitor<'a, N: Idx> {
|
||||
elements: &'a DenseLocationMap,
|
||||
values: SparseIntervalMatrix<N, PointIndex>,
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N>
|
||||
where
|
||||
N: Idx,
|
||||
{
|
||||
type FlowState = ChunkedBitSet<N>;
|
||||
|
||||
fn visit_statement_after_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
state: &Self::FlowState,
|
||||
_statement: &'mir mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
let point = self.elements.point_from_location(location);
|
||||
// Use internal iterator manually as it is much more efficient.
|
||||
state.iter().for_each(|node| {
|
||||
self.values.insert(node, point);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_terminator_after_primary_effect(
|
||||
&mut self,
|
||||
_results: &mut R,
|
||||
state: &Self::FlowState,
|
||||
_terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
let point = self.elements.point_from_location(location);
|
||||
// Use internal iterator manually as it is much more efficient.
|
||||
state.iter().for_each(|node| {
|
||||
self.values.insert(node, point);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -134,6 +134,7 @@
|
|||
use crate::MirPass;
|
||||
use rustc_data_structures::fx::{FxIndexMap, IndexEntry, IndexOccupiedEntry};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::interval::SparseIntervalMatrix;
|
||||
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::HasLocalDecls;
|
||||
use rustc_middle::mir::{dump_mir, PassWhere};
|
||||
|
|
@ -143,7 +144,8 @@ use rustc_middle::mir::{
|
|||
};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_mir_dataflow::impls::MaybeLiveLocals;
|
||||
use rustc_mir_dataflow::{Analysis, ResultsCursor};
|
||||
use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex};
|
||||
use rustc_mir_dataflow::Analysis;
|
||||
|
||||
pub struct DestinationPropagation;
|
||||
|
||||
|
|
@ -167,6 +169,13 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
|
|||
|
||||
let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body);
|
||||
|
||||
let live = MaybeLiveLocals
|
||||
.into_engine(tcx, body)
|
||||
.pass_name("MaybeLiveLocals-DestinationPropagation")
|
||||
.iterate_to_fixpoint();
|
||||
let points = DenseLocationMap::new(body);
|
||||
let mut live = save_as_intervals(&points, body, live);
|
||||
|
||||
// In order to avoid having to collect data for every single pair of locals in the body, we
|
||||
// do not allow doing more than one merge for places that are derived from the same local at
|
||||
// once. To avoid missed opportunities, we instead iterate to a fixed point - we'll refer to
|
||||
|
|
@ -190,22 +199,19 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
|
|||
&mut allocations.candidates_reverse,
|
||||
);
|
||||
trace!(?candidates);
|
||||
let mut live = MaybeLiveLocals
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint()
|
||||
.into_results_cursor(body);
|
||||
dest_prop_mir_dump(tcx, body, &mut live, round_count);
|
||||
dest_prop_mir_dump(tcx, body, &points, &live, round_count);
|
||||
|
||||
FilterInformation::filter_liveness(
|
||||
&mut candidates,
|
||||
&mut live,
|
||||
&points,
|
||||
&live,
|
||||
&mut allocations.write_info,
|
||||
body,
|
||||
);
|
||||
|
||||
// Because we do not update liveness information, it is unsound to use a local for more
|
||||
// than one merge operation within a single round of optimizations. We store here which
|
||||
// ones we have already used.
|
||||
// Because we only filter once per round, it is unsound to use a local for more than
|
||||
// one merge operation within a single round of optimizations. We store here which ones
|
||||
// we have already used.
|
||||
let mut merged_locals: BitSet<Local> = BitSet::new_empty(body.local_decls.len());
|
||||
|
||||
// This is the set of merges we will apply this round. It is a subset of the candidates.
|
||||
|
|
@ -224,9 +230,15 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
|
|||
}) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Replace `src` by `dest` everywhere.
|
||||
merges.insert(*src, *dest);
|
||||
merged_locals.insert(*src);
|
||||
merged_locals.insert(*dest);
|
||||
|
||||
// Update liveness information based on the merge we just performed.
|
||||
// Every location where `src` was live, `dest` will be live.
|
||||
live.union_rows(*src, *dest);
|
||||
}
|
||||
trace!(merging = ?merges);
|
||||
|
||||
|
|
@ -349,7 +361,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> {
|
|||
|
||||
struct FilterInformation<'a, 'body, 'alloc, 'tcx> {
|
||||
body: &'body Body<'tcx>,
|
||||
live: &'a mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>,
|
||||
points: &'a DenseLocationMap,
|
||||
live: &'a SparseIntervalMatrix<Local, PointIndex>,
|
||||
candidates: &'a mut Candidates<'alloc>,
|
||||
write_info: &'alloc mut WriteInfo,
|
||||
at: Location,
|
||||
|
|
@ -452,12 +465,14 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
|
|||
/// locals as also being read from.
|
||||
fn filter_liveness<'b>(
|
||||
candidates: &mut Candidates<'alloc>,
|
||||
live: &mut ResultsCursor<'b, 'tcx, MaybeLiveLocals>,
|
||||
points: &DenseLocationMap,
|
||||
live: &SparseIntervalMatrix<Local, PointIndex>,
|
||||
write_info_alloc: &'alloc mut WriteInfo,
|
||||
body: &'b Body<'tcx>,
|
||||
) {
|
||||
let mut this = FilterInformation {
|
||||
body,
|
||||
points,
|
||||
live,
|
||||
candidates,
|
||||
// We don't actually store anything at this scope, we just keep things here to be able
|
||||
|
|
@ -472,13 +487,11 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
|
|||
fn internal_filter_liveness(&mut self) {
|
||||
for (block, data) in traversal::preorder(self.body) {
|
||||
self.at = Location { block, statement_index: data.statements.len() };
|
||||
self.live.seek_after_primary_effect(self.at);
|
||||
self.write_info.for_terminator(&data.terminator().kind);
|
||||
self.apply_conflicts();
|
||||
|
||||
for (i, statement) in data.statements.iter().enumerate().rev() {
|
||||
self.at = Location { block, statement_index: i };
|
||||
self.live.seek_after_primary_effect(self.at);
|
||||
self.write_info.for_statement(&statement.kind, self.body);
|
||||
self.apply_conflicts();
|
||||
}
|
||||
|
|
@ -497,6 +510,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
|
|||
None
|
||||
}
|
||||
});
|
||||
let at = self.points.point_from_location(self.at);
|
||||
self.candidates.filter_candidates_by(
|
||||
*p,
|
||||
|q| {
|
||||
|
|
@ -508,7 +522,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
|
|||
// calls or inline asm. Because of this, we also mark locals as
|
||||
// conflicting when both of them are written to in the same
|
||||
// statement.
|
||||
if self.live.contains(q) || writes.contains(&q) {
|
||||
if self.live.contains(q, at) || writes.contains(&q) {
|
||||
CandidateFilter::Remove
|
||||
} else {
|
||||
CandidateFilter::Keep
|
||||
|
|
@ -801,38 +815,17 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool {
|
|||
fn dest_prop_mir_dump<'body, 'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'body Body<'tcx>,
|
||||
live: &mut ResultsCursor<'body, 'tcx, MaybeLiveLocals>,
|
||||
points: &DenseLocationMap,
|
||||
live: &SparseIntervalMatrix<Local, PointIndex>,
|
||||
round: usize,
|
||||
) {
|
||||
let mut reachable = None;
|
||||
let locals_live_at = |location| {
|
||||
let location = points.point_from_location(location);
|
||||
live.rows().filter(|&r| live.contains(r, location)).collect::<Vec<_>>()
|
||||
};
|
||||
dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, |pass_where, w| {
|
||||
let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body));
|
||||
|
||||
match pass_where {
|
||||
PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => {
|
||||
live.seek_after_primary_effect(loc);
|
||||
writeln!(w, " // live: {:?}", live.get())?;
|
||||
}
|
||||
PassWhere::AfterTerminator(bb) if reachable.contains(bb) => {
|
||||
let loc = body.terminator_loc(bb);
|
||||
live.seek_before_primary_effect(loc);
|
||||
writeln!(w, " // live: {:?}", live.get())?;
|
||||
}
|
||||
|
||||
PassWhere::BeforeBlock(bb) if reachable.contains(bb) => {
|
||||
live.seek_to_block_start(bb);
|
||||
writeln!(w, " // live: {:?}", live.get())?;
|
||||
}
|
||||
|
||||
PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {}
|
||||
|
||||
PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => {
|
||||
writeln!(w, " // live: <unreachable>")?;
|
||||
}
|
||||
|
||||
PassWhere::BeforeBlock(_) => {
|
||||
writeln!(w, " // live: <unreachable>")?;
|
||||
}
|
||||
if let PassWhere::BeforeLocation(loc) = pass_where {
|
||||
writeln!(w, " // live: {:?}", locals_live_at(loc))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -128,7 +128,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
if let Some(def_id) = self.typeck_results().type_dependent_def_id(id) {
|
||||
self.check_def_id(def_id);
|
||||
} else {
|
||||
bug!("no type-dependent def for method");
|
||||
assert!(
|
||||
self.typeck_results().tainted_by_errors.is_some(),
|
||||
"no type-dependent def for method"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
derivative = "2.2.0"
|
||||
rustc-hash = "1.1.0"
|
||||
rustc_apfloat = "0.2.0"
|
||||
rustc_arena = { path = "../rustc_arena", optional = true }
|
||||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||
|
|
|
|||
|
|
@ -155,13 +155,13 @@ use std::iter::once;
|
|||
use smallvec::SmallVec;
|
||||
|
||||
use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
|
||||
use rustc_index::bit_set::{BitSet, GrowableBitSet};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
|
||||
use self::Constructor::*;
|
||||
use self::MaybeInfiniteInt::*;
|
||||
use self::SliceKind::*;
|
||||
|
||||
use crate::index;
|
||||
use crate::usefulness::PlaceCtxt;
|
||||
use crate::TypeCx;
|
||||
|
||||
|
|
@ -804,7 +804,10 @@ pub enum ConstructorSet<Cx: TypeCx> {
|
|||
Struct { empty: bool },
|
||||
/// This type has the following list of constructors. If `variants` is empty and
|
||||
/// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
|
||||
Variants { variants: IndexVec<Cx::VariantIdx, VariantVisibility>, non_exhaustive: bool },
|
||||
Variants {
|
||||
variants: index::IdxContainer<Cx::VariantIdx, VariantVisibility>,
|
||||
non_exhaustive: bool,
|
||||
},
|
||||
/// The type is `&T`.
|
||||
Ref,
|
||||
/// The type is a union.
|
||||
|
|
@ -904,7 +907,7 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
|
|||
}
|
||||
}
|
||||
ConstructorSet::Variants { variants, non_exhaustive } => {
|
||||
let mut seen_set: BitSet<_> = BitSet::new_empty(variants.len());
|
||||
let mut seen_set = index::IdxSet::new_empty(variants.len());
|
||||
for idx in seen.iter().map(|c| c.as_variant().unwrap()) {
|
||||
seen_set.insert(idx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,45 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
|||
|
||||
use std::fmt;
|
||||
|
||||
use rustc_index::Idx;
|
||||
#[cfg(feature = "rustc")]
|
||||
pub mod index {
|
||||
// Faster version when the indices of variants are `0..variants.len()`.
|
||||
pub use rustc_index::bit_set::BitSet as IdxSet;
|
||||
pub use rustc_index::Idx;
|
||||
pub use rustc_index::IndexVec as IdxContainer;
|
||||
}
|
||||
#[cfg(not(feature = "rustc"))]
|
||||
pub mod index {
|
||||
// Slower version when the indices of variants are something else.
|
||||
pub trait Idx: Copy + PartialEq + Eq + std::hash::Hash {}
|
||||
impl<T: Copy + PartialEq + Eq + std::hash::Hash> Idx for T {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IdxContainer<K, V>(pub rustc_hash::FxHashMap<K, V>);
|
||||
impl<K: Idx, V> IdxContainer<K, V> {
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
pub fn iter_enumerated(&self) -> impl Iterator<Item = (K, &V)> {
|
||||
self.0.iter().map(|(k, v)| (*k, v))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IdxSet<T>(pub rustc_hash::FxHashSet<T>);
|
||||
impl<T: Idx> IdxSet<T> {
|
||||
pub fn new_empty(_len: usize) -> Self {
|
||||
Self(Default::default())
|
||||
}
|
||||
pub fn contains(&self, elem: T) -> bool {
|
||||
self.0.contains(&elem)
|
||||
}
|
||||
pub fn insert(&mut self, elem: T) {
|
||||
self.0.insert(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustc")]
|
||||
use rustc_middle::ty::Ty;
|
||||
#[cfg(feature = "rustc")]
|
||||
|
|
@ -48,7 +86,7 @@ pub trait TypeCx: Sized + fmt::Debug {
|
|||
/// Errors that can abort analysis.
|
||||
type Error: fmt::Debug;
|
||||
/// The index of an enum variant.
|
||||
type VariantIdx: Clone + Idx;
|
||||
type VariantIdx: Clone + index::Idx + fmt::Debug;
|
||||
/// A string literal
|
||||
type StrLit: Clone + PartialEq + fmt::Debug;
|
||||
/// Extra data to store in a match arm.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ pub fn opts() -> TargetOptions {
|
|||
dynamic_linking: true,
|
||||
families: cvs!["unix"],
|
||||
has_rpath: true,
|
||||
crt_static_respected: true,
|
||||
position_independent_executables: true,
|
||||
relro_level: RelroLevel::Full,
|
||||
abi_return_struct_as_int: true,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
//! or [`BinaryHeap<T>`], the adapters guarantee to consume enough items per step to make room
|
||||
//! for the results (represented by [`InPlaceIterable`]), provide transitive access to `source`
|
||||
//! (via [`SourceIter`]) and thus the underlying allocation.
|
||||
//! And finally there are alignment and size constriants to consider, this is currently ensured via
|
||||
//! And finally there are alignment and size constraints to consider, this is currently ensured via
|
||||
//! const eval instead of trait bounds in the specialized [`SpecFromIter`] implementation.
|
||||
//!
|
||||
//! [`BinaryHeap<T>`]: crate::collections::BinaryHeap
|
||||
|
|
|
|||
|
|
@ -121,10 +121,16 @@ extern "C" {}
|
|||
#[link(name = "unwind", kind = "static", modifiers = "-bundle")]
|
||||
extern "C" {}
|
||||
|
||||
#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
|
||||
#[cfg(target_os = "netbsd")]
|
||||
#[link(name = "gcc_s")]
|
||||
extern "C" {}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[link(name = "gcc", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "gcc_eh", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
|
||||
#[cfg(all(target_os = "openbsd", target_arch = "sparc64"))]
|
||||
#[link(name = "gcc")]
|
||||
extern "C" {}
|
||||
|
|
|
|||
|
|
@ -917,6 +917,19 @@ class RustBuild(object):
|
|||
if toml_val is not None:
|
||||
env["{}_{}".format(var_name, host_triple_sanitized)] = toml_val
|
||||
|
||||
# In src/etc/rust_analyzer_settings.json, we configure rust-analyzer to
|
||||
# pass RUSTC_BOOTSTRAP=1 to all cargo invocations because the standard
|
||||
# library uses unstable Cargo features. Without RUSTC_BOOTSTRAP,
|
||||
# rust-analyzer would fail to fetch workspace layout when the system's
|
||||
# default toolchain is not nightly.
|
||||
#
|
||||
# But that setting has the collateral effect of rust-analyzer also
|
||||
# passing RUSTC_BOOTSTRAP=1 to all x.py invocations too (the various
|
||||
# overrideCommand). For compiling bootstrap, that is unwanted and can
|
||||
# cause spurious rebuilding of bootstrap when rust-analyzer x.py
|
||||
# invocations are interleaved with handwritten ones on the command line.
|
||||
env.pop("RUSTC_BOOTSTRAP", None)
|
||||
|
||||
# preserve existing RUSTFLAGS
|
||||
env.setdefault("RUSTFLAGS", "")
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ LL | let c1 : () = c;
|
|||
| expected due to this
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found closure `{mod1::f<T>::{closure#0} closure_args=(unavailable) args=[T, ?16t, extern "rust-call" fn(()), ?15t]}`
|
||||
found closure `{mod1::f<T>::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}`
|
||||
help: use parentheses to call this closure
|
||||
|
|
||||
LL | let c1 : () = c();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ LL | let c1 : () = c;
|
|||
| expected due to this
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found closure `{f<T>::{closure#0} closure_args=(unavailable) args=[T, ?16t, extern "rust-call" fn(()), ?15t]}`
|
||||
found closure `{f<T>::{closure#0} closure_args=(unavailable) args=[T, ?8t, extern "rust-call" fn(()), ?7t]}`
|
||||
help: use parentheses to call this closure
|
||||
|
|
||||
LL | let c1 : () = c();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
|
|||
| expected due to this
|
||||
|
|
||||
= note: expected fn pointer `fn(u8) -> u8`
|
||||
found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?6t]}`
|
||||
found closure `{main::{closure#0} closure_args=(unavailable) args=[i8, extern "rust-call" fn((u8,)) -> u8, ?4t]}`
|
||||
note: closures can only be coerced to `fn` types if they do not capture any variables
|
||||
--> $DIR/closure-print-verbose.rs:10:39
|
||||
|
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
//! This test tests two things at once:
|
||||
//! 1. we error if a const evaluation hits the deny-by-default lint limit
|
||||
//! 2. we do not ICE on invalid follow-up code
|
||||
|
||||
// compile-flags: -Z tiny-const-eval-limit
|
||||
|
||||
fn main() {
|
||||
// Tests the Collatz conjecture with an incorrect base case (0 instead of 1).
|
||||
// The value of `n` will loop indefinitely (4 - 2 - 1 - 4).
|
||||
let _ = [(); {
|
||||
let s = [(); {
|
||||
let mut n = 113383; // #20 in https://oeis.org/A006884
|
||||
while n != 0 {
|
||||
//~^ ERROR is taking a long time
|
||||
|
|
@ -9,4 +15,6 @@ fn main() {
|
|||
}
|
||||
n
|
||||
}];
|
||||
|
||||
s.nonexistent_method();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: constant evaluation is taking a long time
|
||||
--> $DIR/infinite_loop.rs:6:9
|
||||
--> $DIR/infinite_loop.rs:12:9
|
||||
|
|
||||
LL | / while n != 0 {
|
||||
LL | |
|
||||
|
|
@ -10,9 +10,9 @@ LL | | }
|
|||
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
|
||||
If your compilation actually takes a long time, you can safely allow the lint.
|
||||
help: the constant being evaluated
|
||||
--> $DIR/infinite_loop.rs:4:18
|
||||
--> $DIR/infinite_loop.rs:10:18
|
||||
|
|
||||
LL | let _ = [(); {
|
||||
LL | let s = [(); {
|
||||
| __________________^
|
||||
LL | | let mut n = 113383; // #20 in https://oeis.org/A006884
|
||||
LL | | while n != 0 {
|
||||
|
|
|
|||
21
tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs
Normal file
21
tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
//! This is a regression test to avoid an ICE in diagnostics code.
|
||||
//! A typo in the compiler used to get the DefId of FnOnce, and
|
||||
//! use it where an associated item was expected.
|
||||
|
||||
fn frob() -> impl Fn<P, Output = T> + '_ {}
|
||||
//~^ ERROR missing lifetime specifier
|
||||
//~| ERROR cannot find type `P`
|
||||
//~| ERROR cannot find type `T`
|
||||
//~| ERROR `Fn`-family traits' type parameters is subject to change
|
||||
|
||||
fn open_parent<'path>() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let old_path = frob("hello");
|
||||
//~^ ERROR function takes 0 arguments
|
||||
|
||||
open_parent(&old_path)
|
||||
//~^ ERROR function takes 0 arguments
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/opaque-used-in-extraneous-argument.rs:5:39
|
||||
|
|
||||
LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
|
||||
| ^^ expected named lifetime parameter
|
||||
|
|
||||
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
|
||||
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
|
||||
|
|
||||
LL | fn frob() -> impl Fn<P, Output = T> + 'static {}
|
||||
| ~~~~~~~
|
||||
|
||||
error[E0412]: cannot find type `P` in this scope
|
||||
--> $DIR/opaque-used-in-extraneous-argument.rs:5:22
|
||||
|
|
||||
LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
|
||||
| ^ not found in this scope
|
||||
|
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | fn frob<P>() -> impl Fn<P, Output = T> + '_ {}
|
||||
| +++
|
||||
|
||||
error[E0412]: cannot find type `T` in this scope
|
||||
--> $DIR/opaque-used-in-extraneous-argument.rs:5:34
|
||||
|
|
||||
LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
|
||||
| ^ not found in this scope
|
||||
|
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | fn frob<T>() -> impl Fn<P, Output = T> + '_ {}
|
||||
| +++
|
||||
|
||||
error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
|
||||
--> $DIR/opaque-used-in-extraneous-argument.rs:5:19
|
||||
|
|
||||
LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
|
||||
| ^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(P) -> T`
|
||||
|
|
||||
= note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
|
||||
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0061]: this function takes 0 arguments but 1 argument was supplied
|
||||
--> $DIR/opaque-used-in-extraneous-argument.rs:16:20
|
||||
|
|
||||
LL | let old_path = frob("hello");
|
||||
| ^^^^ -------
|
||||
| |
|
||||
| unexpected argument of type `&'static str`
|
||||
| help: remove the extra argument
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/opaque-used-in-extraneous-argument.rs:5:4
|
||||
|
|
||||
LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
|
||||
| ^^^^
|
||||
|
||||
error[E0061]: this function takes 0 arguments but 1 argument was supplied
|
||||
--> $DIR/opaque-used-in-extraneous-argument.rs:19:5
|
||||
|
|
||||
LL | open_parent(&old_path)
|
||||
| ^^^^^^^^^^^ ---------
|
||||
| |
|
||||
| unexpected argument of type `&impl FnOnce<{type error}, Output = {type error}> + Fn<{type error}> + 'static`
|
||||
| help: remove the extra argument
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/opaque-used-in-extraneous-argument.rs:11:4
|
||||
|
|
||||
LL | fn open_parent<'path>() {
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0061, E0106, E0412, E0658.
|
||||
For more information about an error, try `rustc --explain E0061`.
|
||||
35
tests/ui/type-alias-impl-trait/closure_infer.rs
Normal file
35
tests/ui/type-alias-impl-trait/closure_infer.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// check-pass
|
||||
|
||||
// Regression test for an ICE: https://github.com/rust-lang/rust/issues/119916
|
||||
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
// `impl_trait_in_assoc_type` example from the bug report.
|
||||
pub trait StreamConsumer {
|
||||
type BarrierStream;
|
||||
fn execute() -> Self::BarrierStream;
|
||||
}
|
||||
|
||||
pub struct DispatchExecutor;
|
||||
|
||||
impl StreamConsumer for DispatchExecutor {
|
||||
type BarrierStream = impl Sized;
|
||||
fn execute() -> Self::BarrierStream {
|
||||
|| -> _ {}
|
||||
}
|
||||
}
|
||||
|
||||
// Functions that constrain TAITs can contain closures with an `_` in the return type.
|
||||
type Foo = impl Sized;
|
||||
fn foo() -> Foo {
|
||||
|| -> _ {}
|
||||
}
|
||||
|
||||
// The `_` in the closure return type can also be the TAIT itself.
|
||||
type Bar = impl Sized;
|
||||
fn bar() -> impl FnOnce() -> Bar {
|
||||
|| -> _ {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -12,3 +12,8 @@ fn test() -> Pointer<_> {
|
|||
fn main() {
|
||||
test();
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
fn bar() -> Pointer<_>;
|
||||
//~^ ERROR: the placeholder `_` is not allowed within types
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,15 @@ LL | fn test() -> Pointer<_> {
|
|||
| | not allowed in type signatures
|
||||
| help: replace with the correct return type: `Pointer<i32>`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
|
||||
--> $DIR/issue-77179.rs:17:25
|
||||
|
|
||||
LL | fn bar() -> Pointer<_>;
|
||||
| ^
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
| help: use type parameters instead: `T`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0121`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue