1
Fork 0

Auto merge of #139781 - jhpratt:rollup-qadsjvb, r=jhpratt

Rollup of 9 pull requests

Successful merges:

 - #138336 (Improve `-Z crate-attr` diagnostics)
 - #139636 (Encode dep node edge count as u32 instead of usize)
 - #139666 (cleanup `mir_borrowck`)
 - #139695 (compiletest: consistently use `camino::{Utf8Path,Utf8PathBuf}` throughout)
 - #139699 (Proactively update coroutine drop shim's phase to account for later passes applied during shim query)
 - #139718 (enforce unsafe attributes in pre-2024 editions by default)
 - #139722 (Move some things to rustc_type_ir)
 - #139760 (UI tests: migrate remaining compile time `error-pattern`s to line annotations when possible)
 - #139776 (Switch attrs to `diagnostic::on_unimplemented`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-04-14 07:07:54 +00:00
commit 5961e5ba3d
152 changed files with 1818 additions and 1713 deletions

View file

@ -627,7 +627,7 @@ pub fn mk_doc_comment(
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
}
pub fn mk_attr(
fn mk_attr(
g: &AttrIdGenerator,
style: AttrStyle,
unsafety: Safety,

View file

@ -21,6 +21,7 @@ use std::cell::RefCell;
use std::marker::PhantomData;
use std::ops::{ControlFlow, Deref};
use borrow_set::LocalsStateAtExit;
use root_cx::BorrowCheckRootCtxt;
use rustc_abi::FieldIdx;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@ -303,33 +304,13 @@ fn do_mir_borrowck<'tcx>(
root_cx.set_tainted_by_errors(e);
}
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
for var_debug_info in &input_body.var_debug_info {
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
if let Some(local) = place.as_local() {
if let Some(prev_name) = local_names[local]
&& var_debug_info.name != prev_name
{
span_bug!(
var_debug_info.source_info.span,
"local {:?} has many names (`{}` vs `{}`)",
local,
prev_name,
var_debug_info.name
);
}
local_names[local] = Some(var_debug_info.name);
}
}
}
// Replace all regions with fresh inference variables. This
// requires first making our own copy of the MIR. This copy will
// be modified (in place) to contain non-lexical lifetimes. It
// will have a lifetime tied to the inference context.
let mut body_owned = input_body.clone();
let mut promoted = input_promoted.to_owned();
let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
let body = &body_owned; // no further changes
let location_table = PoloniusLocationTable::new(body);
@ -354,7 +335,7 @@ fn do_mir_borrowck<'tcx>(
} = nll::compute_regions(
root_cx,
&infcx,
free_regions,
universal_regions,
body,
&promoted,
&location_table,
@ -367,24 +348,23 @@ fn do_mir_borrowck<'tcx>(
// Dump MIR results into a file, if that is enabled. This lets us
// write unit-tests, as well as helping with debugging.
nll::dump_nll_mir(&infcx, body, &regioncx, &opt_closure_req, &borrow_set);
polonius::dump_polonius_mir(
&infcx,
body,
&regioncx,
&opt_closure_req,
&borrow_set,
polonius_diagnostics.as_ref(),
);
// We also have a `#[rustc_regions]` annotation that causes us to dump
// information.
nll::dump_annotation(&infcx, body, &regioncx, &opt_closure_req);
let movable_coroutine = body.coroutine.is_some()
&& tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
nll::dump_annotation(&infcx, body, &regioncx, &opt_closure_req, diags_buffer);
let movable_coroutine =
// The first argument is the coroutine type passed by value
if let Some(local) = body.local_decls.raw.get(1)
// Get the interior types and args which typeck computed
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
{
true
} else {
false
};
// While promoteds should mostly be correct by construction, we need to check them for
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
for promoted_body in &promoted {
@ -402,7 +382,6 @@ fn do_mir_borrowck<'tcx>(
location_table: &location_table,
movable_coroutine,
fn_self_span_reported: Default::default(),
locals_are_invalidated_at_exit,
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
uninitialized_error_reported: Default::default(),
@ -434,6 +413,26 @@ fn do_mir_borrowck<'tcx>(
promoted_mbcx.report_move_errors();
}
let mut local_names = IndexVec::from_elem(None, &body.local_decls);
for var_debug_info in &body.var_debug_info {
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
if let Some(local) = place.as_local() {
if let Some(prev_name) = local_names[local]
&& var_debug_info.name != prev_name
{
span_bug!(
var_debug_info.source_info.span,
"local {:?} has many names (`{}` vs `{}`)",
local,
prev_name,
var_debug_info.name
);
}
local_names[local] = Some(var_debug_info.name);
}
}
}
let mut mbcx = MirBorrowckCtxt {
root_cx,
infcx: &infcx,
@ -441,7 +440,6 @@ fn do_mir_borrowck<'tcx>(
move_data: &move_data,
location_table: &location_table,
movable_coroutine,
locals_are_invalidated_at_exit,
fn_self_span_reported: Default::default(),
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
@ -454,9 +452,9 @@ fn do_mir_borrowck<'tcx>(
local_names,
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
polonius_output,
move_errors: Vec::new(),
diags_buffer,
polonius_output: polonius_output.as_deref(),
polonius_diagnostics: polonius_diagnostics.as_ref(),
};
@ -473,16 +471,6 @@ fn do_mir_borrowck<'tcx>(
mbcx.report_move_errors();
// If requested, dump polonius MIR.
polonius::dump_polonius_mir(
&infcx,
body,
&regioncx,
&borrow_set,
polonius_diagnostics.as_ref(),
&opt_closure_req,
);
// For each non-user used mutable variable, check if it's been assigned from
// a user-declared local. If so, then put that local into the used_mut set.
// Note that this set is expected to be small - only upvars from closures
@ -513,7 +501,6 @@ fn do_mir_borrowck<'tcx>(
};
let body_with_facts = if consumer_options.is_some() {
let output_facts = mbcx.polonius_output;
Some(Box::new(BodyWithBorrowckFacts {
body: body_owned,
promoted,
@ -521,7 +508,7 @@ fn do_mir_borrowck<'tcx>(
region_inference_context: regioncx,
location_table: polonius_input.as_ref().map(|_| location_table),
input_facts: polonius_input,
output_facts,
output_facts: polonius_output,
}))
} else {
None
@ -654,13 +641,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
location_table: &'a PoloniusLocationTable,
movable_coroutine: bool,
/// This keeps track of whether local variables are free-ed when the function
/// exits even without a `StorageDead`, which appears to be the case for
/// constants.
///
/// I'm not sure this is the right approach - @eddyb could you try and
/// figure this out?
locals_are_invalidated_at_exit: bool,
/// This field keeps track of when borrow errors are reported in the access_place function
/// so that there is no duplicate reporting. This field cannot also be used for the conflicting
/// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
@ -708,12 +688,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
/// The counter for generating new region names.
next_region_name: RefCell<usize>,
/// Results of Polonius analysis.
polonius_output: Option<Box<PoloniusOutput>>,
diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
move_errors: Vec<MoveError<'tcx>>,
/// Results of Polonius analysis.
polonius_output: Option<&'a PoloniusOutput>,
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
}
@ -937,13 +916,20 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
| TerminatorKind::Return
| TerminatorKind::TailCall { .. }
| TerminatorKind::CoroutineDrop => {
// Returning from the function implicitly kills storage for all locals and statics.
// Often, the storage will already have been killed by an explicit
// StorageDead, but we don't always emit those (notably on unwind paths),
// so this "extra check" serves as a kind of backup.
for i in state.borrows.iter() {
let borrow = &self.borrow_set[i];
self.check_for_invalidation_at_exit(loc, borrow, span);
match self.borrow_set.locals_state_at_exit() {
LocalsStateAtExit::AllAreInvalidated => {
// Returning from the function implicitly kills storage for all locals and statics.
// Often, the storage will already have been killed by an explicit
// StorageDead, but we don't always emit those (notably on unwind paths),
// so this "extra check" serves as a kind of backup.
for i in state.borrows.iter() {
let borrow = &self.borrow_set[i];
self.check_for_invalidation_at_exit(loc, borrow, span);
}
}
// If we do not implicitly invalidate all locals on exit,
// we check for conflicts when dropping or moving this local.
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
}
}
@ -1715,22 +1701,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
// we'll have a memory leak) and assume that all statics have a destructor.
//
// FIXME: allow thread-locals to borrow other thread locals?
let (might_be_alive, will_be_dropped) =
if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
// Thread-locals might be dropped after the function exits
// We have to dereference the outer reference because
// borrows don't conflict behind shared references.
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
(true, true)
} else {
(false, self.locals_are_invalidated_at_exit)
};
if !will_be_dropped {
debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
return;
}
let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
// Thread-locals might be dropped after the function exits
// We have to dereference the outer reference because
// borrows don't conflict behind shared references.
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
true
} else {
false
};
let sd = if might_be_alive { Deep } else { Shallow(None) };

View file

@ -21,7 +21,7 @@ use tracing::{debug, instrument};
use crate::borrow_set::BorrowSet;
use crate::consumers::ConsumerOptions;
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
use crate::diagnostics::RegionErrors;
use crate::polonius::PoloniusDiagnosticsContext;
use crate::polonius::legacy::{
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
@ -117,11 +117,6 @@ pub(crate) fn compute_regions<'a, 'tcx>(
Rc::clone(&location_map),
);
// Create the region inference context, taking ownership of the
// region inference data that was contained in `infcx`, and the
// base constraints generated by the type-check.
let var_infos = infcx.get_region_var_infos();
// If requested, emit legacy polonius facts.
polonius::legacy::emit_facts(
&mut polonius_facts,
@ -134,13 +129,8 @@ pub(crate) fn compute_regions<'a, 'tcx>(
&constraints,
);
let mut regioncx = RegionInferenceContext::new(
infcx,
var_infos,
constraints,
universal_region_relations,
location_map,
);
let mut regioncx =
RegionInferenceContext::new(infcx, constraints, universal_region_relations, location_map);
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
// and use them to compute loan liveness.
@ -297,7 +287,6 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
) {
let tcx = infcx.tcx;
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
@ -335,13 +324,11 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
} else {
let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements");
regioncx.annotate(tcx, &mut err);
err
};
// FIXME(@lcnr): We currently don't dump the inferred hidden types here.
diagnostics_buffer.buffer_non_error(err);
err.emit();
}
fn for_each_region_constraint<'tcx>(

View file

@ -24,9 +24,9 @@ pub(crate) fn dump_polonius_mir<'tcx>(
infcx: &BorrowckInferCtxt<'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
borrow_set: &BorrowSet<'tcx>,
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
) {
let tcx = infcx.tcx;
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {

View file

@ -9,7 +9,7 @@ use rustc_errors::Diag;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_index::IndexVec;
use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound, VerifyIfEq};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::bug;
use rustc_middle::mir::{
@ -145,7 +145,7 @@ pub struct RegionInferenceContext<'tcx> {
/// variables are identified by their index (`RegionVid`). The
/// definition contains information about where the region came
/// from as well as its final inferred value.
pub(crate) definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
pub(crate) definitions: Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>,
/// The liveness constraints added to each region. For most
/// regions, these start out empty and steadily grow, though for
@ -385,6 +385,26 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
debug!("SCC edges {:#?}", scc_node_to_edges);
}
fn create_definitions<'tcx>(
infcx: &BorrowckInferCtxt<'tcx>,
universal_regions: &UniversalRegions<'tcx>,
) -> Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>> {
// Create a RegionDefinition for each inference variable.
let mut definitions: IndexVec<_, _> = infcx
.get_region_var_infos()
.iter()
.map(|info| RegionDefinition::new(info.universe, info.origin))
.collect();
// Add the external name for all universal regions.
for (external_name, variable) in universal_regions.named_universal_regions_iter() {
debug!("region {variable:?} has external name {external_name:?}");
definitions[variable].external_name = Some(external_name);
}
Frozen::freeze(definitions)
}
impl<'tcx> RegionInferenceContext<'tcx> {
/// Creates a new region inference context with a total of
/// `num_region_variables` valid inference variables; the first N
@ -395,7 +415,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// of constraints produced by the MIR type check.
pub(crate) fn new(
infcx: &BorrowckInferCtxt<'tcx>,
var_infos: VarInfos,
constraints: MirTypeckRegionConstraints<'tcx>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
location_map: Rc<DenseLocationMap>,
@ -426,11 +445,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
infcx.set_tainted_by_errors(guar);
}
// Create a RegionDefinition for each inference variable.
let definitions: IndexVec<_, _> = var_infos
.iter()
.map(|info| RegionDefinition::new(info.universe, info.origin))
.collect();
let definitions = create_definitions(infcx, &universal_regions);
let constraint_sccs =
outlives_constraints.add_outlives_static(&universal_regions, &definitions);
@ -526,18 +541,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// means that the `R1: !1` constraint here will cause
/// `R1` to become `'static`.
fn init_free_and_bound_regions(&mut self) {
// Update the names (if any)
// This iterator has unstable order but we collect it all into an IndexVec
for (external_name, variable) in
self.universal_region_relations.universal_regions.named_universal_regions_iter()
{
debug!(
"init_free_and_bound_regions: region {:?} has external name {:?}",
variable, external_name
);
self.definitions[variable].external_name = Some(external_name);
}
for variable in self.definitions.indices() {
let scc = self.constraint_sccs.scc(variable);

View file

@ -21,7 +21,6 @@ use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategor
pub(crate) struct ConstraintConversion<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
universal_regions: &'a UniversalRegions<'tcx>,
/// Each RBP `GK: 'a` is assumed to be true. These encode
/// relationships like `T: 'a` that are added via implicit bounds
@ -34,7 +33,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
/// logic expecting to see (e.g.) `ReStatic`, and if we supplied
/// our special inference variable there, we would mess that up.
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
param_env: ty::ParamEnv<'tcx>,
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
locations: Locations,
@ -49,7 +47,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
universal_regions: &'a UniversalRegions<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
param_env: ty::ParamEnv<'tcx>,
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
locations: Locations,
@ -59,10 +56,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
) -> Self {
Self {
infcx,
tcx: infcx.tcx,
universal_regions,
region_bound_pairs,
implicit_region_bound,
param_env,
known_type_outlives_obligations,
locations,
@ -96,7 +91,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
// into a vector. These are the regions that we will be
// relating to one another.
let closure_mapping = &UniversalRegions::closure_mapping(
self.tcx,
self.infcx.tcx,
closure_args,
closure_requirements.num_external_vids,
closure_def_id,
@ -111,7 +106,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
let subject = match outlives_requirement.subject {
ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
ClosureOutlivesSubject::Ty(subject_ty) => {
subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into()
subject_ty.instantiate(self.infcx.tcx, |vid| closure_mapping[vid]).into()
}
};
@ -127,14 +122,14 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
constraint_category: ConstraintCategory<'tcx>,
) {
let tcx = self.infcx.tcx;
debug!("generate: constraints at: {:#?}", self.locations);
// Extract out various useful fields we'll need below.
let ConstraintConversion {
tcx,
infcx,
universal_regions,
region_bound_pairs,
implicit_region_bound,
known_type_outlives_obligations,
..
} = *self;
@ -145,7 +140,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
break;
}
if !self.tcx.recursion_limit().value_within_limit(iteration) {
if !tcx.recursion_limit().value_within_limit(iteration) {
bug!(
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
);
@ -170,10 +165,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
);
}
let implicit_region_bound =
ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(self.span, t1, None);
TypeOutlives::new(
&mut *self,
tcx,
@ -205,7 +201,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
/// are dealt with during trait solving.
fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
if value.has_placeholders() {
fold_regions(self.tcx, value, |r, _| match r.kind() {
fold_regions(self.infcx.tcx, value, |r, _| match r.kind() {
ty::RePlaceholder(placeholder) => {
self.constraints.placeholder_region(self.infcx, placeholder)
}

View file

@ -49,14 +49,12 @@ pub(crate) struct CreateResult<'tcx> {
pub(crate) fn create<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
universal_regions: UniversalRegions<'tcx>,
constraints: &mut MirTypeckRegionConstraints<'tcx>,
) -> CreateResult<'tcx> {
UniversalRegionRelationsBuilder {
infcx,
param_env,
implicit_region_bound,
constraints,
universal_regions,
region_bound_pairs: Default::default(),
@ -181,7 +179,6 @@ struct UniversalRegionRelationsBuilder<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
universal_regions: UniversalRegions<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
// outputs:
@ -320,7 +317,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.infcx,
&self.universal_regions,
&self.region_bound_pairs,
self.implicit_region_bound,
param_env,
&known_type_outlives_obligations,
Locations::All(span),

View file

@ -113,7 +113,6 @@ pub(crate) fn type_check<'a, 'tcx>(
move_data: &MoveData<'tcx>,
location_map: Rc<DenseLocationMap>,
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
let mut constraints = MirTypeckRegionConstraints {
placeholder_indices: PlaceholderIndices::default(),
placeholder_index_to_region: IndexVec::default(),
@ -129,13 +128,7 @@ pub(crate) fn type_check<'a, 'tcx>(
region_bound_pairs,
normalized_inputs_and_output,
known_type_outlives_obligations,
} = free_region_relations::create(
infcx,
infcx.param_env,
implicit_region_bound,
universal_regions,
&mut constraints,
);
} = free_region_relations::create(infcx, infcx.param_env, universal_regions, &mut constraints);
let pre_obligations = infcx.take_registered_region_obligations();
assert!(
@ -160,7 +153,6 @@ pub(crate) fn type_check<'a, 'tcx>(
user_type_annotations: &body.user_type_annotations,
region_bound_pairs,
known_type_outlives_obligations,
implicit_region_bound,
reported_errors: Default::default(),
universal_regions: &universal_region_relations.universal_regions,
location_table,
@ -226,7 +218,6 @@ struct TypeChecker<'a, 'tcx> {
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
region_bound_pairs: RegionBoundPairs<'tcx>,
known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
implicit_region_bound: ty::Region<'tcx>,
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
universal_regions: &'a UniversalRegions<'tcx>,
location_table: &'a PoloniusLocationTable,
@ -422,7 +413,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.infcx,
self.universal_regions,
&self.region_bound_pairs,
self.implicit_region_bound,
self.infcx.param_env,
&self.known_type_outlives_obligations,
locations,
@ -2507,7 +2497,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.infcx,
self.universal_regions,
&self.region_bound_pairs,
self.implicit_region_bound,
self.infcx.param_env,
&self.known_type_outlives_obligations,
locations,

View file

@ -438,6 +438,10 @@ impl<'tcx> UniversalRegions<'tcx> {
}
}
pub(crate) fn implicit_region_bound(&self) -> RegionVid {
self.fr_fn_body
}
pub(crate) fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
self.indices.tainted_by_errors.get()
}

View file

@ -231,8 +231,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
builtin_macros_format_use_positional = consider using a positional formatting argument instead
builtin_macros_invalid_crate_attribute = invalid crate attribute
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
.note = only one `#[default]` attribute is needed
.label = `#[default]` used here

View file

@ -1,44 +1,37 @@
//! Attributes injected into the crate root from command line using `-Z crate-attr`.
use rustc_ast::attr::mk_attr;
use rustc_ast::{self as ast, AttrItem, AttrStyle, token};
use rustc_parse::parser::ForceCollect;
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
use rustc_ast::{self as ast};
use rustc_errors::Diag;
use rustc_parse::parser::attr::InnerAttrPolicy;
use rustc_parse::{parse_in, source_str_to_stream};
use rustc_session::parse::ParseSess;
use rustc_span::FileName;
use crate::errors;
pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
for raw_attr in attrs {
let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
psess,
FileName::cli_crate_attr_source_code(raw_attr),
raw_attr.clone(),
));
let start_span = parser.token.span;
let AttrItem { unsafety, path, args, tokens: _ } =
match parser.parse_attr_item(ForceCollect::No) {
Ok(ai) => ai,
Err(err) => {
let source = format!("#![{raw_attr}]");
let parse = || -> Result<ast::Attribute, Vec<Diag<'_>>> {
let tokens = source_str_to_stream(
psess,
FileName::cli_crate_attr_source_code(raw_attr),
source,
None,
)?;
parse_in(psess, tokens, "<crate attribute>", |p| {
p.parse_attribute(InnerAttrPolicy::Permitted)
})
.map_err(|e| vec![e])
};
let meta = match parse() {
Ok(meta) => meta,
Err(errs) => {
for err in errs {
err.emit();
continue;
}
};
let end_span = parser.token.span;
if parser.token != token::Eof {
psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
continue;
}
continue;
}
};
krate.attrs.push(mk_attr(
&psess.attr_id_generator,
AttrStyle::Inner,
unsafety,
path,
args,
start_span.to(end_span),
));
krate.attrs.push(meta);
}
}

View file

@ -109,13 +109,6 @@ pub(crate) struct ProcMacro {
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_invalid_crate_attribute)]
pub(crate) struct InvalidCrateAttr {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_non_abi)]
pub(crate) struct NonABI {

View file

@ -1,13 +1,13 @@
use std::alloc::Allocator;
#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")]
// This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()`
// is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a
// `Send` type in `IntoDynSyncSend` will create a `DynSend` type.
pub unsafe auto trait DynSend {}
#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`")]
// This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()`
// is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a

View file

@ -5,7 +5,7 @@ Erroneous code example:
```compile_fail,E0755
#![feature(ffi_pure)]
#[ffi_pure] // error!
#[unsafe(ffi_pure)] // error!
pub fn foo() {}
# fn main() {}
```
@ -17,7 +17,7 @@ side effects or infinite loops:
#![feature(ffi_pure)]
extern "C" {
#[ffi_pure] // ok!
#[unsafe(ffi_pure)] // ok!
pub fn strlen(s: *const i8) -> isize;
}
# fn main() {}

View file

@ -6,7 +6,7 @@ Erroneous code example:
```compile_fail,E0756
#![feature(ffi_const)]
#[ffi_const] // error!
#[unsafe(ffi_const)] // error!
pub fn foo() {}
# fn main() {}
```
@ -18,7 +18,7 @@ which have no side effects except for their return value:
#![feature(ffi_const)]
extern "C" {
#[ffi_const] // ok!
#[unsafe(ffi_const)] // ok!
pub fn strlen(s: *const i8) -> i32;
}
# fn main() {}

View file

@ -6,8 +6,9 @@ Erroneous code example:
#![feature(ffi_const, ffi_pure)]
extern "C" {
#[ffi_const]
#[ffi_pure] // error: `#[ffi_const]` function cannot be `#[ffi_pure]`
#[unsafe(ffi_const)]
#[unsafe(ffi_pure)]
//~^ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]`
pub fn square(num: i32) -> i32;
}
```
@ -19,7 +20,7 @@ As `ffi_const` provides stronger guarantees than `ffi_pure`, remove the
#![feature(ffi_const)]
extern "C" {
#[ffi_const]
#[unsafe(ffi_const)]
pub fn square(num: i32) -> i32;
}
```

View file

@ -6,6 +6,7 @@ use AttributeDuplicates::*;
use AttributeGate::*;
use AttributeType::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_span::edition::Edition;
use rustc_span::{Symbol, sym};
use crate::{Features, Stability};
@ -65,9 +66,12 @@ pub enum AttributeSafety {
/// Normal attribute that does not need `#[unsafe(...)]`
Normal,
/// Unsafe attribute that requires safety obligations
/// to be discharged
Unsafe,
/// Unsafe attribute that requires safety obligations to be discharged.
///
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
/// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
/// earlier editions, but become unsafe in later ones.
Unsafe { unsafe_since: Option<Edition> },
}
#[derive(Clone, Copy)]
@ -187,12 +191,23 @@ macro_rules! template {
}
macro_rules! ungated {
(unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) },
template: $tpl,
gate: Ungated,
duplicates: $duplicates,
}
};
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe,
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
gate: Ungated,
duplicates: $duplicates,
@ -217,7 +232,7 @@ macro_rules! gated {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe,
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
@ -228,7 +243,7 @@ macro_rules! gated {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe,
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
@ -423,9 +438,9 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),

View file

@ -89,7 +89,6 @@ macro_rules! arena_types {
[] name_set: rustc_data_structures::unord::UnordSet<rustc_span::Symbol>,
[] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem,
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::Symbol>,
[] pats: rustc_middle::ty::PatternKind<'tcx>,
[] valtree: rustc_middle::ty::ValTreeKind<'tcx>,
// Note that this deliberately duplicates items in the `rustc_hir::arena`,

View file

@ -3,6 +3,7 @@ use std::borrow::Cow;
use rustc_data_structures::intern::Interned;
use rustc_error_messages::MultiSpan;
use rustc_macros::HashStable;
use rustc_type_ir::walk::TypeWalker;
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
use crate::ty::{self, Ty, TyCtxt};
@ -243,4 +244,18 @@ impl<'tcx> Const<'tcx> {
pub fn is_ct_infer(self) -> bool {
matches!(self.kind(), ty::ConstKind::Infer(_))
}
/// Iterator that walks `self` and any types reachable from
/// `self`, in depth-first order. Note that just walks the types
/// that appear in `self`, it does not descend into the fields of
/// structs or variants. For example:
///
/// ```text
/// isize => { isize }
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize }
/// ```
pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
TypeWalker::new(self.into())
}
}

View file

@ -870,7 +870,7 @@ impl<'tcx> CtxtInterners<'tcx> {
Ty(Interned::new_unchecked(
self.type_
.intern(kind, |kind| {
let flags = super::flags::FlagComputation::for_kind(&kind);
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_kind(&kind);
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
@ -896,7 +896,7 @@ impl<'tcx> CtxtInterners<'tcx> {
Const(Interned::new_unchecked(
self.const_
.intern(kind, |kind: ty::ConstKind<'_>| {
let flags = super::flags::FlagComputation::for_const_kind(&kind);
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_const_kind(&kind);
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
@ -912,7 +912,7 @@ impl<'tcx> CtxtInterners<'tcx> {
fn stable_hash<'a, T: HashStable<StableHashingContext<'a>>>(
&self,
flags: &ty::flags::FlagComputation,
flags: &ty::FlagComputation<TyCtxt<'tcx>>,
sess: &'a Session,
untracked: &'a Untracked,
val: &T,
@ -940,7 +940,7 @@ impl<'tcx> CtxtInterners<'tcx> {
Predicate(Interned::new_unchecked(
self.predicate
.intern(kind, |kind| {
let flags = super::flags::FlagComputation::for_predicate(kind);
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_predicate(kind);
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
@ -961,7 +961,7 @@ impl<'tcx> CtxtInterners<'tcx> {
} else {
self.clauses
.intern_ref(clauses, || {
let flags = super::flags::FlagComputation::for_clauses(clauses);
let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_clauses(clauses);
InternedInSet(ListWithCachedTypeInfo::from_arena(
&*self.arena,

View file

@ -1,359 +0,0 @@
use std::slice;
use crate::ty::{self, GenericArg, GenericArgKind, InferConst, Ty, TypeFlags};
#[derive(Debug)]
pub struct FlagComputation {
pub flags: TypeFlags,
/// see `Ty::outer_exclusive_binder` for details
pub outer_exclusive_binder: ty::DebruijnIndex,
}
impl FlagComputation {
fn new() -> FlagComputation {
FlagComputation { flags: TypeFlags::empty(), outer_exclusive_binder: ty::INNERMOST }
}
#[allow(rustc::usage_of_ty_tykind)]
pub fn for_kind(kind: &ty::TyKind<'_>) -> FlagComputation {
let mut result = FlagComputation::new();
result.add_kind(kind);
result
}
pub fn for_predicate(binder: ty::Binder<'_, ty::PredicateKind<'_>>) -> FlagComputation {
let mut result = FlagComputation::new();
result.add_predicate(binder);
result
}
pub fn for_const_kind(kind: &ty::ConstKind<'_>) -> FlagComputation {
let mut result = FlagComputation::new();
result.add_const_kind(kind);
result
}
pub fn for_clauses(clauses: &[ty::Clause<'_>]) -> FlagComputation {
let mut result = FlagComputation::new();
for c in clauses {
result.add_flags(c.as_predicate().flags());
result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder());
}
result
}
fn add_flags(&mut self, flags: TypeFlags) {
self.flags = self.flags | flags;
}
/// indicates that `self` refers to something at binding level `binder`
fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
let exclusive_binder = binder.shifted_in(1);
self.add_exclusive_binder(exclusive_binder);
}
/// indicates that `self` refers to something *inside* binding
/// level `binder` -- not bound by `binder`, but bound by the next
/// binder internal to it
fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
}
/// Adds the flags/depth from a set of types that appear within the current type, but within a
/// region binder.
fn bound_computation<T, F>(&mut self, value: ty::Binder<'_, T>, f: F)
where
F: FnOnce(&mut Self, T),
{
let mut computation = FlagComputation::new();
if !value.bound_vars().is_empty() {
computation.add_flags(TypeFlags::HAS_BINDER_VARS);
}
f(&mut computation, value.skip_binder());
self.add_flags(computation.flags);
// The types that contributed to `computation` occurred within
// a region binder, so subtract one from the region depth
// within when adding the depth to `self`.
let outer_exclusive_binder = computation.outer_exclusive_binder;
if outer_exclusive_binder > ty::INNERMOST {
self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
} // otherwise, this binder captures nothing
}
#[allow(rustc::usage_of_ty_tykind)]
fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
match kind {
&ty::Bool
| &ty::Char
| &ty::Int(_)
| &ty::Float(_)
| &ty::Uint(_)
| &ty::Never
| &ty::Str
| &ty::Foreign(..) => {}
&ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
&ty::Param(_) => {
self.add_flags(TypeFlags::HAS_TY_PARAM);
}
&ty::Closure(_, args)
| &ty::Coroutine(_, args)
| &ty::CoroutineClosure(_, args)
| &ty::CoroutineWitness(_, args) => {
self.add_args(args);
}
&ty::Bound(debruijn, _) => {
self.add_bound_var(debruijn);
self.add_flags(TypeFlags::HAS_TY_BOUND);
}
&ty::Placeholder(..) => {
self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
}
&ty::Infer(infer) => match infer {
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
self.add_flags(TypeFlags::HAS_TY_FRESH)
}
ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
self.add_flags(TypeFlags::HAS_TY_INFER)
}
},
&ty::Adt(_, args) => {
self.add_args(args);
}
&ty::Alias(kind, data) => {
self.add_flags(match kind {
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
ty::Weak => TypeFlags::HAS_TY_WEAK,
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
});
self.add_alias_ty(data);
}
&ty::Dynamic(obj, r, _) => {
for predicate in obj.iter() {
self.bound_computation(predicate, |computation, predicate| match predicate {
ty::ExistentialPredicate::Trait(tr) => computation.add_args(tr.args),
ty::ExistentialPredicate::Projection(p) => {
computation.add_existential_projection(&p);
}
ty::ExistentialPredicate::AutoTrait(_) => {}
});
}
self.add_region(r);
}
&ty::Array(tt, len) => {
self.add_ty(tt);
self.add_const(len);
}
&ty::Pat(ty, pat) => {
self.add_ty(ty);
match *pat {
ty::PatternKind::Range { start, end } => {
self.add_const(start);
self.add_const(end);
}
}
}
&ty::Slice(tt) => self.add_ty(tt),
&ty::RawPtr(ty, _) => {
self.add_ty(ty);
}
&ty::Ref(r, ty, _) => {
self.add_region(r);
self.add_ty(ty);
}
&ty::Tuple(types) => {
self.add_tys(types);
}
&ty::FnDef(_, args) => {
self.add_args(args);
}
&ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
computation.add_tys(sig_tys.inputs_and_output);
}),
&ty::UnsafeBinder(bound_ty) => {
self.bound_computation(bound_ty.into(), |computation, ty| {
computation.add_ty(ty);
})
}
}
}
fn add_predicate(&mut self, binder: ty::Binder<'_, ty::PredicateKind<'_>>) {
self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
}
fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
match atom {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
self.add_args(trait_pred.trait_ref.args);
}
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
trait_ref,
constness: _,
})) => {
self.add_args(trait_ref.args);
}
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
a,
b,
))) => {
self.add_region(a);
self.add_region(b);
}
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
ty,
region,
))) => {
self.add_ty(ty);
self.add_region(region);
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
self.add_const(ct);
self.add_ty(ty);
}
ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
self.add_ty(a);
self.add_ty(b);
}
ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
self.add_ty(a);
self.add_ty(b);
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
projection_term,
term,
})) => {
self.add_alias_term(projection_term);
self.add_term(term);
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
self.add_args(slice::from_ref(&arg));
}
ty::PredicateKind::DynCompatible(_def_id) => {}
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
self.add_const(uv);
}
ty::PredicateKind::ConstEquate(expected, found) => {
self.add_const(expected);
self.add_const(found);
}
ty::PredicateKind::Ambiguous => {}
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
self.add_alias_term(alias);
self.add_term(term);
}
ty::PredicateKind::AliasRelate(t1, t2, _) => {
self.add_term(t1);
self.add_term(t2);
}
}
}
fn add_ty(&mut self, ty: Ty<'_>) {
self.add_flags(ty.flags());
self.add_exclusive_binder(ty.outer_exclusive_binder());
}
fn add_tys(&mut self, tys: &[Ty<'_>]) {
for &ty in tys {
self.add_ty(ty);
}
}
fn add_region(&mut self, r: ty::Region<'_>) {
self.add_flags(r.type_flags());
if let ty::ReBound(debruijn, _) = r.kind() {
self.add_bound_var(debruijn);
}
}
fn add_const(&mut self, c: ty::Const<'_>) {
self.add_flags(c.flags());
self.add_exclusive_binder(c.outer_exclusive_binder());
}
fn add_const_kind(&mut self, c: &ty::ConstKind<'_>) {
match *c {
ty::ConstKind::Unevaluated(uv) => {
self.add_args(uv.args);
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
}
ty::ConstKind::Infer(infer) => match infer {
InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
},
ty::ConstKind::Bound(debruijn, _) => {
self.add_bound_var(debruijn);
self.add_flags(TypeFlags::HAS_CT_BOUND);
}
ty::ConstKind::Param(_) => {
self.add_flags(TypeFlags::HAS_CT_PARAM);
}
ty::ConstKind::Placeholder(_) => {
self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
}
ty::ConstKind::Value(cv) => self.add_ty(cv.ty),
ty::ConstKind::Expr(e) => self.add_args(e.args()),
ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
}
}
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
self.add_args(projection.args);
match projection.term.unpack() {
ty::TermKind::Ty(ty) => self.add_ty(ty),
ty::TermKind::Const(ct) => self.add_const(ct),
}
}
fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<'_>) {
self.add_args(alias_ty.args);
}
fn add_alias_term(&mut self, alias_term: ty::AliasTerm<'_>) {
self.add_args(alias_term.args);
}
fn add_args(&mut self, args: &[GenericArg<'_>]) {
for kind in args {
match kind.unpack() {
GenericArgKind::Type(ty) => self.add_ty(ty),
GenericArgKind::Lifetime(lt) => self.add_region(lt),
GenericArgKind::Const(ct) => self.add_const(ct),
}
}
}
fn add_term(&mut self, term: ty::Term<'_>) {
match term.unpack() {
ty::TermKind::Ty(ty) => self.add_ty(ty),
ty::TermKind::Const(ct) => self.add_const(ct),
}
}
}

View file

@ -11,6 +11,7 @@ use rustc_hir::def_id::DefId;
use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
use rustc_serialize::{Decodable, Encodable};
use rustc_type_ir::WithCachedTypeInfo;
use rustc_type_ir::walk::TypeWalker;
use smallvec::SmallVec;
use crate::ty::codec::{TyDecoder, TyEncoder};
@ -297,6 +298,20 @@ impl<'tcx> GenericArg<'tcx> {
GenericArgKind::Const(ct) => ct.is_ct_infer(),
}
}
/// Iterator that walks `self` and any types reachable from
/// `self`, in depth-first order. Note that just walks the types
/// that appear in `self`, it does not descend into the fields of
/// structs or variants. For example:
///
/// ```text
/// isize => { isize }
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize }
/// ```
pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
TypeWalker::new(self)
}
}
impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for GenericArg<'a> {

View file

@ -7,9 +7,9 @@ use std::{fmt, iter, mem, ptr, slice};
use rustc_data_structures::aligned::{Aligned, align_of};
use rustc_data_structures::sync::DynSync;
use rustc_serialize::{Encodable, Encoder};
use rustc_type_ir::FlagComputation;
use super::flags::FlagComputation;
use super::{DebruijnIndex, TypeFlags};
use super::{DebruijnIndex, TyCtxt, TypeFlags};
use crate::arena::Arena;
/// `List<T>` is a bit like `&[T]`, but with some critical differences.
@ -299,8 +299,8 @@ impl TypeInfo {
}
}
impl From<FlagComputation> for TypeInfo {
fn from(computation: FlagComputation) -> TypeInfo {
impl<'tcx> From<FlagComputation<TyCtxt<'tcx>>> for TypeInfo {
fn from(computation: FlagComputation<TyCtxt<'tcx>>) -> TypeInfo {
TypeInfo {
flags: computation.flags,
outer_exclusive_binder: computation.outer_exclusive_binder,

View file

@ -117,7 +117,6 @@ pub mod cast;
pub mod codec;
pub mod error;
pub mod fast_reject;
pub mod flags;
pub mod inhabitedness;
pub mod layout;
pub mod normalize_erasing_regions;
@ -128,7 +127,6 @@ pub mod significant_drop_order;
pub mod trait_def;
pub mod util;
pub mod vtable;
pub mod walk;
mod adt;
mod assoc;

View file

@ -1,14 +1,40 @@
use std::fmt;
use rustc_data_structures::intern::Interned;
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_macros::HashStable;
use rustc_type_ir::ir_print::IrPrint;
use rustc_type_ir::{
FlagComputation, Flags, {self as ir},
};
use super::TyCtxt;
use crate::ty;
pub type PatternKind<'tcx> = ir::PatternKind<TyCtxt<'tcx>>;
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
#[rustc_pass_by_value]
pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>);
impl<'tcx> Flags for Pattern<'tcx> {
fn flags(&self) -> rustc_type_ir::TypeFlags {
match &**self {
ty::PatternKind::Range { start, end } => {
FlagComputation::for_const_kind(&start.kind()).flags
| FlagComputation::for_const_kind(&end.kind()).flags
}
}
}
fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
match &**self {
ty::PatternKind::Range { start, end } => {
start.outer_exclusive_binder().max(end.outer_exclusive_binder())
}
}
}
}
impl<'tcx> std::ops::Deref for Pattern<'tcx> {
type Target = PatternKind<'tcx>;
@ -23,9 +49,9 @@ impl<'tcx> fmt::Debug for Pattern<'tcx> {
}
}
impl<'tcx> fmt::Debug for PatternKind<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
impl<'tcx> IrPrint<PatternKind<'tcx>> for TyCtxt<'tcx> {
fn print(t: &PatternKind<'tcx>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *t {
PatternKind::Range { start, end } => {
write!(f, "{start}")?;
@ -53,10 +79,15 @@ impl<'tcx> fmt::Debug for PatternKind<'tcx> {
}
}
}
fn print_debug(t: &PatternKind<'tcx>, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Self::print(t, fmt)
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
pub enum PatternKind<'tcx> {
Range { start: ty::Const<'tcx>, end: ty::Const<'tcx> },
impl<'tcx> rustc_type_ir::inherent::IntoKind for Pattern<'tcx> {
type Kind = PatternKind<'tcx>;
fn kind(self) -> Self::Kind {
*self
}
}

View file

@ -16,6 +16,7 @@ use rustc_hir::def_id::DefId;
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension};
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use rustc_type_ir::TyKind::*;
use rustc_type_ir::walk::TypeWalker;
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate};
use tracing::instrument;
use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
@ -2029,6 +2030,20 @@ impl<'tcx> Ty<'tcx> {
pub fn is_known_rigid(self) -> bool {
self.kind().is_known_rigid()
}
/// Iterator that walks `self` and any types reachable from
/// `self`, in depth-first order. Note that just walks the types
/// that appear in `self`, it does not descend into the fields of
/// structs or variants. For example:
///
/// ```text
/// isize => { isize }
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize }
/// ```
pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
TypeWalker::new(self.into())
}
}
impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {

View file

@ -1169,6 +1169,13 @@ fn create_coroutine_drop_shim<'tcx>(
dump_mir(tcx, false, "coroutine_drop", &0, &body, |_, _| Ok(()));
body.source.instance = drop_instance;
// Creating a coroutine drop shim happens on `Analysis(PostCleanup) -> Runtime(Initial)`
// but the pass manager doesn't update the phase of the coroutine drop shim. Update the
// phase of the drop shim so that later on when we run the pass manager on the shim, in
// the `mir_shims` query, we don't ICE on the intra-pass validation before we've updated
// the phase of the body from analysis.
body.phase = MirPhase::Runtime(RuntimePhase::Initial);
body
}

View file

@ -157,7 +157,7 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: &Attribute) {
let attr_item = attr.get_normal_item();
if safety == AttributeSafety::Unsafe {
if let AttributeSafety::Unsafe { unsafe_since } = safety {
if let ast::Safety::Default = attr_item.unsafety {
let path_span = attr_item.path.span;
@ -167,7 +167,13 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr:
// square bracket respectively.
let diag_span = attr_item.span();
if attr.span.at_least_rust_2024() {
// Attributes can be safe in earlier editions, and become unsafe in later ones.
let emit_error = match unsafe_since {
None => true,
Some(unsafe_since) => attr.span.edition() >= unsafe_since,
};
if emit_error {
psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
span: path_span,
suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion {

View file

@ -226,12 +226,12 @@ impl SerializedDepGraph {
// If the length of this node's edge list is small, the length is stored in the header.
// If it is not, we fall back to another decoder call.
let num_edges = node_header.len().unwrap_or_else(|| d.read_usize());
let num_edges = node_header.len().unwrap_or_else(|| d.read_u32());
// The edges index list uses the same varint strategy as rmeta tables; we select the
// number of byte elements per-array not per-element. This lets us read the whole edge
// list for a node with one decoder call and also use the on-disk format in memory.
let edges_len_bytes = node_header.bytes_per_index() * num_edges;
let edges_len_bytes = node_header.bytes_per_index() * (num_edges as usize);
// The in-memory structure for the edges list stores the byte width of the edges on
// this node with the offset into the global edge data array.
let edges_header = node_header.edges_header(&edge_list_data);
@ -296,7 +296,7 @@ struct SerializedNodeHeader<D> {
// The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only
// to make the implementation of `SerializedNodeHeader` simpler.
struct Unpacked {
len: Option<usize>,
len: Option<u32>,
bytes_per_index: usize,
kind: DepKind,
hash: PackedFingerprint,
@ -352,7 +352,7 @@ impl<D: Deps> SerializedNodeHeader<D> {
assert_eq!(fingerprint, res.fingerprint());
assert_eq!(node, res.node());
if let Some(len) = res.len() {
assert_eq!(edge_count, len);
assert_eq!(edge_count, len as usize);
}
}
Self { bytes, _marker: PhantomData }
@ -366,7 +366,7 @@ impl<D: Deps> SerializedNodeHeader<D> {
let kind = head & mask(Self::KIND_BITS) as u16;
let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16;
let len = (head as usize) >> (Self::WIDTH_BITS + Self::KIND_BITS);
let len = (head as u32) >> (Self::WIDTH_BITS + Self::KIND_BITS);
Unpacked {
len: len.checked_sub(1),
@ -378,7 +378,7 @@ impl<D: Deps> SerializedNodeHeader<D> {
}
#[inline]
fn len(&self) -> Option<usize> {
fn len(&self) -> Option<u32> {
self.unpack().len
}
@ -421,7 +421,8 @@ impl NodeInfo {
e.write_array(header.bytes);
if header.len().is_none() {
e.emit_usize(edges.len());
// The edges are all unique and the number of unique indices is less than u32::MAX.
e.emit_u32(edges.len().try_into().unwrap());
}
let bytes_per_index = header.bytes_per_index();
@ -456,7 +457,8 @@ impl NodeInfo {
e.write_array(header.bytes);
if header.len().is_none() {
e.emit_usize(edge_count);
// The edges are all unique and the number of unique indices is less than u32::MAX.
e.emit_u32(edge_count.try_into().unwrap());
}
let bytes_per_index = header.bytes_per_index();

View file

@ -268,8 +268,8 @@ trait_selection_oc_type_compat = type not compatible with trait
trait_selection_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
.label = opaque type defined here
trait_selection_opaque_type_non_generic_param =
expected generic {$kind} parameter, found `{$ty}`
.label = {STREQ($ty, "'static") ->
expected generic {$kind} parameter, found `{$arg}`
.label = {STREQ($arg, "'static") ->
[true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
*[other] this generic parameter must be used with a generic {$kind} parameter
}

View file

@ -1926,7 +1926,7 @@ impl Subdiagnostic for AddPreciseCapturingForOvercapture {
#[derive(Diagnostic)]
#[diag(trait_selection_opaque_type_non_generic_param, code = E0792)]
pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
pub ty: GenericArg<'tcx>,
pub arg: GenericArg<'tcx>,
pub kind: &'a str,
#[primary_span]
pub span: Span,

View file

@ -70,7 +70,7 @@ pub fn check_opaque_type_parameter_valid<'tcx>(
opaque_env.param_is_error(i)?;
return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam {
ty: arg,
arg,
kind,
span,
param_span: tcx.def_span(opaque_param.def_id),

View file

@ -1,3 +1,9 @@
use std::slice;
use crate::inherent::*;
use crate::visit::Flags;
use crate::{self as ty, Interner};
bitflags::bitflags! {
/// Flags that we track on types. These flags are propagated upwards
/// through the type during type construction, so that we can quickly check
@ -128,3 +134,362 @@ bitflags::bitflags! {
const HAS_BINDER_VARS = 1 << 23;
}
}
#[derive(Debug)]
pub struct FlagComputation<I> {
pub flags: TypeFlags,
/// see `Ty::outer_exclusive_binder` for details
pub outer_exclusive_binder: ty::DebruijnIndex,
interner: std::marker::PhantomData<I>,
}
impl<I: Interner> FlagComputation<I> {
fn new() -> FlagComputation<I> {
FlagComputation {
flags: TypeFlags::empty(),
outer_exclusive_binder: ty::INNERMOST,
interner: std::marker::PhantomData,
}
}
#[allow(rustc::usage_of_ty_tykind)]
pub fn for_kind(kind: &ty::TyKind<I>) -> FlagComputation<I> {
let mut result = FlagComputation::new();
result.add_kind(kind);
result
}
pub fn for_predicate(binder: ty::Binder<I, ty::PredicateKind<I>>) -> FlagComputation<I> {
let mut result = FlagComputation::new();
result.add_predicate(binder);
result
}
pub fn for_const_kind(kind: &ty::ConstKind<I>) -> FlagComputation<I> {
let mut result = FlagComputation::new();
result.add_const_kind(kind);
result
}
pub fn for_clauses(clauses: &[I::Clause]) -> FlagComputation<I> {
let mut result = FlagComputation::new();
for c in clauses {
result.add_flags(c.as_predicate().flags());
result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder());
}
result
}
fn add_flags(&mut self, flags: TypeFlags) {
self.flags = self.flags | flags;
}
/// indicates that `self` refers to something at binding level `binder`
fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
let exclusive_binder = binder.shifted_in(1);
self.add_exclusive_binder(exclusive_binder);
}
/// indicates that `self` refers to something *inside* binding
/// level `binder` -- not bound by `binder`, but bound by the next
/// binder internal to it
fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
}
/// Adds the flags/depth from a set of types that appear within the current type, but within a
/// region binder.
fn bound_computation<T, F>(&mut self, value: ty::Binder<I, T>, f: F)
where
F: FnOnce(&mut Self, T),
{
let mut computation = FlagComputation::new();
if !value.bound_vars().is_empty() {
computation.add_flags(TypeFlags::HAS_BINDER_VARS);
}
f(&mut computation, value.skip_binder());
self.add_flags(computation.flags);
// The types that contributed to `computation` occurred within
// a region binder, so subtract one from the region depth
// within when adding the depth to `self`.
let outer_exclusive_binder = computation.outer_exclusive_binder;
if outer_exclusive_binder > ty::INNERMOST {
self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
} // otherwise, this binder captures nothing
}
#[allow(rustc::usage_of_ty_tykind)]
fn add_kind(&mut self, kind: &ty::TyKind<I>) {
match *kind {
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Float(_)
| ty::Uint(_)
| ty::Never
| ty::Str
| ty::Foreign(..) => {}
ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
ty::Param(_) => {
self.add_flags(TypeFlags::HAS_TY_PARAM);
}
ty::Closure(_, args)
| ty::Coroutine(_, args)
| ty::CoroutineClosure(_, args)
| ty::CoroutineWitness(_, args) => {
self.add_args(args.as_slice());
}
ty::Bound(debruijn, _) => {
self.add_bound_var(debruijn);
self.add_flags(TypeFlags::HAS_TY_BOUND);
}
ty::Placeholder(..) => {
self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
}
ty::Infer(infer) => match infer {
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
self.add_flags(TypeFlags::HAS_TY_FRESH)
}
ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
self.add_flags(TypeFlags::HAS_TY_INFER)
}
},
ty::Adt(_, args) => {
self.add_args(args.as_slice());
}
ty::Alias(kind, data) => {
self.add_flags(match kind {
ty::Projection => TypeFlags::HAS_TY_PROJECTION,
ty::Weak => TypeFlags::HAS_TY_WEAK,
ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
ty::Inherent => TypeFlags::HAS_TY_INHERENT,
});
self.add_alias_ty(data);
}
ty::Dynamic(obj, r, _) => {
for predicate in obj.iter() {
self.bound_computation(predicate, |computation, predicate| match predicate {
ty::ExistentialPredicate::Trait(tr) => {
computation.add_args(tr.args.as_slice())
}
ty::ExistentialPredicate::Projection(p) => {
computation.add_existential_projection(&p);
}
ty::ExistentialPredicate::AutoTrait(_) => {}
});
}
self.add_region(r);
}
ty::Array(tt, len) => {
self.add_ty(tt);
self.add_const(len);
}
ty::Pat(ty, pat) => {
self.add_ty(ty);
self.add_flags(pat.flags());
}
ty::Slice(tt) => self.add_ty(tt),
ty::RawPtr(ty, _) => {
self.add_ty(ty);
}
ty::Ref(r, ty, _) => {
self.add_region(r);
self.add_ty(ty);
}
ty::Tuple(types) => {
self.add_tys(types);
}
ty::FnDef(_, args) => {
self.add_args(args.as_slice());
}
ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
computation.add_tys(sig_tys.inputs_and_output);
}),
ty::UnsafeBinder(bound_ty) => {
self.bound_computation(bound_ty.into(), |computation, ty| {
computation.add_ty(ty);
})
}
}
}
fn add_predicate(&mut self, binder: ty::Binder<I, ty::PredicateKind<I>>) {
self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
}
fn add_predicate_atom(&mut self, atom: ty::PredicateKind<I>) {
match atom {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
self.add_args(trait_pred.trait_ref.args.as_slice());
}
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
trait_ref,
constness: _,
})) => {
self.add_args(trait_ref.args.as_slice());
}
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
a,
b,
))) => {
self.add_region(a);
self.add_region(b);
}
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
ty,
region,
))) => {
self.add_ty(ty);
self.add_region(region);
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
self.add_const(ct);
self.add_ty(ty);
}
ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
self.add_ty(a);
self.add_ty(b);
}
ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
self.add_ty(a);
self.add_ty(b);
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
projection_term,
term,
})) => {
self.add_alias_term(projection_term);
self.add_term(term);
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
self.add_args(slice::from_ref(&arg));
}
ty::PredicateKind::DynCompatible(_def_id) => {}
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
self.add_const(uv);
}
ty::PredicateKind::ConstEquate(expected, found) => {
self.add_const(expected);
self.add_const(found);
}
ty::PredicateKind::Ambiguous => {}
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
self.add_alias_term(alias);
self.add_term(term);
}
ty::PredicateKind::AliasRelate(t1, t2, _) => {
self.add_term(t1);
self.add_term(t2);
}
}
}
fn add_ty(&mut self, ty: I::Ty) {
self.add_flags(ty.flags());
self.add_exclusive_binder(ty.outer_exclusive_binder());
}
fn add_tys(&mut self, tys: I::Tys) {
for ty in tys.iter() {
self.add_ty(ty);
}
}
fn add_region(&mut self, r: I::Region) {
self.add_flags(r.flags());
if let ty::ReBound(debruijn, _) = r.kind() {
self.add_bound_var(debruijn);
}
}
fn add_const(&mut self, c: I::Const) {
self.add_flags(c.flags());
self.add_exclusive_binder(c.outer_exclusive_binder());
}
fn add_const_kind(&mut self, c: &ty::ConstKind<I>) {
match *c {
ty::ConstKind::Unevaluated(uv) => {
self.add_args(uv.args.as_slice());
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
}
ty::ConstKind::Infer(infer) => match infer {
ty::InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
ty::InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
},
ty::ConstKind::Bound(debruijn, _) => {
self.add_bound_var(debruijn);
self.add_flags(TypeFlags::HAS_CT_BOUND);
}
ty::ConstKind::Param(_) => {
self.add_flags(TypeFlags::HAS_CT_PARAM);
}
ty::ConstKind::Placeholder(_) => {
self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
}
ty::ConstKind::Value(cv) => self.add_ty(cv.ty()),
ty::ConstKind::Expr(e) => self.add_args(e.args().as_slice()),
ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
}
}
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<I>) {
self.add_args(projection.args.as_slice());
match projection.term.kind() {
ty::TermKind::Ty(ty) => self.add_ty(ty),
ty::TermKind::Const(ct) => self.add_const(ct),
}
}
fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<I>) {
self.add_args(alias_ty.args.as_slice());
}
fn add_alias_term(&mut self, alias_term: ty::AliasTerm<I>) {
self.add_args(alias_term.args.as_slice());
}
fn add_args(&mut self, args: &[I::GenericArg]) {
for kind in args {
match kind.kind() {
ty::GenericArgKind::Type(ty) => self.add_ty(ty),
ty::GenericArgKind::Lifetime(lt) => self.add_region(lt),
ty::GenericArgKind::Const(ct) => self.add_const(ct),
}
}
}
fn add_term(&mut self, term: I::Term) {
match term.kind() {
ty::TermKind::Ty(ty) => self.add_ty(ty),
ty::TermKind::Const(ct) => self.add_const(ct),
}
}
}

View file

@ -583,7 +583,7 @@ pub trait Span<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
pub trait SliceLike: Sized + Copy {
type Item: Copy;
type IntoIter: Iterator<Item = Self::Item>;
type IntoIter: Iterator<Item = Self::Item> + DoubleEndedIterator;
fn iter(self) -> Self::IntoIter;

View file

@ -31,6 +31,7 @@ pub trait Interner:
+ IrPrint<ty::SubtypePredicate<Self>>
+ IrPrint<ty::CoercePredicate<Self>>
+ IrPrint<ty::FnSig<Self>>
+ IrPrint<ty::PatternKind<Self>>
{
type DefId: DefId<Self>;
type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
@ -104,7 +105,14 @@ pub trait Interner:
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
type BoundExistentialPredicates: BoundExistentialPredicates<Self>;
type AllocId: Copy + Debug + Hash + Eq;
type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>;
type Pat: Copy
+ Debug
+ Hash
+ Eq
+ Debug
+ Relate<Self>
+ Flags
+ IntoKind<Kind = ty::PatternKind<Self>>;
type Safety: Safety<Self>;
type Abi: Abi<Self>;

View file

@ -2,8 +2,8 @@ use std::fmt;
use crate::{
AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate,
SubtypePredicate, TraitPredicate, TraitRef,
HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, PatternKind,
ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
};
pub trait IrPrint<T> {
@ -57,9 +57,10 @@ define_display_via_print!(
AliasTy,
AliasTerm,
FnSig,
PatternKind,
);
define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);
define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection, PatternKind);
impl<I: Interner, T> fmt::Display for OutlivesPredicate<I, T>
where

View file

@ -31,6 +31,7 @@ pub mod outlives;
pub mod relate;
pub mod search_graph;
pub mod solve;
pub mod walk;
// These modules are not `pub` since they are glob-imported.
#[macro_use]
@ -44,6 +45,7 @@ mod generic_arg;
mod infer_ctxt;
mod interner;
mod opaque_ty;
mod pattern;
mod predicate;
mod predicate_kind;
mod region_kind;
@ -67,6 +69,7 @@ pub use generic_arg::*;
pub use infer_ctxt::*;
pub use interner::*;
pub use opaque_ty::*;
pub use pattern::*;
pub use predicate::*;
pub use predicate_kind::*;
pub use region_kind::*;

View file

@ -0,0 +1,16 @@
use derive_where::derive_where;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use crate::Interner;
#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
)]
pub enum PatternKind<I: Interner> {
Range { start: I::Const, end: I::Const },
}

View file

@ -1,20 +1,21 @@
//! An iterator over the type substructure.
//! WARNING: this does not keep track of the region depth.
use rustc_data_structures::sso::SsoHashSet;
use smallvec::{SmallVec, smallvec};
use tracing::debug;
use crate::ty::{self, GenericArg, GenericArgKind, Ty};
use crate::data_structures::SsoHashSet;
use crate::inherent::*;
use crate::{self as ty, Interner};
// The TypeWalker's stack is hot enough that it's worth going to some effort to
// avoid heap allocations.
type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>;
type TypeWalkerStack<I> = SmallVec<[<I as Interner>::GenericArg; 8]>;
pub struct TypeWalker<'tcx> {
stack: TypeWalkerStack<'tcx>,
pub struct TypeWalker<I: Interner> {
stack: TypeWalkerStack<I>,
last_subtree: usize,
pub visited: SsoHashSet<GenericArg<'tcx>>,
pub visited: SsoHashSet<I::GenericArg>,
}
/// An iterator for walking the type tree.
@ -25,8 +26,8 @@ pub struct TypeWalker<'tcx> {
/// in this situation walker only visits each type once.
/// It maintains a set of visited types and
/// skips any types that are already there.
impl<'tcx> TypeWalker<'tcx> {
pub fn new(root: GenericArg<'tcx>) -> Self {
impl<I: Interner> TypeWalker<I> {
pub fn new(root: I::GenericArg) -> Self {
Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
}
@ -47,16 +48,16 @@ impl<'tcx> TypeWalker<'tcx> {
}
}
impl<'tcx> Iterator for TypeWalker<'tcx> {
type Item = GenericArg<'tcx>;
impl<I: Interner> Iterator for TypeWalker<I> {
type Item = I::GenericArg;
fn next(&mut self) -> Option<GenericArg<'tcx>> {
fn next(&mut self) -> Option<I::GenericArg> {
debug!("next(): stack={:?}", self.stack);
loop {
let next = self.stack.pop()?;
self.last_subtree = self.stack.len();
if self.visited.insert(next) {
push_inner(&mut self.stack, next);
push_inner::<I>(&mut self.stack, next);
debug!("next: stack={:?}", self.stack);
return Some(next);
}
@ -64,63 +65,15 @@ impl<'tcx> Iterator for TypeWalker<'tcx> {
}
}
impl<'tcx> GenericArg<'tcx> {
/// Iterator that walks `self` and any types reachable from
/// `self`, in depth-first order. Note that just walks the types
/// that appear in `self`, it does not descend into the fields of
/// structs or variants. For example:
///
/// ```text
/// isize => { isize }
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize }
/// ```
pub fn walk(self) -> TypeWalker<'tcx> {
TypeWalker::new(self)
}
}
impl<'tcx> Ty<'tcx> {
/// Iterator that walks `self` and any types reachable from
/// `self`, in depth-first order. Note that just walks the types
/// that appear in `self`, it does not descend into the fields of
/// structs or variants. For example:
///
/// ```text
/// isize => { isize }
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize }
/// ```
pub fn walk(self) -> TypeWalker<'tcx> {
TypeWalker::new(self.into())
}
}
impl<'tcx> ty::Const<'tcx> {
/// Iterator that walks `self` and any types reachable from
/// `self`, in depth-first order. Note that just walks the types
/// that appear in `self`, it does not descend into the fields of
/// structs or variants. For example:
///
/// ```text
/// isize => { isize }
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize }
/// ```
pub fn walk(self) -> TypeWalker<'tcx> {
TypeWalker::new(self.into())
}
}
/// We push `GenericArg`s on the stack in reverse order so as to
/// maintain a pre-order traversal. As of the time of this
/// writing, the fact that the traversal is pre-order is not
/// known to be significant to any code, but it seems like the
/// natural order one would expect (basically, the order of the
/// types as they are written).
fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) {
match parent.unpack() {
GenericArgKind::Type(parent_ty) => match *parent_ty.kind() {
fn push_inner<I: Interner>(stack: &mut TypeWalkerStack<I>, parent: I::GenericArg) {
match parent.kind() {
ty::GenericArgKind::Type(parent_ty) => match parent_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
@ -136,7 +89,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
| ty::Foreign(..) => {}
ty::Pat(ty, pat) => {
match *pat {
match pat.kind() {
ty::PatternKind::Range { start, end } => {
stack.push(end.into());
stack.push(start.into());
@ -163,22 +116,25 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
}
ty::Dynamic(obj, lt, _) => {
stack.push(lt.into());
stack.extend(obj.iter().rev().flat_map(|predicate| {
let (args, opt_ty) = match predicate.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => (tr.args, None),
ty::ExistentialPredicate::Projection(p) => (p.args, Some(p.term)),
ty::ExistentialPredicate::AutoTrait(_) =>
// Empty iterator
{
(ty::GenericArgs::empty(), None)
}
};
stack.extend(
obj.iter()
.rev()
.filter_map(|predicate| {
let (args, opt_ty) = match predicate.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => (tr.args, None),
ty::ExistentialPredicate::Projection(p) => (p.args, Some(p.term)),
ty::ExistentialPredicate::AutoTrait(_) => {
return None;
}
};
args.iter().rev().chain(opt_ty.map(|term| match term.unpack() {
ty::TermKind::Ty(ty) => ty.into(),
ty::TermKind::Const(ct) => ct.into(),
}))
}));
Some(args.iter().rev().chain(opt_ty.map(|term| match term.kind() {
ty::TermKind::Ty(ty) => ty.into(),
ty::TermKind::Const(ct) => ct.into(),
})))
})
.flatten(),
);
}
ty::Adt(_, args)
| ty::Closure(_, args)
@ -188,7 +144,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
| ty::FnDef(_, args) => {
stack.extend(args.iter().rev());
}
ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)),
ty::Tuple(ts) => stack.extend(ts.iter().rev().map(|ty| ty.into())),
ty::FnPtr(sig_tys, _hdr) => {
stack.extend(
sig_tys.skip_binder().inputs_and_output.iter().rev().map(|ty| ty.into()),
@ -198,15 +154,15 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
stack.push(bound_ty.skip_binder().into());
}
},
GenericArgKind::Lifetime(_) => {}
GenericArgKind::Const(parent_ct) => match parent_ct.kind() {
ty::GenericArgKind::Lifetime(_) => {}
ty::GenericArgKind::Const(parent_ct) => match parent_ct.kind() {
ty::ConstKind::Infer(_)
| ty::ConstKind::Param(_)
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Error(_) => {}
ty::ConstKind::Value(cv) => stack.push(cv.ty.into()),
ty::ConstKind::Value(cv) => stack.push(cv.ty().into()),
ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()),
ty::ConstKind::Unevaluated(ct) => {