From abf212c16cbc2fdef9dc4b515165f144c716f3d3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Oct 2024 17:38:42 +1000 Subject: [PATCH 01/12] Remove `OutlivesEnvironmentBuilder`. `OutlivesEnvironment::new` can call `OutlivesEnvironment::with_bounds` with an empty `extra_bounds`. And once that's done, `OutlivesEnvironmentBuilder` has a single use and can be inlined and removed into `OutlivesEnvironment::with_bounds`. --- .../rustc_infer/src/infer/outlives/env.rs | 87 ++++++------------- 1 file changed, 26 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index a071b84a1a00f..9300fc574dc29 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -1,8 +1,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::transitive_relation::TransitiveRelationBuilder; -use rustc_middle::bug; -use rustc_middle::ty::{self, Region}; -use tracing::{debug, instrument}; +use rustc_middle::{bug, ty}; +use tracing::debug; use super::explicit_outlives_bounds; use crate::infer::GenericKind; @@ -54,37 +53,16 @@ pub struct OutlivesEnvironment<'tcx> { region_bound_pairs: RegionBoundPairs<'tcx>, } -/// Builder of OutlivesEnvironment. -#[derive(Debug)] -struct OutlivesEnvironmentBuilder<'tcx> { - param_env: ty::ParamEnv<'tcx>, - region_relation: TransitiveRelationBuilder>, - region_bound_pairs: RegionBoundPairs<'tcx>, -} - /// "Region-bound pairs" tracks outlives relations that are known to /// be true, either because of explicit where-clauses like `T: 'a` or /// because of implied bounds. pub type RegionBoundPairs<'tcx> = FxIndexSet>>; impl<'tcx> OutlivesEnvironment<'tcx> { - /// Create a builder using `ParamEnv` and add explicit outlives bounds into it. - fn builder(param_env: ty::ParamEnv<'tcx>) -> OutlivesEnvironmentBuilder<'tcx> { - let mut builder = OutlivesEnvironmentBuilder { - param_env, - region_relation: Default::default(), - region_bound_pairs: Default::default(), - }; - - builder.add_outlives_bounds(explicit_outlives_bounds(param_env)); - - builder - } - - #[inline] /// Create a new `OutlivesEnvironment` without extra outlives bounds. + #[inline] pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self { - Self::builder(param_env).build() + Self::with_bounds(param_env, vec![]) } /// Create a new `OutlivesEnvironment` with extra outlives bounds. @@ -92,56 +70,27 @@ impl<'tcx> OutlivesEnvironment<'tcx> { param_env: ty::ParamEnv<'tcx>, extra_bounds: impl IntoIterator>, ) -> Self { - let mut builder = Self::builder(param_env); - builder.add_outlives_bounds(extra_bounds); - builder.build() - } + let mut region_relation = TransitiveRelationBuilder::default(); + let mut region_bound_pairs = RegionBoundPairs::default(); - /// Borrows current value of the `free_region_map`. - pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> { - &self.free_region_map - } - - /// Borrows current `region_bound_pairs`. - pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> { - &self.region_bound_pairs - } -} - -impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { - #[inline] - #[instrument(level = "debug")] - fn build(self) -> OutlivesEnvironment<'tcx> { - OutlivesEnvironment { - param_env: self.param_env, - free_region_map: FreeRegionMap { relation: self.region_relation.freeze() }, - region_bound_pairs: self.region_bound_pairs, - } - } - - /// Processes outlives bounds that are known to hold, whether from implied or other sources. - fn add_outlives_bounds(&mut self, outlives_bounds: I) - where - I: IntoIterator>, - { // Record relationships such as `T:'x` that don't go into the // free-region-map but which we use here. - for outlives_bound in outlives_bounds { + for outlives_bound in explicit_outlives_bounds(param_env).chain(extra_bounds) { debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound); match outlives_bound { OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs + region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Param(param_b), r_a)); } OutlivesBound::RegionSubAlias(r_a, alias_b) => { - self.region_bound_pairs + region_bound_pairs .insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a)); } OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) { ( ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_), ty::ReStatic | ty::ReEarlyParam(_) | ty::ReLateParam(_), - ) => self.region_relation.add(r_a, r_b), + ) => region_relation.add(r_a, r_b), (ty::ReError(_), _) | (_, ty::ReError(_)) => {} // FIXME(#109628): We shouldn't have existential variables in implied bounds. // Panic here once the linked issue is resolved! @@ -150,5 +99,21 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> { }, } } + + OutlivesEnvironment { + param_env, + free_region_map: FreeRegionMap { relation: region_relation.freeze() }, + region_bound_pairs, + } + } + + /// Borrows current value of the `free_region_map`. + pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> { + &self.free_region_map + } + + /// Borrows current `region_bound_pairs`. + pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> { + &self.region_bound_pairs } } From 27dad009c61e6a21fc7cb438a08597cf0ec0b1c8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Oct 2024 09:25:41 +1000 Subject: [PATCH 02/12] Add a useful comment about `InferOk`. Prompted by #131134, which tried to remove `InferOk<'tcx, ()>` occurrences. --- compiler/rustc_infer/src/infer/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index cb60d9f286b13..29936fadc57d8 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -67,6 +67,13 @@ pub mod resolve; pub(crate) mod snapshot; mod type_variable; +/// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper +/// around `Vec>`, but it has one important property: +/// because `InferOk` is marked with `#[must_use]`, if you have a method +/// `InferCtxt::f` that returns `InferResult<'tcx, ()>` and you call it with +/// `infcx.f()?;` you'll get a warning about the obligations being discarded +/// without use, which is probably unintentional and has been a source of bugs +/// in the past. #[must_use] #[derive(Debug)] pub struct InferOk<'tcx, T> { From 0293827e093b233eda3a403a5238c164200bfc98 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 2 Oct 2024 14:07:57 +1000 Subject: [PATCH 03/12] Improve formatting of some comments. I.e. fixing comments lines that are too long or too short. --- compiler/rustc_infer/src/infer/mod.rs | 12 ++--- .../rustc_infer/src/infer/opaque_types/mod.rs | 10 ++-- .../src/infer/outlives/obligations.rs | 11 ++-- .../infer/region_constraints/leak_check.rs | 11 ++-- .../src/infer/relate/generalize.rs | 6 ++- compiler/rustc_infer/src/traits/project.rs | 53 ++++++++----------- 6 files changed, 50 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 29936fadc57d8..f2cb28fd6f6f4 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1011,8 +1011,8 @@ impl<'tcx> InferCtxt<'tcx> { ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid)).into() } - /// Given a set of generics defined on a type or impl, returns the generic parameters mapping each - /// type/region parameter to a fresh inference variable. + /// Given a set of generics defined on a type or impl, returns the generic parameters mapping + /// each type/region parameter to a fresh inference variable. pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> { GenericArgs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param)) } @@ -1390,10 +1390,10 @@ impl<'tcx> InferCtxt<'tcx> { /// /// The constant can be located on a trait like `::C`, in which case the given /// generic parameters and environment are used to resolve the constant. Alternatively if the - /// constant has generic parameters in scope the instantiations are used to evaluate the value of - /// the constant. For example in `fn foo() { let _ = [0; bar::()]; }` the repeat count - /// constant `bar::()` requires a instantiation for `T`, if the instantiation for `T` is still - /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is + /// constant has generic parameters in scope the instantiations are used to evaluate the value + /// of the constant. For example in `fn foo() { let _ = [0; bar::()]; }` the repeat count + /// constant `bar::()` requires a instantiation for `T`, if the instantiation for `T` is + /// still too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is /// returned. /// /// This handles inferences variables within both `param_env` and `args` by diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 5a2ffbf029eb2..365ddaba138ff 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -148,11 +148,11 @@ impl<'tcx> InferCtxt<'tcx> { } if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() { - // We could accept this, but there are various ways to handle this situation, and we don't - // want to make a decision on it right now. Likely this case is so super rare anyway, that - // no one encounters it in practice. - // It does occur however in `fn fut() -> impl Future { async { 42 } }`, - // where it is of no concern, so we only check for TAITs. + // We could accept this, but there are various ways to handle this situation, + // and we don't want to make a decision on it right now. Likely this case is so + // super rare anyway, that no one encounters it in practice. It does occur + // however in `fn fut() -> impl Future { async { 42 } }`, where + // it is of no concern, so we only check for TAITs. if self.can_define_opaque_ty(b_def_id) && self.tcx.is_type_alias_impl_trait(b_def_id) { diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 634cda86bc338..e0e03a2922010 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -396,11 +396,12 @@ where // 'a` in the environment but `trait Foo<'b> { type Item: 'b // }` in the trait definition. approx_env_bounds.retain(|bound_outlives| { - // OK to skip binder because we only manipulate and compare against other - // values from the same binder. e.g. if we have (e.g.) `for<'a> >::Item: 'a` - // in `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region. - // If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait` - // will be invoked with `['b => ^1]` and so we will get `^1` returned. + // OK to skip binder because we only manipulate and compare against other values from + // the same binder. e.g. if we have (e.g.) `for<'a> >::Item: 'a` in + // `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region. If the + // declaration is `trait Trait<'b> { type Item: 'b; }`, then + // `projection_declared_bounds_from_trait` will be invoked with `['b => ^1]` and so we + // will get `^1` returned. let bound = bound_outlives.skip_binder(); let ty::Alias(_, alias_ty) = bound.0.kind() else { bug!("expected AliasTy") }; self.verify_bound.declared_bounds_from_definition(*alias_ty).all(|r| r != bound.1) diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 7913f0e340e09..30eba3e8f4fb7 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -55,8 +55,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// * what placeholder they must outlive transitively /// * if they must also be equal to a placeholder, report an error because `P1: P2` /// * minimum universe U of all SCCs they must outlive - /// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that - /// indicates `P: R` and `R` is in an incompatible universe + /// * if they must also be equal to a placeholder P, and U cannot name P, report an error, as + /// that indicates `P: R` and `R` is in an incompatible universe /// /// To improve performance and for the old trait solver caching to be sound, this takes /// an optional snapshot in which case we only look at region constraints added in that @@ -216,8 +216,8 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { // Walk over each `scc2` such that `scc1: scc2` and compute: // // * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1` - // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple, - // we pick one arbitrarily) + // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there + // are multiple, we pick one arbitrarily) let mut scc1_universe = self.scc_universes[scc1]; let mut succ_bound = None; for &scc2 in self.mini_graph.sccs.successors(scc1) { @@ -260,7 +260,8 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { self.scc_placeholders[scc1] = succ_bound; } - // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any). + // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must + // outlive (if any). } Ok(()) } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index a6d10aa5968c7..726a2296d11a3 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -50,7 +50,8 @@ impl<'tcx> InferCtxt<'tcx> { // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh // region/type inference variables. // - // We then relate `generalized_ty <: source_ty`,adding constraints like `'x: '?2` and `?1 <: ?3`. + // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and + // `?1 <: ?3`. let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self .generalize( relation.span(), @@ -104,7 +105,8 @@ impl<'tcx> InferCtxt<'tcx> { &ty::Alias(ty::Projection, data) => { // FIXME: This does not handle subtyping correctly, we could // instead create a new inference variable `?normalized_source`, emitting - // `Projection(normalized_source, ?ty_normalized)` and `?normalized_source <: generalized_ty`. + // `Projection(normalized_source, ?ty_normalized)` and + // `?normalized_source <: generalized_ty`. relation.register_predicates([ty::ProjectionPredicate { projection_term: data.into(), term: generalized_ty.into(), diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index fa813d0f90ca0..64b72de398622 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -92,38 +92,31 @@ pub enum ProjectionCacheEntry<'tcx> { Error, NormalizedTerm { ty: NormalizedTerm<'tcx>, - /// If we were able to successfully evaluate the - /// corresponding cache entry key during predicate - /// evaluation, then this field stores the final - /// result obtained from evaluating all of the projection - /// sub-obligations. During evaluation, we will skip - /// evaluating the cached sub-obligations in `ty` - /// if this field is set. Evaluation only - /// cares about the final result, so we don't - /// care about any region constraint side-effects - /// produced by evaluating the sub-obligations. + /// If we were able to successfully evaluate the corresponding cache + /// entry key during predicate evaluation, then this field stores the + /// final result obtained from evaluating all of the projection + /// sub-obligations. During evaluation, we will skip evaluating the + /// cached sub-obligations in `ty` if this field is set. Evaluation + /// only cares about the final result, so we don't care about any + /// region constraint side-effects produced by evaluating the + /// sub-obligations. /// - /// Additionally, we will clear out the sub-obligations - /// entirely if we ever evaluate the cache entry (along - /// with all its sub obligations) to `EvaluatedToOk`. - /// This affects all users of the cache, not just evaluation. - /// Since a result of `EvaluatedToOk` means that there were - /// no region obligations that need to be tracked, it's - /// fine to forget about the sub-obligations - they - /// don't provide any additional information. However, - /// we do *not* discard any obligations when we see - /// `EvaluatedToOkModuloRegions` - we don't know - /// which sub-obligations may introduce region constraints, - /// so we keep them all to be safe. + /// Additionally, we will clear out the sub-obligations entirely if we + /// ever evaluate the cache entry (along with all its sub obligations) + /// to `EvaluatedToOk`. This affects all users of the cache, not just + /// evaluation. Since a result of `EvaluatedToOk` means that there were + /// no region obligations that need to be tracked, it's fine to forget + /// about the sub-obligations - they don't provide any additional + /// information. However, we do *not* discard any obligations when we + /// see `EvaluatedToOkModuloRegions` - we don't know which + /// sub-obligations may introduce region constraints, so we keep them + /// all to be safe. /// - /// When we are not performing evaluation - /// (e.g. in `FulfillmentContext`), we ignore this field, - /// and always re-process the cached sub-obligations - /// (which may have been cleared out - see the above - /// paragraph). - /// This ensures that we do not lose any regions - /// constraints that arise from processing the - /// sub-obligations. + /// When we are not performing evaluation (e.g. in + /// `FulfillmentContext`), we ignore this field, and always re-process + /// the cached sub-obligations (which may have been cleared out - see + /// the above paragraph). This ensures that we do not lose any regions + /// constraints that arise from processing the sub-obligations. complete: Option, }, } From 2b57a785a917faa8a1c44414ed3d43e13e626f63 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Oct 2024 10:44:48 +1000 Subject: [PATCH 04/12] Inline and remove `RegionConstraintCollector::into_infos_and_data`. It's a weird method, and used weirdly: - It's on `RegionConstraintCollector` but operates on `RegionConstraintStorage`. So at both call sites we create a temporary `RegionConstraintCollector`, using `with_log`, to call it. - It `take`s just two of the six fields in `RegionConstraintStorage`. At one of the two call sites we unnecessarily clone the entire `RegionConstraintStorage` just to take those two fields. This commit just inlines and removes it. We no longer need to `take` the two fields, we can just use them directly. --- compiler/rustc_infer/src/infer/mod.rs | 23 ++++++++----------- .../rustc_infer/src/infer/outlives/mod.rs | 15 +++++------- .../src/infer/region_constraints/mod.rs | 12 ++-------- 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index f2cb28fd6f6f4..785ef8f939e14 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -18,7 +18,7 @@ pub use relate::combine::PredicateEmittingRelation; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::undo_log::Rollback; +use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::unify as ut; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use rustc_hir as hir; @@ -50,6 +50,7 @@ use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use type_variable::TypeVariableOrigin; +use crate::infer::region_constraints::UndoLog; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; pub mod at; @@ -1043,18 +1044,14 @@ impl<'tcx> InferCtxt<'tcx> { /// Clone the list of variable regions. This is used only during NLL processing /// to put the set of region variables into the NLL region context. pub fn get_region_var_origins(&self) -> VarInfos { - let mut inner = self.inner.borrow_mut(); - let (var_infos, data) = inner - .region_constraint_storage - // We clone instead of taking because borrowck still wants to use - // the inference context after calling this for diagnostics - // and the new trait solver. - .clone() - .expect("regions already resolved") - .with_log(&mut inner.undo_log) - .into_infos_and_data(); - assert!(data.is_empty()); - var_infos + let inner = self.inner.borrow(); + assert!(!UndoLogs::>::in_snapshot(&inner.undo_log)); + let storage = inner.region_constraint_storage.as_ref().expect("regions already resolved"); + assert!(storage.data.is_empty()); + // We clone instead of taking because borrowck still wants to use the + // inference context after calling this for diagnostics and the new + // trait solver. + storage.var_infos.clone() } #[instrument(level = "debug", skip(self), ret)] diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index a270f9322f39b..e23bb1aaa5631 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -1,11 +1,12 @@ //! Various code related to computing outlives relations. +use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::traits::query::{NoSolution, OutlivesBound}; use rustc_middle::ty; use tracing::instrument; use self::env::OutlivesEnvironment; -use super::region_constraints::RegionConstraintData; +use super::region_constraints::{RegionConstraintData, UndoLog}; use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; @@ -63,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> { } }; - let (var_infos, data) = { + let storage = { let mut inner = self.inner.borrow_mut(); let inner = &mut *inner; assert!( @@ -71,18 +72,14 @@ impl<'tcx> InferCtxt<'tcx> { "region_obligations not empty: {:#?}", inner.region_obligations ); - inner - .region_constraint_storage - .take() - .expect("regions already resolved") - .with_log(&mut inner.undo_log) - .into_infos_and_data() + assert!(!UndoLogs::>::in_snapshot(&inner.undo_log)); + inner.region_constraint_storage.take().expect("regions already resolved") }; let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map()); let (lexical_region_resolutions, errors) = - lexical_region_resolve::resolve(region_rels, var_infos, data); + lexical_region_resolve::resolve(region_rels, storage.var_infos, storage.data); let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); assert!(old_value.is_none()); diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 4411f8db72a1e..0d9249bb552d8 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -27,9 +27,9 @@ pub use rustc_middle::infer::MemberConstraint; #[derive(Clone, Default)] pub struct RegionConstraintStorage<'tcx> { /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. - var_infos: IndexVec, + pub(super) var_infos: IndexVec, - data: RegionConstraintData<'tcx>, + pub(super) data: RegionConstraintData<'tcx>, /// For a given pair of regions (R1, R2), maps to a region R3 that /// is designated as their LUB (edges R1 <= R3 and R2 <= R3 @@ -354,14 +354,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { &self.data } - /// Once all the constraints have been gathered, extract out the final data. - /// - /// Not legal during a snapshot. - pub fn into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>) { - assert!(!UndoLogs::>::in_snapshot(&self.undo_log)); - (mem::take(&mut self.storage.var_infos), mem::take(&mut self.storage.data)) - } - /// Takes (and clears) the current set of constraints. Note that /// the set of variables remains intact, but all relationships /// between them are reset. This is used during NLL checking to From 85507cffc32de9211f03b5e257acfad4a24fcea5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Oct 2024 12:06:34 +1000 Subject: [PATCH 05/12] Inline and remove `RegionConstraintStorage::remove_constraint_entry`. It has a single call site. --- .../src/infer/region_constraints/mod.rs | 44 +++++++++---------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 0d9249bb552d8..a60954ad545d8 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -320,29 +320,6 @@ impl<'tcx> RegionConstraintStorage<'tcx> { ) -> RegionConstraintCollector<'a, 'tcx> { RegionConstraintCollector { storage: self, undo_log } } - - fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) { - match undo_entry { - AddVar(vid) => { - self.var_infos.pop().unwrap(); - assert_eq!(self.var_infos.len(), vid.index()); - } - AddConstraint(index) => { - self.data.constraints.pop().unwrap(); - assert_eq!(self.data.constraints.len(), index); - } - AddVerify(index) => { - self.data.verifys.pop(); - assert_eq!(self.data.verifys.len(), index); - } - AddCombination(Glb, ref regions) => { - self.glbs.remove(regions); - } - AddCombination(Lub, ref regions) => { - self.lubs.remove(regions); - } - } - } } impl<'tcx> RegionConstraintCollector<'_, 'tcx> { @@ -793,6 +770,25 @@ impl<'tcx> RegionConstraintData<'tcx> { impl<'tcx> Rollback> for RegionConstraintStorage<'tcx> { fn reverse(&mut self, undo: UndoLog<'tcx>) { - self.rollback_undo_entry(undo) + match undo { + AddVar(vid) => { + self.var_infos.pop().unwrap(); + assert_eq!(self.var_infos.len(), vid.index()); + } + AddConstraint(index) => { + self.data.constraints.pop().unwrap(); + assert_eq!(self.data.constraints.len(), index); + } + AddVerify(index) => { + self.data.verifys.pop(); + assert_eq!(self.data.verifys.len(), index); + } + AddCombination(Glb, ref regions) => { + self.glbs.remove(regions); + } + AddCombination(Lub, ref regions) => { + self.lubs.remove(regions); + } + } } } From e8a0bd65498976656fbb7fff7d74fbc91cc442d1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Oct 2024 13:58:13 +1000 Subject: [PATCH 06/12] Remove unnecessary lifetime from `LeakCheck`. `LeakCheck` can own `mini_graph` and `rcc` instead of holding references to them. This requires inlining `assign_scc_value` to avoid a borrowck error, but that's fine because it has a single call site. --- .../infer/region_constraints/leak_check.rs | 54 ++++++++----------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 30eba3e8f4fb7..3cfc58dea05bd 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -73,7 +73,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// * R: P1, R: P2, as above #[instrument(level = "debug", skip(self, tcx, only_consider_snapshot), ret)] pub fn leak_check( - &mut self, + self, tcx: TyCtxt<'tcx>, outer_universe: ty::UniverseIndex, max_universe: ty::UniverseIndex, @@ -83,7 +83,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { return Ok(()); } - let mini_graph = &MiniGraph::new(tcx, self, only_consider_snapshot); + let mini_graph = MiniGraph::new(tcx, &self, only_consider_snapshot); let mut leak_check = LeakCheck::new(tcx, outer_universe, max_universe, mini_graph, self); leak_check.assign_placeholder_values()?; @@ -92,11 +92,11 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } } -struct LeakCheck<'a, 'b, 'tcx> { +struct LeakCheck<'a, 'tcx> { tcx: TyCtxt<'tcx>, outer_universe: ty::UniverseIndex, - mini_graph: &'a MiniGraph<'tcx>, - rcc: &'a mut RegionConstraintCollector<'b, 'tcx>, + mini_graph: MiniGraph<'tcx>, + rcc: RegionConstraintCollector<'a, 'tcx>, // Initially, for each SCC S, stores a placeholder `P` such that `S = P` // must hold. @@ -115,26 +115,27 @@ struct LeakCheck<'a, 'b, 'tcx> { // either the placeholder `P1` or the empty region in that same universe. // // To detect errors, we look for an SCC S where the values in - // `scc_values[S]` (if any) cannot be stored into `scc_universes[S]`. + // `scc_placeholders[S]` (if any) cannot be stored into `scc_universes[S]`. scc_universes: IndexVec>, } -impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { +impl<'a, 'tcx> LeakCheck<'a, 'tcx> { fn new( tcx: TyCtxt<'tcx>, outer_universe: ty::UniverseIndex, max_universe: ty::UniverseIndex, - mini_graph: &'a MiniGraph<'tcx>, - rcc: &'a mut RegionConstraintCollector<'b, 'tcx>, + mini_graph: MiniGraph<'tcx>, + rcc: RegionConstraintCollector<'a, 'tcx>, ) -> Self { let dummy_scc_universe = SccUniverse { universe: max_universe, region: None }; + let num_sccs = mini_graph.sccs.num_sccs(); Self { tcx, outer_universe, mini_graph, rcc, - scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()), - scc_universes: IndexVec::from_elem_n(dummy_scc_universe, mini_graph.sccs.num_sccs()), + scc_placeholders: IndexVec::from_elem_n(None, num_sccs), + scc_universes: IndexVec::from_elem_n(dummy_scc_universe, num_sccs), } } @@ -156,7 +157,16 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { // Detect those SCCs that directly contain a placeholder if let ty::RePlaceholder(placeholder) = **region { if self.outer_universe.cannot_name(placeholder.universe) { - self.assign_scc_value(scc, placeholder)?; + // Update `scc_placeholders` to account for the fact that `P: S` must hold. + match self.scc_placeholders[scc] { + Some(p) => { + assert_ne!(p, placeholder); + return Err(self.placeholder_error(p, placeholder)); + } + None => { + self.scc_placeholders[scc] = Some(placeholder); + } + } } } } @@ -164,26 +174,6 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { Ok(()) } - // assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold. - // This may create an error. - fn assign_scc_value( - &mut self, - scc: LeakCheckScc, - placeholder: ty::PlaceholderRegion, - ) -> RelateResult<'tcx, ()> { - match self.scc_placeholders[scc] { - Some(p) => { - assert_ne!(p, placeholder); - return Err(self.placeholder_error(p, placeholder)); - } - None => { - self.scc_placeholders[scc] = Some(placeholder); - } - }; - - Ok(()) - } - /// For each SCC S, iterate over each successor S1 where `S: S1`: /// /// * Compute From 8b05df44f96978b81df4af51f469c266b21df793 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Oct 2024 14:16:55 +1000 Subject: [PATCH 07/12] Remove `Deref`/`DerefMut` impls for `RegionConstraintCollector`. `Deref`/`DerefMut` can be useful, but they can also obfuscate. I don't think they're worth it for `RegionConstraintCollector`. They're also not present on the similar types `OpaqueTypeTable` and `TypeVariableTable`. --- .../src/infer/region_constraints/mod.rs | 50 +++++++------------ 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index a60954ad545d8..c7dd65330be50 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -61,21 +61,6 @@ pub struct RegionConstraintCollector<'a, 'tcx> { undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } -impl<'tcx> std::ops::Deref for RegionConstraintCollector<'_, 'tcx> { - type Target = RegionConstraintStorage<'tcx>; - #[inline] - fn deref(&self) -> &RegionConstraintStorage<'tcx> { - self.storage - } -} - -impl<'tcx> std::ops::DerefMut for RegionConstraintCollector<'_, 'tcx> { - #[inline] - fn deref_mut(&mut self) -> &mut RegionConstraintStorage<'tcx> { - self.storage - } -} - pub type VarInfos = IndexVec; /// The full set of region constraints gathered up by the collector. @@ -324,11 +309,11 @@ impl<'tcx> RegionConstraintStorage<'tcx> { impl<'tcx> RegionConstraintCollector<'_, 'tcx> { pub fn num_region_vars(&self) -> usize { - self.var_infos.len() + self.storage.var_infos.len() } pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> { - &self.data + &self.storage.data } /// Takes (and clears) the current set of constraints. Note that @@ -384,17 +369,17 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } pub fn data(&self) -> &RegionConstraintData<'tcx> { - &self.data + &self.storage.data } pub(super) fn start_snapshot(&mut self) -> RegionSnapshot { debug!("RegionConstraintCollector: start_snapshot"); - RegionSnapshot { any_unifications: self.any_unifications } + RegionSnapshot { any_unifications: self.storage.any_unifications } } pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) { debug!("RegionConstraintCollector: rollback_to({:?})", snapshot); - self.any_unifications = snapshot.any_unifications; + self.storage.any_unifications = snapshot.any_unifications; } pub(super) fn new_region_var( @@ -402,7 +387,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { universe: ty::UniverseIndex, origin: RegionVariableOrigin, ) -> RegionVid { - let vid = self.var_infos.push(RegionVariableInfo { origin, universe }); + let vid = self.storage.var_infos.push(RegionVariableInfo { origin, universe }); let u_vid = self.unification_table_mut().new_key(RegionVariableValue::Unknown { universe }); assert_eq!(vid, u_vid.vid); @@ -413,7 +398,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// Returns the origin for the given variable. pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { - self.var_infos[vid].origin + self.storage.var_infos[vid].origin } fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) { @@ -436,8 +421,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { return; } - let index = self.data.verifys.len(); - self.data.verifys.push(verify); + let index = self.storage.data.verifys.len(); + self.storage.data.verifys.push(verify); self.undo_log.push(AddVerify(index)); } @@ -457,7 +442,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { (ty::ReVar(a), ty::ReVar(b)) => { debug!("make_eqregion: unifying {:?} with {:?}", a, b); if self.unification_table_mut().unify_var_var(a, b).is_ok() { - self.any_unifications = true; + self.storage.any_unifications = true; } } (ty::ReVar(vid), _) => { @@ -467,7 +452,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { .unify_var_value(vid, RegionVariableValue::Known { value: b }) .is_ok() { - self.any_unifications = true; + self.storage.any_unifications = true; }; } (_, ty::ReVar(vid)) => { @@ -477,7 +462,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { .unify_var_value(vid, RegionVariableValue::Known { value: a }) .is_ok() { - self.any_unifications = true; + self.storage.any_unifications = true; }; } (_, _) => {} @@ -499,7 +484,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { return; } - self.data.member_constraints.push(MemberConstraint { + self.storage.data.member_constraints.push(MemberConstraint { key, definition_span, hidden_ty, @@ -615,8 +600,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> { match t { - Glb => &mut self.glbs, - Lub => &mut self.lubs, + Glb => &mut self.storage.glbs, + Lub => &mut self.storage.lubs, } } @@ -669,11 +654,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { &self, value_count: usize, ) -> (Range, Vec) { - let range = RegionVid::from(value_count)..RegionVid::from(self.unification_table.len()); + let range = + RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len()); ( range.clone(), (range.start.index()..range.end.index()) - .map(|index| self.var_infos[ty::RegionVid::from(index)].origin) + .map(|index| self.storage.var_infos[ty::RegionVid::from(index)].origin) .collect(), ) } From 4df21f2ca0a51e0687fd7443c99ed32edb080988 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Oct 2024 14:33:28 +1000 Subject: [PATCH 08/12] Downgrade a `&mut self` to `&self`. --- compiler/rustc_infer/src/infer/region_constraints/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index c7dd65330be50..6a7f30a5dcf5d 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -372,7 +372,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { &self.storage.data } - pub(super) fn start_snapshot(&mut self) -> RegionSnapshot { + pub(super) fn start_snapshot(&self) -> RegionSnapshot { debug!("RegionConstraintCollector: start_snapshot"); RegionSnapshot { any_unifications: self.storage.any_unifications } } From 1dac23f6fef62faf178d3bbdab15b99fc19abafa Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Oct 2024 14:40:05 +1000 Subject: [PATCH 09/12] Use `Default` more in `InferCtxtInner`. --- compiler/rustc_infer/src/infer/mod.rs | 12 ++++++------ .../rustc_infer/src/infer/region_constraints/mod.rs | 4 ---- compiler/rustc_infer/src/infer/type_variable.rs | 9 +-------- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 785ef8f939e14..21f9bf028d5ea 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -171,12 +171,12 @@ impl<'tcx> InferCtxtInner<'tcx> { undo_log: InferCtxtUndoLogs::default(), projection_cache: Default::default(), - type_variable_storage: type_variable::TypeVariableStorage::new(), - const_unification_storage: ut::UnificationTableStorage::new(), - int_unification_storage: ut::UnificationTableStorage::new(), - float_unification_storage: ut::UnificationTableStorage::new(), - effect_unification_storage: ut::UnificationTableStorage::new(), - region_constraint_storage: Some(RegionConstraintStorage::new()), + type_variable_storage: Default::default(), + const_unification_storage: Default::default(), + int_unification_storage: Default::default(), + float_unification_storage: Default::default(), + effect_unification_storage: Default::default(), + region_constraint_storage: Some(Default::default()), region_obligations: vec![], opaque_type_storage: Default::default(), } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 6a7f30a5dcf5d..270217e26b78c 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -294,10 +294,6 @@ pub(crate) struct RegionSnapshot { } impl<'tcx> RegionConstraintStorage<'tcx> { - pub fn new() -> Self { - Self::default() - } - #[inline] pub(crate) fn with_log<'a>( &'a mut self, diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index c50477b2922be..779ce976becc0 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -19,7 +19,7 @@ impl<'tcx> Rollback>>> for TypeVariabl } } -#[derive(Clone)] +#[derive(Clone, Default)] pub(crate) struct TypeVariableStorage<'tcx> { /// The origins of each type variable. values: IndexVec, @@ -74,13 +74,6 @@ impl<'tcx> TypeVariableValue<'tcx> { } impl<'tcx> TypeVariableStorage<'tcx> { - pub(crate) fn new() -> TypeVariableStorage<'tcx> { - TypeVariableStorage { - values: Default::default(), - eq_relations: ut::UnificationTableStorage::new(), - } - } - #[inline] pub(crate) fn with_log<'a>( &'a mut self, From 3b1eee775550530c51131161d3b397517ef69f10 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 7 Oct 2024 10:01:37 +1100 Subject: [PATCH 10/12] Remove unnecessary `return` keyword. --- compiler/rustc_infer/src/infer/resolve.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 025c3a629fabf..64cc76f827eb8 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx> TypeFolder> for OpportunisticVarResolver<'a, 'tcx> { if !t.has_non_region_infer() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else if let Some(&ty) = self.cache.get(&t) { - return ty; + ty } else { let shallow = self.infcx.shallow_resolve(t); let res = shallow.super_fold_with(self); From b81a3c81998b03cab4925801edf11c3113b26184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Tue, 8 Oct 2024 04:30:19 +0000 Subject: [PATCH 11/12] Drop compiletest legacy directive checks Sufficient time has passed (> 6 months) since we migrated from `//` to `//@`, so let's drop the legacy directive check as it causes friction due to false positives. --- src/tools/compiletest/src/header.rs | 129 +++++++----------- .../test-auxillary/known_legacy_directive.rs | 1 - src/tools/compiletest/src/header/tests.rs | 11 -- 3 files changed, 48 insertions(+), 93 deletions(-) delete mode 100644 src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 83a10c5620864..a6830a6aa173f 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -5,9 +5,7 @@ use std::io::BufReader; use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Command; -use std::sync::OnceLock; -use regex::Regex; use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; @@ -797,7 +795,6 @@ struct HeaderLine<'ln> { pub(crate) struct CheckDirectiveResult<'ln> { is_known_directive: bool, - directive_name: &'ln str, trailing_directive: Option<&'ln str>, } @@ -832,11 +829,7 @@ pub(crate) fn check_directive<'a>( } .then_some(trailing); - CheckDirectiveResult { - is_known_directive: is_known(&directive_name), - directive_name: directive_ln, - trailing_directive, - } + CheckDirectiveResult { is_known_directive: is_known(&directive_name), trailing_directive } } fn iter_header( @@ -851,16 +844,17 @@ fn iter_header( return; } - // Coverage tests in coverage-run mode always have these extra directives, - // without needing to specify them manually in every test file. - // (Some of the comments below have been copied over from the old - // `tests/run-make/coverage-reports/Makefile`, which no longer exists.) + // Coverage tests in coverage-run mode always have these extra directives, without needing to + // specify them manually in every test file. (Some of the comments below have been copied over + // from the old `tests/run-make/coverage-reports/Makefile`, which no longer exists.) + // + // FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later. if mode == Mode::CoverageRun { let extra_directives: &[&str] = &[ "needs-profiler-support", - // FIXME(pietroalbini): this test currently does not work on cross-compiled - // targets because remote-test is not capable of sending back the *.profraw - // files generated by the LLVM instrumentation. + // FIXME(pietroalbini): this test currently does not work on cross-compiled targets + // because remote-test is not capable of sending back the *.profraw files generated by + // the LLVM instrumentation. "ignore-cross-compile", ]; // Process the extra implied directives, with a dummy line number of 0. @@ -869,17 +863,13 @@ fn iter_header( } } + // NOTE(jieyouxu): once we get rid of `Makefile`s we can unconditionally check for `//@`. let comment = if testfile.extension().is_some_and(|e| e == "rs") { "//@" } else { "#" }; let mut rdr = BufReader::with_capacity(1024, rdr); let mut ln = String::new(); let mut line_number = 0; - // Match on error annotations like `//~ERROR`. - static REVISION_MAGIC_COMMENT_RE: OnceLock = OnceLock::new(); - let revision_magic_comment_re = - REVISION_MAGIC_COMMENT_RE.get_or_init(|| Regex::new("//(\\[.*\\])?~.*").unwrap()); - loop { line_number += 1; ln.clear(); @@ -892,85 +882,62 @@ fn iter_header( // with a warm page cache. Maybe with a cold one. let original_line = &ln; let ln = ln.trim(); + + // Assume that any directives will be found before the first module or function. This + // doesn't seem to be an optimization with a warm page cache. Maybe with a cold one. + // FIXME(jieyouxu): this will cause `//@` directives in the rest of the test file to + // not be checked. if ln.starts_with("fn") || ln.starts_with("mod") { return; + } - // First try to accept `ui_test` style comments (`//@`) - } else if let Some((header_revision, non_revisioned_directive_line)) = - line_directive(comment, ln) - { - // Perform unknown directive check on Rust files. - if testfile.extension().map(|e| e == "rs").unwrap_or(false) { - let directive_ln = non_revisioned_directive_line.trim(); - - let CheckDirectiveResult { is_known_directive, trailing_directive, .. } = - check_directive(directive_ln, mode, ln); - - if !is_known_directive { - *poisoned = true; - - eprintln!( - "error: detected unknown compiletest test directive `{}` in {}:{}", - directive_ln, - testfile.display(), - line_number, - ); - - return; - } + let Some((header_revision, non_revisioned_directive_line)) = line_directive(comment, ln) + else { + continue; + }; - if let Some(trailing_directive) = &trailing_directive { - *poisoned = true; + // Perform unknown directive check on Rust files. + if testfile.extension().map(|e| e == "rs").unwrap_or(false) { + let directive_ln = non_revisioned_directive_line.trim(); - eprintln!( - "error: detected trailing compiletest test directive `{}` in {}:{}\n \ - help: put the trailing directive in it's own line: `//@ {}`", - trailing_directive, - testfile.display(), - line_number, - trailing_directive, - ); + let CheckDirectiveResult { is_known_directive, trailing_directive } = + check_directive(directive_ln, mode, ln); - return; - } - } + if !is_known_directive { + *poisoned = true; - it(HeaderLine { - line_number, - original_line, - header_revision, - directive: non_revisioned_directive_line, - }); - // Then we try to check for legacy-style candidates, which are not the magic ~ERROR family - // error annotations. - } else if !revision_magic_comment_re.is_match(ln) { - let Some((_, rest)) = line_directive("//", ln) else { - continue; - }; + eprintln!( + "error: detected unknown compiletest test directive `{}` in {}:{}", + directive_ln, + testfile.display(), + line_number, + ); - if rest.trim_start().starts_with(':') { - // This is likely a markdown link: - // `[link_name]: https://example.org` - continue; + return; } - let rest = rest.trim_start(); - - let CheckDirectiveResult { is_known_directive, directive_name, .. } = - check_directive(rest, mode, ln); - - if is_known_directive { + if let Some(trailing_directive) = &trailing_directive { *poisoned = true; + eprintln!( - "error: detected legacy-style directive {} in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead: {:#?}", - directive_name, + "error: detected trailing compiletest test directive `{}` in {}:{}\n \ + help: put the trailing directive in it's own line: `//@ {}`", + trailing_directive, testfile.display(), line_number, - line_directive("//", ln), + trailing_directive, ); + return; } } + + it(HeaderLine { + line_number, + original_line, + header_revision, + directive: non_revisioned_directive_line, + }); } } diff --git a/src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs b/src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs deleted file mode 100644 index 108ca432e1308..0000000000000 --- a/src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs +++ /dev/null @@ -1 +0,0 @@ -// ignore-wasm diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 76a8b129198dc..b70b4b27f400d 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -618,17 +618,6 @@ fn test_unknown_directive_check() { assert!(poisoned); } -#[test] -fn test_known_legacy_directive_check() { - let mut poisoned = false; - run_path( - &mut poisoned, - Path::new("a.rs"), - include_bytes!("./test-auxillary/known_legacy_directive.rs"), - ); - assert!(poisoned); -} - #[test] fn test_known_directive_check_no_error() { let mut poisoned = false; From aeaea1b4b1a0b7bb7f3269d11d816251dc99aa00 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 8 Oct 2024 12:08:16 +0200 Subject: [PATCH 12/12] Add a mailmap entry for bjorn3 --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 9ac7f1a9b494c..0f58762e0233c 100644 --- a/.mailmap +++ b/.mailmap @@ -74,6 +74,7 @@ Ben Striegel Benjamin Jackman Benoît Cortier Bheesham Persaud Bheesham Persaud +bjorn3 <17426603+bjorn3@users.noreply.github.com> Björn Steinbrink blake2-ppc blyxyas Alejandra González