From 924d6cd1a625a1200bd587f9ecb734aec0d72ae2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 6 Feb 2024 01:14:12 +0100 Subject: Tweak how we record missing constructors This is slower but also not a performance-sensitive path. --- compiler/rustc_pattern_analysis/src/usefulness.rs | 37 ++++++++++------------- 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 80a807b4f27..bab53c04248 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -1319,7 +1319,7 @@ impl WitnessMatrix { fn apply_constructor( &mut self, pcx: &PlaceCtxt<'_, Cx>, - missing_ctors: &[Constructor], + mut missing_ctors: &[Constructor], ctor: &Constructor, report_individual_missing_ctors: bool, ) { @@ -1329,32 +1329,27 @@ impl WitnessMatrix { if matches!(ctor, Constructor::Missing) { // We got the special `Missing` constructor that stands for the constructors not present // in the match. - if missing_ctors.is_empty() { - // Nothing to report. - *self = Self::empty(); - } else if !report_individual_missing_ctors { + if !missing_ctors.is_empty() && !report_individual_missing_ctors { // Report `_` as missing. - let pat = pcx.wild_from_ctor(Constructor::Wildcard); - self.push_pattern(pat); + missing_ctors = &[Constructor::Wildcard]; } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { // We need to report a `_` anyway, so listing other constructors would be redundant. // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked // up by diagnostics to add a note about why `_` is required here. - let pat = pcx.wild_from_ctor(Constructor::NonExhaustive); - self.push_pattern(pat); - } else { - // For each missing constructor `c`, we add a `c(_, _, _)` witness appropriately - // filled with wildcards. - let mut ret = Self::empty(); - for ctor in missing_ctors { - let pat = pcx.wild_from_ctor(ctor.clone()); - // Clone `self` and add `c(_, _, _)` to each of its witnesses. - let mut wit_matrix = self.clone(); - wit_matrix.push_pattern(pat); - ret.extend(wit_matrix); - } - *self = ret; + missing_ctors = &[Constructor::NonExhaustive]; + } + + // For each missing constructor `c`, we add a `c(_, _, _)` witness appropriately + // filled with wildcards. + let mut ret = Self::empty(); + for ctor in missing_ctors { + let pat = pcx.wild_from_ctor(ctor.clone()); + // Clone `self` and add `c(_, _, _)` to each of its witnesses. + let mut wit_matrix = self.clone(); + wit_matrix.push_pattern(pat); + ret.extend(wit_matrix); } + *self = ret; } else { // Any other constructor we unspecialize as expected. for witness in self.0.iter_mut() { -- cgit 1.4.1-3-g733a5 From 3602b9d8174ac697b0f28721076e0c1e7513a410 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 6 Feb 2024 01:21:29 +0100 Subject: Decide which constructors to report earlier. This gets rid of `report_individual_missing_ctors` --- compiler/rustc_pattern_analysis/src/usefulness.rs | 36 +++++++++++------------ 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index bab53c04248..9b15f447c89 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -1319,28 +1319,16 @@ impl WitnessMatrix { fn apply_constructor( &mut self, pcx: &PlaceCtxt<'_, Cx>, - mut missing_ctors: &[Constructor], + missing_ctors: &[Constructor], ctor: &Constructor, - report_individual_missing_ctors: bool, ) { if self.is_empty() { return; } if matches!(ctor, Constructor::Missing) { // We got the special `Missing` constructor that stands for the constructors not present - // in the match. - if !missing_ctors.is_empty() && !report_individual_missing_ctors { - // Report `_` as missing. - missing_ctors = &[Constructor::Wildcard]; - } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { - // We need to report a `_` anyway, so listing other constructors would be redundant. - // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked - // up by diagnostics to add a note about why `_` is required here. - missing_ctors = &[Constructor::NonExhaustive]; - } - - // For each missing constructor `c`, we add a `c(_, _, _)` witness appropriately - // filled with wildcards. + // in the match. For each missing constructor `c`, we add a `c(_, _, _)` witness + // appropriately filled with wildcards. let mut ret = Self::empty(); for ctor in missing_ctors { let pat = pcx.wild_from_ctor(ctor.clone()); @@ -1515,9 +1503,6 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( split_ctors.push(Constructor::Missing); } - // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". At the top - // level we prefer to list all constructors. - let report_individual_missing_ctors = place.is_scrutinee || !all_missing; // Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() => // split_ctors.contains(Missing)`. The converse usually holds except when // `!place_validity.is_known_valid()`. @@ -1526,6 +1511,19 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( missing_ctors.append(&mut split_set.missing_empty); } + // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". At the top + // level we prefer to list all constructors. + let report_individual_missing_ctors = place.is_scrutinee || !all_missing; + if !missing_ctors.is_empty() && !report_individual_missing_ctors { + // Report `_` as missing. + missing_ctors = vec![Constructor::Wildcard]; + } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { + // We need to report a `_` anyway, so listing other constructors would be redundant. + // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked + // up by diagnostics to add a note about why `_` is required here. + missing_ctors = vec![Constructor::NonExhaustive]; + } + let mut ret = WitnessMatrix::empty(); for ctor in split_ctors { // Dig into rows that match `ctor`. @@ -1540,7 +1538,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( })?; // Transform witnesses for `spec_matrix` into witnesses for `matrix`. - witnesses.apply_constructor(pcx, &missing_ctors, &ctor, report_individual_missing_ctors); + witnesses.apply_constructor(pcx, &missing_ctors, &ctor); // Accumulate the found witnesses. ret.extend(witnesses); -- cgit 1.4.1-3-g733a5 From 778c7e1db4fbafa62eb9fdd945544eecc437986f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 6 Feb 2024 03:52:46 +0100 Subject: Move constructor selection logic to `PlaceInfo` --- compiler/rustc_pattern_analysis/src/usefulness.rs | 135 +++++++++++++--------- 1 file changed, 79 insertions(+), 56 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 9b15f447c89..90fcb63dc1d 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -767,9 +767,6 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> { fn ctor_arity(&self, ctor: &Constructor) -> usize { self.cx.ctor_arity(ctor, self.ty) } - fn ctors_for_ty(&self) -> Result, Cx::Error> { - self.cx.ctors_for_ty(self.ty) - } fn wild_from_ctor(&self, ctor: Constructor) -> WitnessPat { WitnessPat::wild_from_ctor(self.cx, ctor, self.ty.clone()) } @@ -822,7 +819,8 @@ impl fmt::Display for ValidityConstraint { } } -/// Data about a place under investigation. +/// Data about a place under investigation. Its methods contain a lot of the logic used to analyze +/// the constructors in the matrix. struct PlaceInfo { /// The type of the place. ty: Cx::Ty, @@ -833,6 +831,8 @@ struct PlaceInfo { } impl PlaceInfo { + /// Given a constructor for the current place, we return one `PlaceInfo` for each field of the + /// constructor. fn specialize<'a>( &'a self, cx: &'a Cx, @@ -846,6 +846,77 @@ impl PlaceInfo { is_scrutinee: false, }) } + + /// This analyzes a column of constructors corresponding to the current place. It returns a pair + /// `(split_ctors, missing_ctors)`. + /// + /// `split_ctors` is a splitted list of constructors that cover the whole type. This will be + /// used to specialize the matrix. + /// + /// `missing_ctors` is a list of the constructors not found in the column, for reporting + /// purposes. + fn split_column_ctors<'a>( + &self, + cx: &Cx, + ctors: impl Iterator> + Clone, + ) -> Result<(SmallVec<[Constructor; 1]>, Vec>), Cx::Error> + where + Cx: 'a, + { + let ctors_for_ty = cx.ctors_for_ty(&self.ty)?; + + // We treat match scrutinees of type `!` or `EmptyEnum` differently. + let is_toplevel_exception = + self.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors); + // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if + // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`). + let empty_arms_are_unreachable = self.validity.is_known_valid() + && (is_toplevel_exception + || cx.is_exhaustive_patterns_feature_on() + || cx.is_min_exhaustive_patterns_feature_on()); + // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the + // toplevel exception and `exhaustive_patterns` cases for backwards compatibility. + let can_omit_empty_arms = empty_arms_are_unreachable + || is_toplevel_exception + || cx.is_exhaustive_patterns_feature_on(); + + // Analyze the constructors present in this column. + let mut split_set = ctors_for_ty.split(ctors); + let all_missing = split_set.present.is_empty(); + + // Build the set of constructors we will specialize with. It must cover the whole type, so + // we add `Missing` to represent the missing ones. This is explained under "Constructor + // Splitting" at the top of this file. + let mut split_ctors = split_set.present; + if !(split_set.missing.is_empty() + && (split_set.missing_empty.is_empty() || empty_arms_are_unreachable)) + { + split_ctors.push(Constructor::Missing); + } + + // Which empty constructors are considered missing. We ensure that + // `!missing_ctors.is_empty() => split_ctors.contains(Missing)`. The converse usually holds + // except when `!self.validity.is_known_valid()`. + let mut missing_ctors = split_set.missing; + if !can_omit_empty_arms { + missing_ctors.append(&mut split_set.missing_empty); + } + + // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". At the top + // level we prefer to list all constructors. + let report_individual_missing_ctors = self.is_scrutinee || !all_missing; + if !missing_ctors.is_empty() && !report_individual_missing_ctors { + // Report `_` as missing. + missing_ctors = vec![Constructor::Wildcard]; + } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { + // We need to report a `_` anyway, so listing other constructors would be redundant. + // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked + // up by diagnostics to add a note about why `_` is required here. + missing_ctors = vec![Constructor::NonExhaustive]; + } + + Ok((split_ctors, missing_ctors)) + } } impl Clone for PlaceInfo { @@ -1469,61 +1540,13 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( }; }; - let ty = &place.ty.clone(); // Clone it out so we can mutate `matrix` later. - let pcx = &PlaceCtxt { cx: mcx.tycx, ty }; - debug!("ty: {:?}", pcx.ty); - let ctors_for_ty = pcx.ctors_for_ty()?; - - // We treat match scrutinees of type `!` or `EmptyEnum` differently. - let is_toplevel_exception = - place.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors); - // Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if - // it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`). - let empty_arms_are_unreachable = place.validity.is_known_valid() - && (is_toplevel_exception - || mcx.tycx.is_exhaustive_patterns_feature_on() - || mcx.tycx.is_min_exhaustive_patterns_feature_on()); - // Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the - // toplevel exception and `exhaustive_patterns` cases for backwards compatibility. - let can_omit_empty_arms = empty_arms_are_unreachable - || is_toplevel_exception - || mcx.tycx.is_exhaustive_patterns_feature_on(); - // Analyze the constructors present in this column. + debug!("ty: {:?}", place.ty); let ctors = matrix.heads().map(|p| p.ctor()); - let mut split_set = ctors_for_ty.split(ctors); - let all_missing = split_set.present.is_empty(); - // Build the set of constructors we will specialize with. It must cover the whole type. - // We need to iterate over a full set of constructors, so we add `Missing` to represent the - // missing ones. This is explained under "Constructor Splitting" at the top of this file. - let mut split_ctors = split_set.present; - if !(split_set.missing.is_empty() - && (split_set.missing_empty.is_empty() || empty_arms_are_unreachable)) - { - split_ctors.push(Constructor::Missing); - } - - // Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() => - // split_ctors.contains(Missing)`. The converse usually holds except when - // `!place_validity.is_known_valid()`. - let mut missing_ctors = split_set.missing; - if !can_omit_empty_arms { - missing_ctors.append(&mut split_set.missing_empty); - } - - // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". At the top - // level we prefer to list all constructors. - let report_individual_missing_ctors = place.is_scrutinee || !all_missing; - if !missing_ctors.is_empty() && !report_individual_missing_ctors { - // Report `_` as missing. - missing_ctors = vec![Constructor::Wildcard]; - } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { - // We need to report a `_` anyway, so listing other constructors would be redundant. - // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked - // up by diagnostics to add a note about why `_` is required here. - missing_ctors = vec![Constructor::NonExhaustive]; - } + let (split_ctors, missing_ctors) = place.split_column_ctors(mcx.tycx, ctors)?; + let ty = &place.ty.clone(); // Clone it out so we can mutate `matrix` later. + let pcx = &PlaceCtxt { cx: mcx.tycx, ty }; let mut ret = WitnessMatrix::empty(); for ctor in split_ctors { // Dig into rows that match `ctor`. -- cgit 1.4.1-3-g733a5 From e9cda9b139548ca096f5fb5f9823bee259f267be Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 13 Feb 2024 14:56:20 +0000 Subject: Continue reporting remaining errors instead of silently dropping them --- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 5 ++-- tests/ui/typeck/cyclic_type_ice.rs | 7 ++++++ tests/ui/typeck/cyclic_type_ice.stderr | 31 +++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tests/ui/typeck/cyclic_type_ice.rs create mode 100644 tests/ui/typeck/cyclic_type_ice.stderr (limited to 'compiler') diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 35b3f27d791..1a454f9dd96 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -740,8 +740,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); // We're done if we found errors, but we already emitted them. - if let Some(reported) = reported { - assert!(errors.is_empty()); + if let Some(reported) = reported + && errors.is_empty() + { return reported; } assert!(!errors.is_empty()); diff --git a/tests/ui/typeck/cyclic_type_ice.rs b/tests/ui/typeck/cyclic_type_ice.rs new file mode 100644 index 00000000000..7899b354f38 --- /dev/null +++ b/tests/ui/typeck/cyclic_type_ice.rs @@ -0,0 +1,7 @@ +fn thing() { + let f = |_, _| (); + f(f); //~ ERROR: closure/coroutine type that references itself + //~^ ERROR: this function takes 2 arguments but 1 argument was supplied +} + +fn main() {} diff --git a/tests/ui/typeck/cyclic_type_ice.stderr b/tests/ui/typeck/cyclic_type_ice.stderr new file mode 100644 index 00000000000..bfff6830fc5 --- /dev/null +++ b/tests/ui/typeck/cyclic_type_ice.stderr @@ -0,0 +1,31 @@ +error[E0644]: closure/coroutine type that references itself + --> $DIR/cyclic_type_ice.rs:3:7 + | +LL | f(f); + | ^ cyclic type of infinite size + | + = note: closures cannot capture themselves or take themselves as argument; + this error may be the result of a recent compiler bug-fix, + see issue #46062 + for more information + +error[E0057]: this function takes 2 arguments but 1 argument was supplied + --> $DIR/cyclic_type_ice.rs:3:5 + | +LL | f(f); + | ^--- an argument is missing + | +note: closure defined here + --> $DIR/cyclic_type_ice.rs:2:13 + | +LL | let f = |_, _| (); + | ^^^^^^ +help: provide the argument + | +LL | f(/* */, /* */); + | ~~~~~~~~~~~~~~~~ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0057, E0644. +For more information about an error, try `rustc --explain E0057`. -- cgit 1.4.1-3-g733a5 From e72e7e9ae3a6938f1a926ca10f693d89948134cb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 17 Feb 2024 09:13:45 +1100 Subject: Merge `CompilerError::CompilationFailed` and `CompilerError::ICE`. `CompilerError` has `CompilationFailed` and `ICE` variants, which seems reasonable at first. But the way it identifies them is flawed: - If compilation errors out, i.e. `RunCompiler::run` returns an `Err`, it uses `CompilationFailed`, which is reasonable. - If compilation panics with `FatalError`, it catches the panic and uses `ICE`. This is sometimes right, because ICEs do cause `FatalError` panics, but sometimes wrong, because certain compiler errors also cause `FatalError` panics. (The compiler/rustdoc/clippy/whatever just catches the `FatalError` with `catch_with_exit_code` in `main`.) In other words, certain non-ICE compilation failures get miscategorized as ICEs. It's not possible to reliably distinguish the two cases, so this commit merges them. It also renames the combined variant as just `Failed`, to better match the existing `Interrupted` and `Skipped` variants. Here is an example of a non-ICE failure that causes a `FatalError` panic, from `tests/ui/recursion_limit/issue-105700.rs`: ``` #![recursion_limit="4"] #![invalid_attribute] #![invalid_attribute] #![invalid_attribute] #![invalid_attribute] #![invalid_attribute] //~^ERROR recursion limit reached while expanding fn main() {{}} ``` --- compiler/rustc_smir/src/rustc_internal/mod.rs | 10 ++++++++-- compiler/stable_mir/src/error.rs | 12 ++++-------- tests/ui-fulldeps/stable-mir/compilation-result.rs | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 6bb8c5452b9..6e870728baf 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -347,8 +347,14 @@ macro_rules! run_driver { Err(CompilerError::Interrupted(value)) } (Ok(Ok(_)), None) => Err(CompilerError::Skipped), - (Ok(Err(_)), _) => Err(CompilerError::CompilationFailed), - (Err(_), _) => Err(CompilerError::ICE), + // Two cases here: + // - `run` finished normally and returned `Err` + // - `run` panicked with `FatalErr` + // You might think that normal compile errors cause the former, and + // ICEs cause the latter. But some normal compiler errors also cause + // the latter. So we can't meaningfully distinguish them, and group + // them together. + (Ok(Err(_)), _) | (Err(_), _) => Err(CompilerError::Failed), } } } diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs index 7085fa937c9..9e3f4936944 100644 --- a/compiler/stable_mir/src/error.rs +++ b/compiler/stable_mir/src/error.rs @@ -15,10 +15,8 @@ macro_rules! error { /// An error type used to represent an error that has already been reported by the compiler. #[derive(Clone, Copy, PartialEq, Eq)] pub enum CompilerError { - /// Internal compiler error (I.e.: Compiler crashed). - ICE, - /// Compilation failed. - CompilationFailed, + /// Compilation failed, either due to normal errors or ICE. + Failed, /// Compilation was interrupted. Interrupted(T), /// Compilation skipped. This happens when users invoke rustc to retrieve information such as @@ -54,8 +52,7 @@ where { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - CompilerError::ICE => write!(f, "Internal Compiler Error"), - CompilerError::CompilationFailed => write!(f, "Compilation Failed"), + CompilerError::Failed => write!(f, "Compilation Failed"), CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason}"), CompilerError::Skipped => write!(f, "Compilation Skipped"), } @@ -68,8 +65,7 @@ where { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - CompilerError::ICE => write!(f, "Internal Compiler Error"), - CompilerError::CompilationFailed => write!(f, "Compilation Failed"), + CompilerError::Failed => write!(f, "Compilation Failed"), CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason:?}"), CompilerError::Skipped => write!(f, "Compilation Skipped"), } diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index e6dd9fa132d..cd61d599eb4 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -55,7 +55,7 @@ fn test_skipped(mut args: Vec) { fn test_failed(mut args: Vec) { args.push("--cfg=broken".to_string()); let result = run!(args, || unreachable!() as ControlFlow<()>); - assert_eq!(result, Err(stable_mir::CompilerError::CompilationFailed)); + assert_eq!(result, Err(stable_mir::CompilerError::Failed)); } /// Test that we are able to pass a closure and set the return according to the captured value. -- cgit 1.4.1-3-g733a5 From 42e7338eae9f60a7eaf65d45f61f0e5b06c6ef25 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 17 Feb 2024 00:25:49 +0100 Subject: rename `needs_wf` and clarify comment --- compiler/rustc_infer/src/infer/relate/combine.rs | 37 ++++++++------ .../rustc_infer/src/infer/relate/generalize.rs | 58 ++++++++++------------ compiler/rustc_infer/src/infer/relate/nll.rs | 15 +++--- 3 files changed, 56 insertions(+), 54 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 7edfbf02a68..2e856f6a145 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -307,14 +307,18 @@ impl<'tcx> InferCtxt<'tcx> { }; // FIXME(generic_const_exprs): Occurs check failures for unevaluated // constants and generic expressions are not yet handled correctly. - let Generalization { value_may_be_infer: value, needs_wf: _ } = generalize::generalize( - self, - &mut CombineDelegate { infcx: self, span }, - ct, - target_vid, - ty::Variance::Invariant, - )?; - + let Generalization { value_may_be_infer: value, has_unconstrained_ty_var } = + generalize::generalize( + self, + &mut CombineDelegate { infcx: self, span }, + ct, + target_vid, + ty::Variance::Invariant, + )?; + + if has_unconstrained_ty_var { + span_bug!(span, "unconstrained ty var when generalizing `{ct:?}`"); + } self.inner .borrow_mut() .const_unification_table() @@ -414,13 +418,14 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { // `'?2` and `?3` are fresh region/type inference // variables. (Down below, we will relate `a_ty <: b_ty`, // adding constraints like `'x: '?2` and `?1 <: ?3`.) - let Generalization { value_may_be_infer: b_ty, needs_wf } = generalize::generalize( - self.infcx, - &mut CombineDelegate { infcx: self.infcx, span: self.trace.span() }, - a_ty, - b_vid, - ambient_variance, - )?; + let Generalization { value_may_be_infer: b_ty, has_unconstrained_ty_var } = + generalize::generalize( + self.infcx, + &mut CombineDelegate { infcx: self.infcx, span: self.trace.span() }, + a_ty, + b_vid, + ambient_variance, + )?; // Constrain `b_vid` to the generalized type `b_ty`. if let &ty::Infer(TyVar(b_ty_vid)) = b_ty.kind() { @@ -429,7 +434,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty); } - if needs_wf { + if has_unconstrained_ty_var { self.obligations.push(Obligation::new( self.tcx(), self.trace.cause.clone(), diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index bc16d613ccb..52d2661bdaf 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -43,14 +43,14 @@ pub fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into> + Rela for_universe, root_term: term.into(), in_alias: false, - needs_wf: false, + has_unconstrained_ty_var: false, cache: Default::default(), }; assert!(!term.has_escaping_bound_vars()); let value_may_be_infer = generalizer.relate(term, term)?; - let needs_wf = generalizer.needs_wf; - Ok(Generalization { value_may_be_infer, needs_wf }) + let has_unconstrained_ty_var = generalizer.has_unconstrained_ty_var; + Ok(Generalization { value_may_be_infer, has_unconstrained_ty_var }) } /// Abstracts the handling of region vars between HIR and MIR/NLL typechecking @@ -150,8 +150,8 @@ struct Generalizer<'me, 'tcx, D> { /// hold by either normalizing the outer or the inner associated type. in_alias: bool, - /// See the field `needs_wf` in `Generalization`. - needs_wf: bool, + /// See the field `has_unconstrained_ty_var` in `Generalization`. + has_unconstrained_ty_var: bool, } impl<'tcx, D> Generalizer<'_, 'tcx, D> { @@ -272,11 +272,10 @@ where } } - // Bivariant: make a fresh var, but we - // may need a WF predicate. See - // comment on `needs_wf` field for - // more info. - ty::Bivariant => self.needs_wf = true, + // Bivariant: make a fresh var, but remember that + // it is unconstrained. See the comment in + // `Generalization`. + ty::Bivariant => self.has_unconstrained_ty_var = true, // Co/contravariant: this will be // sufficiently constrained later on. @@ -511,30 +510,27 @@ pub struct Generalization { /// recursion. pub value_may_be_infer: T, - /// If true, then the generalized type may not be well-formed, - /// even if the source type is well-formed, so we should add an - /// additional check to enforce that it is. This arises in - /// particular around 'bivariant' type parameters that are only - /// constrained by a where-clause. As an example, imagine a type: + /// In general, we do not check whether all types which occur during + /// type checking are well-formed. We only check wf of user-provided types + /// and when actually using a type, e.g. for method calls. + /// + /// This means that when subtyping, we may end up with unconstrained + /// inference variables if a generalized type has bivariant parameters. + /// A parameter may only be bivariant if it is constrained by a projection + /// bound in a where-clause. As an example, imagine a type: /// /// struct Foo where A: Iterator { /// data: A /// } /// - /// here, `A` will be covariant, but `B` is - /// unconstrained. However, whatever it is, for `Foo` to be WF, it - /// must be equal to `A::Item`. If we have an input `Foo`, - /// then after generalization we will wind up with a type like - /// `Foo`. When we enforce that `Foo <: Foo` (or `>:`), we will wind up with the requirement that `?A - /// <: ?C`, but no particular relationship between `?B` and `?D` - /// (after all, we do not know the variance of the normalized form - /// of `A::Item` with respect to `A`). If we do nothing else, this - /// may mean that `?D` goes unconstrained (as in #41677). So, in - /// this scenario where we create a new type variable in a - /// bivariant context, we set the `needs_wf` flag to true. This - /// will force the calling code to check that `WF(Foo)` - /// holds, which in turn implies that `?C::Item == ?D`. So once - /// `?C` is constrained, that should suffice to restrict `?D`. - pub needs_wf: bool, + /// here, `A` will be covariant, but `B` is unconstrained. + /// + /// However, whatever it is, for `Foo` to be WF, it must be equal to `A::Item`. + /// If we have an input `Foo`, then after generalization we will wind + /// up with a type like `Foo`. When we enforce `Foo <: Foo`, + /// we will wind up with the requirement that `?A <: ?C`, but no particular + /// relationship between `?B` and `?D` (after all, these types may be completely + /// different). If we do nothing else, this may mean that `?D` goes unconstrained + /// (as in #41677). To avoid this we emit a `WellFormed` obligation in these cases. + pub has_unconstrained_ty_var: bool, } diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs index 5e2d2af9b85..fac597c9432 100644 --- a/compiler/rustc_infer/src/infer/relate/nll.rs +++ b/compiler/rustc_infer/src/infer/relate/nll.rs @@ -214,13 +214,14 @@ where } fn generalize(&mut self, ty: Ty<'tcx>, for_vid: ty::TyVid) -> RelateResult<'tcx, Ty<'tcx>> { - let Generalization { value_may_be_infer: ty, needs_wf: _ } = generalize::generalize( - self.infcx, - &mut self.delegate, - ty, - for_vid, - self.ambient_variance, - )?; + let Generalization { value_may_be_infer: ty, has_unconstrained_ty_var: _ } = + generalize::generalize( + self.infcx, + &mut self.delegate, + ty, + for_vid, + self.ambient_variance, + )?; if ty.is_ty_var() { span_bug!(self.delegate.span(), "occurs check failure in MIR typeck"); -- cgit 1.4.1-3-g733a5 From f65e7437488ef099fe55c267afca5f4e823362e7 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 17 Feb 2024 00:26:57 +0100 Subject: add fixme --- compiler/rustc_infer/src/infer/relate/generalize.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'compiler') diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 52d2661bdaf..6a96afe7083 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -451,6 +451,9 @@ where } } ty::ConstKind::Infer(InferConst::EffectVar(_)) => Ok(c), + // FIXME: Unevaluated constants are also not rigid, so the current + // approach of always relating them structurally is incomplete. + // // FIXME: remove this branch once `structurally_relate_consts` is fully // structural. ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { -- cgit 1.4.1-3-g733a5 From 88a559fa9fd5d0ec24e4a28c31eb53659ca493a7 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 17 Feb 2024 01:42:36 +0100 Subject: move ty var instantiation into the generalize module --- compiler/rustc_infer/src/infer/relate/combine.rs | 204 +-------------------- compiler/rustc_infer/src/infer/relate/equate.rs | 13 +- .../rustc_infer/src/infer/relate/generalize.rs | 200 +++++++++++++++++++- compiler/rustc_infer/src/infer/relate/glb.rs | 5 + compiler/rustc_infer/src/infer/relate/lub.rs | 5 + compiler/rustc_infer/src/infer/relate/nll.rs | 4 + compiler/rustc_infer/src/infer/relate/sub.rs | 13 +- .../occurs-check/associated-type.next.stderr | 8 +- .../occurs-check/associated-type.old.stderr | 8 +- .../occurs-check-nested-alias.next.stderr | 4 +- 10 files changed, 243 insertions(+), 221 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 2e856f6a145..454de4f9785 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -23,19 +23,18 @@ //! this should be correctly updated. use super::equate::Equate; -use super::generalize::{self, CombineDelegate, Generalization}; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_middle::infer::canonical::OriginalQueryValues; -use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue}; +use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{RelateResult, TypeRelation}; use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::ty::{AliasRelationDirection, TyVar}; use rustc_middle::ty::{IntType, UintType}; +use rustc_span::Span; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -221,11 +220,11 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(vid, b); + return self.instantiate_const_var(vid, b); } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(vid, a); + return self.instantiate_const_var(vid, a); } (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => { @@ -259,73 +258,6 @@ impl<'tcx> InferCtxt<'tcx> { ty::relate::structurally_relate_consts(relation, a, b) } - /// Unifies the const variable `target_vid` with the given constant. - /// - /// This also tests if the given const `ct` contains an inference variable which was previously - /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct` - /// would result in an infinite type as we continuously replace an inference variable - /// in `ct` with `ct` itself. - /// - /// This is especially important as unevaluated consts use their parents generics. - /// They therefore often contain unused args, making these errors far more likely. - /// - /// A good example of this is the following: - /// - /// ```compile_fail,E0308 - /// #![feature(generic_const_exprs)] - /// - /// fn bind(value: [u8; N]) -> [u8; 3 + 4] { - /// todo!() - /// } - /// - /// fn main() { - /// let mut arr = Default::default(); - /// arr = bind(arr); - /// } - /// ``` - /// - /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics - /// of `fn bind` (meaning that its args contain `N`). - /// - /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`. - /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`. - /// - /// As `3 + 4` contains `N` in its args, this must not succeed. - /// - /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. - #[instrument(level = "debug", skip(self))] - fn unify_const_variable( - &self, - target_vid: ty::ConstVid, - ct: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) { - ConstVariableValue::Known { value } => { - bug!("instantiating a known const var: {target_vid:?} {value} {ct}") - } - ConstVariableValue::Unknown { origin, universe: _ } => origin.span, - }; - // FIXME(generic_const_exprs): Occurs check failures for unevaluated - // constants and generic expressions are not yet handled correctly. - let Generalization { value_may_be_infer: value, has_unconstrained_ty_var } = - generalize::generalize( - self, - &mut CombineDelegate { infcx: self, span }, - ct, - target_vid, - ty::Variance::Invariant, - )?; - - if has_unconstrained_ty_var { - span_bug!(span, "unconstrained ty var when generalizing `{ct:?}`"); - } - self.inner - .borrow_mut() - .const_unification_table() - .union_value(target_vid, ConstVariableValue::Known { value }); - Ok(value) - } - fn unify_integral_variable( &self, vid_is_expected: bool, @@ -387,132 +319,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { Glb::new(self, a_is_expected) } - /// Here, `dir` is either `EqTo`, `SubtypeOf`, or `SupertypeOf`. - /// The idea is that we should ensure that the type `a_ty` is equal - /// to, a subtype of, or a supertype of (respectively) the type - /// to which `b_vid` is bound. - /// - /// Since `b_vid` has not yet been instantiated with a type, we - /// will first instantiate `b_vid` with a *generalized* version - /// of `a_ty`. Generalization introduces other inference - /// variables wherever subtyping could occur. - #[instrument(skip(self), level = "debug")] - pub fn instantiate( - &mut self, - a_ty: Ty<'tcx>, - ambient_variance: ty::Variance, - b_vid: ty::TyVid, - a_is_expected: bool, - ) -> RelateResult<'tcx, ()> { - // Get the actual variable that b_vid has been inferred to - debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown()); - - // Generalize type of `a_ty` appropriately depending on the - // direction. As an example, assume: - // - // - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an - // inference variable, - // - and `dir` == `SubtypeOf`. - // - // Then the generalized form `b_ty` would be `&'?2 ?3`, where - // `'?2` and `?3` are fresh region/type inference - // variables. (Down below, we will relate `a_ty <: b_ty`, - // adding constraints like `'x: '?2` and `?1 <: ?3`.) - let Generalization { value_may_be_infer: b_ty, has_unconstrained_ty_var } = - generalize::generalize( - self.infcx, - &mut CombineDelegate { infcx: self.infcx, span: self.trace.span() }, - a_ty, - b_vid, - ambient_variance, - )?; - - // Constrain `b_vid` to the generalized type `b_ty`. - if let &ty::Infer(TyVar(b_ty_vid)) = b_ty.kind() { - self.infcx.inner.borrow_mut().type_variables().equate(b_vid, b_ty_vid); - } else { - self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty); - } - - if has_unconstrained_ty_var { - self.obligations.push(Obligation::new( - self.tcx(), - self.trace.cause.clone(), - self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( - b_ty.into(), - ))), - )); - } - - // Finally, relate `b_ty` to `a_ty`, as described in previous comment. - // - // FIXME(#16847): This code is non-ideal because all these subtype - // relations wind up attributed to the same spans. We need - // to associate causes/spans with each of the relations in - // the stack to get this right. - if b_ty.is_ty_var() { - // This happens for cases like `::Assoc == ?0`. - // We can't instantiate `?0` here as that would result in a - // cyclic type. We instead delay the unification in case - // the alias can be normalized to something which does not - // mention `?0`. - if self.infcx.next_trait_solver() { - let (lhs, rhs, direction) = match ambient_variance { - ty::Variance::Invariant => { - (a_ty.into(), b_ty.into(), AliasRelationDirection::Equate) - } - ty::Variance::Covariant => { - (a_ty.into(), b_ty.into(), AliasRelationDirection::Subtype) - } - ty::Variance::Contravariant => { - (b_ty.into(), a_ty.into(), AliasRelationDirection::Subtype) - } - ty::Variance::Bivariant => unreachable!("bivariant generalization"), - }; - self.obligations.push(Obligation::new( - self.tcx(), - self.trace.cause.clone(), - self.param_env, - ty::PredicateKind::AliasRelate(lhs, rhs, direction), - )); - } else { - match a_ty.kind() { - &ty::Alias(ty::Projection, data) => { - // FIXME: This does not handle subtyping correctly, we could - // instead create a new inference variable for `a_ty`, emitting - // `Projection(a_ty, a_infer)` and `a_infer <: b_ty`. - self.obligations.push(Obligation::new( - self.tcx(), - self.trace.cause.clone(), - self.param_env, - ty::ProjectionPredicate { projection_ty: data, term: b_ty.into() }, - )) - } - // The old solver only accepts projection predicates for associated types. - ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => { - return Err(TypeError::CyclicTy(a_ty)); - } - _ => bug!("generalizated `{a_ty:?} to infer, not an alias"), - } - } - } else { - match ambient_variance { - ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty), - ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty), - ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance( - ty::Contravariant, - ty::VarianceDiagInfo::default(), - a_ty, - b_ty, - ), - ty::Variance::Bivariant => unreachable!("bivariant generalization"), - }?; - } - - Ok(()) - } - pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.obligations.extend(obligations); } @@ -525,6 +331,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { } pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { + fn span(&self) -> Span; + fn param_env(&self) -> ty::ParamEnv<'tcx>; /// Register obligations that must hold in order for this relation to hold diff --git a/compiler/rustc_infer/src/infer/relate/equate.rs b/compiler/rustc_infer/src/infer/relate/equate.rs index cb62f258373..0087add4c72 100644 --- a/compiler/rustc_infer/src/infer/relate/equate.rs +++ b/compiler/rustc_infer/src/infer/relate/equate.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_hir::def_id::DefId; +use rustc_span::Span; /// Ensures `a` is made equal to `b`. Returns `a` on success. pub struct Equate<'combine, 'infcx, 'tcx> { @@ -81,12 +82,12 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { infcx.inner.borrow_mut().type_variables().equate(a_id, b_id); } - (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, ty::Invariant, a_id, self.a_is_expected)?; + (&ty::Infer(TyVar(a_vid)), _) => { + infcx.instantiate_ty_var(self, self.a_is_expected, a_vid, ty::Invariant, b)?; } - (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, ty::Invariant, b_id, self.a_is_expected)?; + (_, &ty::Infer(TyVar(b_vid))) => { + infcx.instantiate_ty_var(self, !self.a_is_expected, b_vid, ty::Invariant, a)?; } ( @@ -170,6 +171,10 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { } impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.fields.trace.span() + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 6a96afe7083..47045058290 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -1,5 +1,8 @@ use std::mem; +use crate::infer::nll_relate::TypeRelatingDelegate; +use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind, TypeVariableValue}; +use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; @@ -7,17 +10,204 @@ use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::MaxUniverse; -use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{AliasRelationDirection, InferConst, Term, TypeVisitable, TypeVisitableExt}; use rustc_span::Span; -use crate::infer::nll_relate::TypeRelatingDelegate; -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind, TypeVariableValue}; -use crate::infer::{InferCtxt, RegionVariableOrigin}; +impl<'tcx> InferCtxt<'tcx> { + /// The idea is that we should ensure that the type variable `target_vid` + /// is equal to, a subtype of, or a supertype of `source_ty`. + /// + /// For this, we will instantiate `target_vid` with a *generalized* version + /// of `source_ty`. Generalization introduces other inference variables wherever + /// subtyping could occur. This also does the occurs checks, detecting whether + /// instantiating `target_vid` would result in a cyclic type. We eagerly error + /// in this case. + #[instrument(skip(self, relation, target_is_expected), level = "debug")] + pub(super) fn instantiate_ty_var>( + &self, + relation: &mut R, + target_is_expected: bool, + target_vid: ty::TyVid, + ambient_variance: ty::Variance, + source_ty: Ty<'tcx>, + ) -> RelateResult<'tcx, ()> { + debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()); + + // Generalize `source_ty` depending on the current variance. As an example, assume + // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference + // variable. + // + // 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`. + let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = + generalize( + self, + &mut CombineDelegate { infcx: self, span: relation.span() }, + source_ty, + target_vid, + ambient_variance, + )?; + + // Constrain `b_vid` to the generalized type `generalized_ty`. + if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() { + self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid); + } else { + self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty); + } + + // See the comment on `Generalization::has_unconstrained_ty_var`. + if has_unconstrained_ty_var { + relation.register_predicates([ty::ClauseKind::WellFormed(generalized_ty.into())]); + } + + // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment. + // + // FIXME(#16847): This code is non-ideal because all these subtype + // relations wind up attributed to the same spans. We need + // to associate causes/spans with each of the relations in + // the stack to get this right. + if generalized_ty.is_ty_var() { + // This happens for cases like `::Assoc == ?0`. + // We can't instantiate `?0` here as that would result in a + // cyclic type. We instead delay the unification in case + // the alias can be normalized to something which does not + // mention `?0`. + if self.next_trait_solver() { + let (lhs, rhs, direction) = match ambient_variance { + ty::Variance::Invariant => { + (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Equate) + } + ty::Variance::Covariant => { + (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Subtype) + } + ty::Variance::Contravariant => { + (source_ty.into(), generalized_ty.into(), AliasRelationDirection::Subtype) + } + ty::Variance::Bivariant => unreachable!("bivariant generalization"), + }; + + relation.register_predicates([ty::PredicateKind::AliasRelate(lhs, rhs, direction)]); + } else { + match source_ty.kind() { + &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`. + relation.register_predicates([ty::ProjectionPredicate { + projection_ty: data, + term: generalized_ty.into(), + }]); + } + // The old solver only accepts projection predicates for associated types. + ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => { + return Err(TypeError::CyclicTy(source_ty)); + } + _ => bug!("generalized `{source_ty:?} to infer, not an alias"), + } + } + } else { + // HACK: make sure that we `a_is_expected` continues to be + // correct when relating the generalized type with the source. + if target_is_expected == relation.a_is_expected() { + relation.relate_with_variance( + ambient_variance, + ty::VarianceDiagInfo::default(), + generalized_ty, + source_ty, + )?; + } else { + relation.relate_with_variance( + ambient_variance.xform(ty::Contravariant), + ty::VarianceDiagInfo::default(), + source_ty, + generalized_ty, + )?; + } + } + + Ok(()) + } + + /// Instantiates the const variable `target_vid` with the given constant. + /// + /// This also tests if the given const `ct` contains an inference variable which was previously + /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct` + /// would result in an infinite type as we continuously replace an inference variable + /// in `ct` with `ct` itself. + /// + /// This is especially important as unevaluated consts use their parents generics. + /// They therefore often contain unused args, making these errors far more likely. + /// + /// A good example of this is the following: + /// + /// ```compile_fail,E0308 + /// #![feature(generic_const_exprs)] + /// + /// fn bind(value: [u8; N]) -> [u8; 3 + 4] { + /// todo!() + /// } + /// + /// fn main() { + /// let mut arr = Default::default(); + /// arr = bind(arr); + /// } + /// ``` + /// + /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics + /// of `fn bind` (meaning that its args contain `N`). + /// + /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`. + /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`. + /// + /// As `3 + 4` contains `N` in its args, this must not succeed. + /// + /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. + #[instrument(level = "debug", skip(self))] + pub(super) fn instantiate_const_var( + &self, + target_vid: ty::ConstVid, + source_ct: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) { + ConstVariableValue::Known { value } => { + bug!("instantiating a known const var: {target_vid:?} {value} {source_ct}") + } + ConstVariableValue::Unknown { origin, universe: _ } => origin.span, + }; + // FIXME(generic_const_exprs): Occurs check failures for unevaluated + // constants and generic expressions are not yet handled correctly. + let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = + generalize( + self, + &mut CombineDelegate { infcx: self, span }, + source_ct, + target_vid, + ty::Variance::Invariant, + )?; + + debug_assert!(!generalized_ct.is_ct_infer()); + if has_unconstrained_ty_var { + span_bug!(span, "unconstrained ty var when generalizing `{source_ct:?}`"); + } + + self.inner + .borrow_mut() + .const_unification_table() + .union_value(target_vid, ConstVariableValue::Known { value: generalized_ct }); + + // FIXME(generic_const_exprs): We have to make sure we actually equate + // `generalized_ct` and `source_ct` here.` + Ok(generalized_ct) + } +} /// Attempts to generalize `term` for the type variable `for_vid`. /// This checks for cycles -- that is, whether the type `term` /// references `for_vid`. -pub fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into> + Relate<'tcx>>( +pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into> + Relate<'tcx>>( infcx: &InferCtxt<'tcx>, delegate: &mut D, term: T, diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index aa89124301e..6cf51354599 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -2,6 +2,7 @@ use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; use super::combine::{CombineFields, ObligationEmittingRelation}; use super::lattice::{self, LatticeDir}; @@ -134,6 +135,10 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, } impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.fields.trace.span() + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 87d777530c8..5b4f80fd73a 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -7,6 +7,7 @@ use crate::traits::{ObligationCause, PredicateObligations}; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; /// "Least upper bound" (common supertype) pub struct Lub<'combine, 'infcx, 'tcx> { @@ -134,6 +135,10 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, } impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.fields.trace.span() + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs index fac597c9432..04995f1a117 100644 --- a/compiler/rustc_infer/src/infer/relate/nll.rs +++ b/compiler/rustc_infer/src/infer/relate/nll.rs @@ -670,6 +670,10 @@ impl<'tcx, D> ObligationEmittingRelation<'tcx> for TypeRelating<'_, 'tcx, D> where D: TypeRelatingDelegate<'tcx>, { + fn span(&self) -> Span { + self.delegate.span() + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.delegate.param_env() } diff --git a/compiler/rustc_infer/src/infer/relate/sub.rs b/compiler/rustc_infer/src/infer/relate/sub.rs index 36876acd7c0..5bd3a238a67 100644 --- a/compiler/rustc_infer/src/infer/relate/sub.rs +++ b/compiler/rustc_infer/src/infer/relate/sub.rs @@ -6,6 +6,7 @@ use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::Span; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. @@ -103,12 +104,12 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { Ok(a) } - (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, ty::Contravariant, a_id, !self.a_is_expected)?; + (&ty::Infer(TyVar(a_vid)), _) => { + infcx.instantiate_ty_var(self, self.a_is_expected, a_vid, ty::Covariant, b)?; Ok(a) } - (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, ty::Covariant, b_id, self.a_is_expected)?; + (_, &ty::Infer(TyVar(b_vid))) => { + infcx.instantiate_ty_var(self, !self.a_is_expected, b_vid, ty::Contravariant, a)?; Ok(a) } @@ -199,6 +200,10 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { } impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.fields.trace.span() + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index 65be4a9c884..e405f389f5e 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -1,11 +1,11 @@ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index 8e852ec796e..4a67a777f10 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -1,11 +1,11 @@ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr index aaadf604a80..cde925db184 100644 --- a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr +++ b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `<>::Id as Unnormalizable>::Assoc == _` +error[E0284]: type annotations needed: cannot satisfy `_ == <>::Id as Unnormalizable>::Assoc` --> $DIR/occurs-check-nested-alias.rs:36:9 | LL | x = y; - | ^ cannot satisfy `<>::Id as Unnormalizable>::Assoc == _` + | ^ cannot satisfy `_ == <>::Id as Unnormalizable>::Assoc` error: aborting due to 1 previous error -- cgit 1.4.1-3-g733a5 From 5c540044d6020c8e5008d48d7a8736d370d3a549 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 17 Feb 2024 02:32:19 +0100 Subject: use `instantiate_ty_var` in nll we already use `instantiate_const_var`. This does lose some debugging info for nll because we stop populating the `reg_var_to_origin` table with `RegionCtxt::Existential(None)`, I don't think that matters however. Supporting this adds additional complexity to one of the most involved parts of the type system, so I really don't think it's worth it. --- .../rustc_borrowck/src/type_check/relate_tys.rs | 16 -- .../src/infer/canonical/query_response.rs | 7 - compiler/rustc_infer/src/infer/relate/mod.rs | 2 +- compiler/rustc_infer/src/infer/relate/nll.rs | 230 +++++---------------- tests/ui/impl-trait/rpit/early_bound.rs | 1 - tests/ui/impl-trait/rpit/early_bound.stderr | 14 +- 6 files changed, 48 insertions(+), 222 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index ee0bd13109b..a60175d9896 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -143,22 +143,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> reg } - #[instrument(skip(self), level = "debug")] - fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - let reg = self.type_checker.infcx.next_nll_region_var_in_universe( - NllRegionVariableOrigin::Existential { from_forall: false }, - universe, - ); - - if cfg!(debug_assertions) { - let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); - let prev = var_to_origin.insert(reg.as_var(), RegionCtxt::Existential(None)); - assert_eq!(prev, None); - } - - reg - } - fn push_outlives( &mut self, sup: ty::Region<'tcx>, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 56a45586c9d..4539ebf8754 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -731,13 +731,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { ty::Region::new_placeholder(self.infcx.tcx, placeholder) } - fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - self.infcx.next_nll_region_var_in_universe( - NllRegionVariableOrigin::Existential { from_forall: false }, - universe, - ) - } - fn push_outlives( &mut self, sup: ty::Region<'tcx>, diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index f688c2b74a6..26270c77f1a 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -3,7 +3,7 @@ pub(super) mod combine; mod equate; -pub(super) mod generalize; +mod generalize; mod glb; mod higher_ranked; mod lattice; diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs index 04995f1a117..4ba4bd38e9f 100644 --- a/compiler/rustc_infer/src/infer/relate/nll.rs +++ b/compiler/rustc_infer/src/infer/relate/nll.rs @@ -25,13 +25,11 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::visit::TypeVisitableExt; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use rustc_span::{Span, Symbol}; -use std::fmt::Debug; use super::combine::ObligationEmittingRelation; -use super::generalize::{self, Generalization}; use crate::infer::InferCtxt; use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::traits::{Obligation, PredicateObligations}; @@ -99,15 +97,6 @@ pub trait TypeRelatingDelegate<'tcx> { /// placeholder region. fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx>; - /// Creates a new existential region in the given universe. This - /// is used when handling subtyping and type variables -- if we - /// have that `?X <: Foo<'a>`, for example, we would instantiate - /// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh - /// existential variable created by this function. We would then - /// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives - /// relation stating that `'?0: 'a`). - fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; - /// Enables some optimizations if we do not expect inference variables /// in the RHS of the relation. fn forbid_inference_vars() -> bool; @@ -153,113 +142,44 @@ where self.delegate.push_outlives(sup, sub, info); } - /// Relate a type inference variable with a value type. This works - /// by creating a "generalization" G of the value where all the - /// lifetimes are replaced with fresh inference values. This - /// generalization G becomes the value of the inference variable, - /// and is then related in turn to the value. So e.g. if you had - /// `vid = ?0` and `value = &'a u32`, we might first instantiate - /// `?0` to a type like `&'0 u32` where `'0` is a fresh variable, - /// and then relate `&'0 u32` with `&'a u32` (resulting in - /// relations between `'0` and `'a`). - /// - /// The variable `pair` can be either a `(vid, ty)` or `(ty, vid)` - /// -- in other words, it is always an (unresolved) inference - /// variable `vid` and a type `ty` that are being related, but the - /// vid may appear either as the "a" type or the "b" type, - /// depending on where it appears in the tuple. The trait - /// `VidValuePair` lets us work with the vid/type while preserving - /// the "sidedness" when necessary -- the sidedness is relevant in - /// particular for the variance and set of in-scope things. - fn relate_ty_var>( - &mut self, - pair: PAIR, - ) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("relate_ty_var({:?})", pair); - - let vid = pair.vid(); - let value_ty = pair.value_ty(); - - // FIXME(invariance) -- this logic assumes invariance, but that is wrong. - // This only presently applies to chalk integration, as NLL - // doesn't permit type variables to appear on both sides (and - // doesn't use lazy norm). - match *value_ty.kind() { - ty::Infer(ty::TyVar(value_vid)) => { - // Two type variables: just equate them. - self.infcx.inner.borrow_mut().type_variables().equate(vid, value_vid); - return Ok(value_ty); - } - - _ => (), - } - - let generalized_ty = self.generalize(value_ty, vid)?; - debug!("relate_ty_var: generalized_ty = {:?}", generalized_ty); - - if D::forbid_inference_vars() { - // In NLL, we don't have type inference variables - // floating around, so we can do this rather imprecise - // variant of the occurs-check. - assert!(!generalized_ty.has_non_region_infer()); - } - - self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty); - - // Relate the generalized kind to the original one. - let result = pair.relate_generalized_ty(self, generalized_ty); - - debug!("relate_ty_var: complete, result = {:?}", result); - result - } - - fn generalize(&mut self, ty: Ty<'tcx>, for_vid: ty::TyVid) -> RelateResult<'tcx, Ty<'tcx>> { - let Generalization { value_may_be_infer: ty, has_unconstrained_ty_var: _ } = - generalize::generalize( - self.infcx, - &mut self.delegate, - ty, - for_vid, - self.ambient_variance, - )?; - - if ty.is_ty_var() { - span_bug!(self.delegate.span(), "occurs check failure in MIR typeck"); - } - Ok(ty) - } - - fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let infcx = self.infcx; + debug_assert!(!infcx.next_trait_solver()); let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; - let mut generalize = |ty, ty_is_expected| { - let var = self.infcx.next_ty_var_id_in_universe( + // `handle_opaque_type` cannot handle subtyping, so to support subtyping + // we instead eagerly generalize here. This is a bit of a mess but will go + // away once we're using the new solver. + let mut enable_subtyping = |ty, ty_is_expected| { + let ty_vid = infcx.next_ty_var_id_in_universe( TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: self.delegate.span(), }, ty::UniverseIndex::ROOT, ); - if ty_is_expected { - self.relate_ty_var((ty, var)) + + let variance = if ty_is_expected { + self.ambient_variance } else { - self.relate_ty_var((var, ty)) - } + self.ambient_variance.xform(ty::Contravariant) + }; + + self.infcx.instantiate_ty_var(self, ty_is_expected, ty_vid, variance, ty)?; + Ok(infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid)))) }; + let (a, b) = match (a.kind(), b.kind()) { - (&ty::Alias(ty::Opaque, ..), _) => (a, generalize(b, false)?), - (_, &ty::Alias(ty::Opaque, ..)) => (generalize(a, true)?, b), + (&ty::Alias(ty::Opaque, ..), _) => (a, enable_subtyping(b, false)?), + (_, &ty::Alias(ty::Opaque, ..)) => (enable_subtyping(a, true)?, b), _ => unreachable!( "expected at least one opaque type in `relate_opaques`, got {a} and {b}." ), }; let cause = ObligationCause::dummy_with_span(self.delegate.span()); - let obligations = self - .infcx - .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())? - .obligations; + let obligations = + infcx.handle_opaque_type(a, b, true, &cause, self.delegate.param_env())?.obligations; self.delegate.register_obligations(obligations); - trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); - Ok(a) + Ok(()) } fn enter_forall( @@ -357,76 +277,6 @@ where } } -/// When we instantiate an inference variable with a value in -/// `relate_ty_var`, we always have the pair of a `TyVid` and a `Ty`, -/// but the ordering may vary (depending on whether the inference -/// variable was found on the `a` or `b` sides). Therefore, this trait -/// allows us to factor out common code, while preserving the order -/// when needed. -trait VidValuePair<'tcx>: Debug { - /// Extract the inference variable (which could be either the - /// first or second part of the tuple). - fn vid(&self) -> ty::TyVid; - - /// Extract the value it is being related to (which will be the - /// opposite part of the tuple from the vid). - fn value_ty(&self) -> Ty<'tcx>; - - /// Given a generalized type G that should replace the vid, relate - /// G to the value, putting G on whichever side the vid would have - /// appeared. - fn relate_generalized_ty( - &self, - relate: &mut TypeRelating<'_, 'tcx, D>, - generalized_ty: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - D: TypeRelatingDelegate<'tcx>; -} - -impl<'tcx> VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) { - fn vid(&self) -> ty::TyVid { - self.0 - } - - fn value_ty(&self) -> Ty<'tcx> { - self.1 - } - - fn relate_generalized_ty( - &self, - relate: &mut TypeRelating<'_, 'tcx, D>, - generalized_ty: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - relate.relate(generalized_ty, self.value_ty()) - } -} - -// In this case, the "vid" is the "b" type. -impl<'tcx> VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) { - fn vid(&self) -> ty::TyVid { - self.1 - } - - fn value_ty(&self) -> Ty<'tcx> { - self.0 - } - - fn relate_generalized_ty( - &self, - relate: &mut TypeRelating<'_, 'tcx, D>, - generalized_ty: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - relate.relate(self.value_ty(), generalized_ty) - } -} - impl<'tcx, D> TypeRelation<'tcx> for TypeRelating<'_, 'tcx, D> where D: TypeRelatingDelegate<'tcx>, @@ -473,6 +323,8 @@ where if !D::forbid_inference_vars() { b = self.infcx.shallow_resolve(b); + } else { + assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); } if a == b { @@ -480,22 +332,30 @@ where } match (a.kind(), b.kind()) { - (_, &ty::Infer(ty::TyVar(vid))) => { - if D::forbid_inference_vars() { - // Forbid inference variables in the RHS. - bug!("unexpected inference var {:?}", b) - } else { - self.relate_ty_var((a, vid)) + (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { + match self.ambient_variance { + ty::Invariant => infcx.inner.borrow_mut().type_variables().equate(a_vid, b_vid), + _ => unimplemented!(), } } - (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)), + (&ty::Infer(ty::TyVar(a_vid)), _) => { + infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)? + } + + (_, &ty::Infer(ty::TyVar(b_vid))) => infcx.instantiate_ty_var( + self, + false, + b_vid, + self.ambient_variance.xform(ty::Contravariant), + a, + )?, ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), ) if a_def_id == b_def_id || infcx.next_trait_solver() => { - infcx.super_combine_tys(self, a, b).or_else(|err| { + infcx.super_combine_tys(self, a, b).map(|_| ()).or_else(|err| { // This behavior is only there for the old solver, the new solver // shouldn't ever fail. Instead, it unconditionally emits an // alias-relate goal. @@ -505,22 +365,24 @@ where "failure to relate an opaque to itself should result in an error later on", ); if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } - }) + })?; } (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) if def_id.is_local() && !self.infcx.next_trait_solver() => { - self.relate_opaques(a, b) + self.relate_opaques(a, b)?; } _ => { debug!(?a, ?b, ?self.ambient_variance); // Will also handle unification of `IntVar` and `FloatVar`. - self.infcx.super_combine_tys(self, a, b) + self.infcx.super_combine_tys(self, a, b)?; } } + + Ok(a) } #[instrument(skip(self), level = "trace")] diff --git a/tests/ui/impl-trait/rpit/early_bound.rs b/tests/ui/impl-trait/rpit/early_bound.rs index 03bd64d4d76..6dda687929c 100644 --- a/tests/ui/impl-trait/rpit/early_bound.rs +++ b/tests/ui/impl-trait/rpit/early_bound.rs @@ -5,7 +5,6 @@ fn test<'a: 'a>(n: bool) -> impl Sized + 'a { let true = n else { loop {} }; let _ = || { let _ = identity::<&'a ()>(test(false)); - //~^ ERROR hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds }; loop {} } diff --git a/tests/ui/impl-trait/rpit/early_bound.stderr b/tests/ui/impl-trait/rpit/early_bound.stderr index 815368f250e..780dea4e284 100644 --- a/tests/ui/impl-trait/rpit/early_bound.stderr +++ b/tests/ui/impl-trait/rpit/early_bound.stderr @@ -1,14 +1,3 @@ -error[E0700]: hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds - --> $DIR/early_bound.rs:7:17 - | -LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a { - | -- --------------- opaque type defined here - | | - | hidden type `&'a ()` captures the lifetime `'a` as defined here -... -LL | let _ = identity::<&'a ()>(test(false)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: concrete type differs from previous defining opaque type use --> $DIR/early_bound.rs:3:29 | @@ -21,6 +10,5 @@ note: previous use here LL | let _ = identity::<&'a ()>(test(false)); | ^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0700`. -- cgit 1.4.1-3-g733a5 From 54b3c8759ad875be52d62c388c3766aaed0e4c64 Mon Sep 17 00:00:00 2001 From: lcnr Date: Sat, 17 Feb 2024 02:32:53 +0100 Subject: yeet `GeneralizerDelegate` --- .../rustc_infer/src/infer/relate/generalize.rs | 178 ++++++--------------- 1 file changed, 52 insertions(+), 126 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 47045058290..c0cb02916fe 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -1,6 +1,5 @@ use std::mem; -use crate::infer::nll_relate::TypeRelatingDelegate; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind, TypeVariableValue}; use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin}; use rustc_data_structures::sso::SsoHashMap; @@ -43,13 +42,7 @@ impl<'tcx> InferCtxt<'tcx> { // // 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 } = - generalize( - self, - &mut CombineDelegate { infcx: self, span: relation.span() }, - source_ty, - target_vid, - ambient_variance, - )?; + self.generalize(relation.span(), target_vid, ambient_variance, source_ty)?; // Constrain `b_vid` to the generalized type `generalized_ty`. if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() { @@ -180,13 +173,7 @@ impl<'tcx> InferCtxt<'tcx> { // FIXME(generic_const_exprs): Occurs check failures for unevaluated // constants and generic expressions are not yet handled correctly. let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = - generalize( - self, - &mut CombineDelegate { infcx: self, span }, - source_ct, - target_vid, - ty::Variance::Invariant, - )?; + self.generalize(span, target_vid, ty::Variance::Invariant, source_ct)?; debug_assert!(!generalized_ct.is_ct_infer()); if has_unconstrained_ty_var { @@ -199,96 +186,48 @@ impl<'tcx> InferCtxt<'tcx> { .union_value(target_vid, ConstVariableValue::Known { value: generalized_ct }); // FIXME(generic_const_exprs): We have to make sure we actually equate - // `generalized_ct` and `source_ct` here.` + // `generalized_ct` and `source_ct` here. Ok(generalized_ct) } -} - -/// Attempts to generalize `term` for the type variable `for_vid`. -/// This checks for cycles -- that is, whether the type `term` -/// references `for_vid`. -pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into> + Relate<'tcx>>( - infcx: &InferCtxt<'tcx>, - delegate: &mut D, - term: T, - for_vid: impl Into, - ambient_variance: ty::Variance, -) -> RelateResult<'tcx, Generalization> { - let (for_universe, root_vid) = match for_vid.into() { - ty::TermVid::Ty(ty_vid) => ( - infcx.probe_ty_var(ty_vid).unwrap_err(), - ty::TermVid::Ty(infcx.inner.borrow_mut().type_variables().sub_root_var(ty_vid)), - ), - ty::TermVid::Const(ct_vid) => ( - infcx.probe_const_var(ct_vid).unwrap_err(), - ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid).vid), - ), - }; - - let mut generalizer = Generalizer { - infcx, - delegate, - ambient_variance, - root_vid, - for_universe, - root_term: term.into(), - in_alias: false, - has_unconstrained_ty_var: false, - cache: Default::default(), - }; - - assert!(!term.has_escaping_bound_vars()); - let value_may_be_infer = generalizer.relate(term, term)?; - let has_unconstrained_ty_var = generalizer.has_unconstrained_ty_var; - Ok(Generalization { value_may_be_infer, has_unconstrained_ty_var }) -} - -/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking -/// in the generalizer code. -pub trait GeneralizerDelegate<'tcx> { - fn forbid_inference_vars() -> bool; - - fn span(&self) -> Span; - - fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; -} - -pub struct CombineDelegate<'cx, 'tcx> { - pub infcx: &'cx InferCtxt<'tcx>, - pub span: Span, -} - -impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> { - fn forbid_inference_vars() -> bool { - false - } - - fn span(&self) -> Span { - self.span - } - - fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - self.infcx - .next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe) - } -} -impl<'tcx, T> GeneralizerDelegate<'tcx> for T -where - T: TypeRelatingDelegate<'tcx>, -{ - fn forbid_inference_vars() -> bool { - >::forbid_inference_vars() - } + /// Attempts to generalize `source_term` for the type variable `target_vid`. + /// This checks for cycles -- that is, whether `source_term` references `target_vid`. + fn generalize> + Relate<'tcx>>( + &self, + span: Span, + target_vid: impl Into, + ambient_variance: ty::Variance, + source_term: T, + ) -> RelateResult<'tcx, Generalization> { + assert!(!source_term.has_escaping_bound_vars()); + let (for_universe, root_vid) = match target_vid.into() { + ty::TermVid::Ty(ty_vid) => ( + self.probe_ty_var(ty_vid).unwrap_err(), + ty::TermVid::Ty(self.inner.borrow_mut().type_variables().sub_root_var(ty_vid)), + ), + ty::TermVid::Const(ct_vid) => ( + self.probe_const_var(ct_vid).unwrap_err(), + ty::TermVid::Const( + self.inner.borrow_mut().const_unification_table().find(ct_vid).vid, + ), + ), + }; - fn span(&self) -> Span { - >::span(&self) - } + let mut generalizer = Generalizer { + infcx: self, + span, + root_vid, + for_universe, + ambient_variance, + root_term: source_term.into(), + in_alias: false, + has_unconstrained_ty_var: false, + cache: Default::default(), + }; - fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - >::generalize_existential(self, universe) + let value_may_be_infer = generalizer.relate(source_term, source_term)?; + let has_unconstrained_ty_var = generalizer.has_unconstrained_ty_var; + Ok(Generalization { value_may_be_infer, has_unconstrained_ty_var }) } } @@ -305,18 +244,10 @@ where /// establishes `'0: 'x` as a constraint. /// /// [blog post]: https://is.gd/0hKvIr -struct Generalizer<'me, 'tcx, D> { +struct Generalizer<'me, 'tcx> { infcx: &'me InferCtxt<'tcx>, - /// This is used to abstract the behaviors of the three previous - /// generalizer-like implementations (`Generalizer`, `TypeGeneralizer`, - /// and `ConstInferUnifier`). See [`GeneralizerDelegate`] for more - /// information. - delegate: &'me mut D, - - /// After we generalize this type, we are going to relate it to - /// some other type. What will be the variance at this point? - ambient_variance: ty::Variance, + span: Span, /// The vid of the type variable that is in the process of being /// instantiated. If we find this within the value we are folding, @@ -328,6 +259,10 @@ struct Generalizer<'me, 'tcx, D> { /// we reject the relation. for_universe: ty::UniverseIndex, + /// After we generalize this type, we are going to relate it to + /// some other type. What will be the variance at this point? + ambient_variance: ty::Variance, + /// The root term (const or type) we're generalizing. Used for cycle errors. root_term: Term<'tcx>, @@ -344,7 +279,7 @@ struct Generalizer<'me, 'tcx, D> { has_unconstrained_ty_var: bool, } -impl<'tcx, D> Generalizer<'_, 'tcx, D> { +impl<'tcx> Generalizer<'_, 'tcx> { /// Create an error that corresponds to the term kind in `root_term` fn cyclic_term_error(&self) -> TypeError<'tcx> { match self.root_term.unpack() { @@ -354,10 +289,7 @@ impl<'tcx, D> Generalizer<'_, 'tcx, D> { } } -impl<'tcx, D> TypeRelation<'tcx> for Generalizer<'_, 'tcx, D> -where - D: GeneralizerDelegate<'tcx>, -{ +impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -426,12 +358,6 @@ where // subtyping. This is basically our "occurs check", preventing // us from creating infinitely sized types. let g = match *t.kind() { - ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) - if D::forbid_inference_vars() => - { - bug!("unexpected inference variable encountered in NLL generalization: {t}"); - } - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("unexpected infer type: {t}") } @@ -534,7 +460,7 @@ where Ok(self.infcx.next_ty_var_in_universe( TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, - span: self.delegate.span(), + span: self.span, }, self.for_universe, )) @@ -592,7 +518,10 @@ where } } - Ok(self.delegate.generalize_region(self.for_universe)) + Ok(self.infcx.next_region_var_in_universe( + RegionVariableOrigin::MiscVariable(self.span), + self.for_universe, + )) } #[instrument(level = "debug", skip(self, c2), ret)] @@ -604,9 +533,6 @@ where assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be == match c.kind() { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { - bug!("unexpected inference variable encountered in NLL generalization: {:?}", c); - } ty::ConstKind::Infer(InferConst::Var(vid)) => { // If root const vids are equal, then `root_vid` and // `vid` are related and we'd be inferring an infinitely -- cgit 1.4.1-3-g733a5 From c00b38e9fbd417ffafd3c0508ababec92527b969 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 02:57:24 +0100 Subject: Don't bother to save a block --- compiler/rustc_mir_build/src/build/matches/mod.rs | 4 - .../building/issue_101867.main.built.after.mir | 20 +++- .../building/issue_49232.main.built.after.mir | 34 +++--- ..._or_in_conditional.test_complex.built.after.mir | 130 ++++++++++++--------- ...h_false_edges.full_tested_match.built.after.mir | 48 +++++--- ..._false_edges.full_tested_match2.built.after.mir | 50 +++++--- .../match_false_edges.main.built.after.mir | 72 +++++++----- .../simple_match.match_bool.built.after.mir | 18 ++- ...y_move_out.move_out_by_subslice.built.after.mir | 34 +++--- ...rray_move_out.move_out_from_end.built.after.mir | 34 +++--- tests/mir-opt/issue_72181.bar.built.after.mir | 4 + tests/mir-opt/issue_72181.main.built.after.mir | 16 ++- tests/mir-opt/issue_91633.bar.built.after.mir | 14 ++- tests/mir-opt/issue_91633.hey.built.after.mir | 8 +- .../mir-opt/issue_99325.main.built.after.32bit.mir | 82 +++++++------ .../mir-opt/issue_99325.main.built.after.64bit.mir | 82 +++++++------ 16 files changed, 381 insertions(+), 269 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 35f5a6bfac5..0f681801815 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1226,10 +1226,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(last_otherwise_block) = otherwise_block { last_otherwise_block } else { - // Any remaining candidates are unreachable. - if unmatched_candidates.is_empty() { - return; - } self.cfg.start_new_block() } } else { diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index 028d7ee7cd8..19a777cb03b 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -27,13 +27,13 @@ fn main() -> () { StorageLive(_5); PlaceMention(_1); _6 = discriminant(_1); - switchInt(move _6) -> [1: bb5, otherwise: bb4]; + switchInt(move _6) -> [1: bb6, otherwise: bb4]; } bb1: { StorageLive(_3); StorageLive(_4); - _4 = begin_panic::<&str>(const "explicit panic") -> bb8; + _4 = begin_panic::<&str>(const "explicit panic") -> bb10; } bb2: { @@ -48,14 +48,22 @@ fn main() -> () { } bb4: { - goto -> bb7; + goto -> bb9; } bb5: { - falseEdge -> [real: bb6, imaginary: bb4]; + goto -> bb3; } bb6: { + falseEdge -> [real: bb8, imaginary: bb4]; + } + + bb7: { + goto -> bb4; + } + + bb8: { _5 = ((_1 as Some).0: u8); _0 = const (); StorageDead(_5); @@ -63,12 +71,12 @@ fn main() -> () { return; } - bb7: { + bb9: { StorageDead(_5); goto -> bb1; } - bb8 (cleanup): { + bb10 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/issue_49232.main.built.after.mir b/tests/mir-opt/building/issue_49232.main.built.after.mir index 7c1f5a6ec72..d09a1748a8b 100644 --- a/tests/mir-opt/building/issue_49232.main.built.after.mir +++ b/tests/mir-opt/building/issue_49232.main.built.after.mir @@ -17,7 +17,7 @@ fn main() -> () { } bb1: { - falseUnwind -> [real: bb2, unwind: bb12]; + falseUnwind -> [real: bb2, unwind: bb14]; } bb2: { @@ -25,7 +25,7 @@ fn main() -> () { StorageLive(_3); _3 = const true; PlaceMention(_3); - switchInt(_3) -> [0: bb4, otherwise: bb5]; + switchInt(_3) -> [0: bb4, otherwise: bb6]; } bb3: { @@ -34,37 +34,45 @@ fn main() -> () { } bb4: { - falseEdge -> [real: bb6, imaginary: bb5]; + falseEdge -> [real: bb8, imaginary: bb6]; } bb5: { - _0 = const (); - goto -> bb11; + goto -> bb3; } bb6: { - _2 = const 4_i32; - goto -> bb9; + _0 = const (); + goto -> bb13; } bb7: { - unreachable; + goto -> bb3; } bb8: { - goto -> bb9; + _2 = const 4_i32; + goto -> bb11; } bb9: { + unreachable; + } + + bb10: { + goto -> bb11; + } + + bb11: { FakeRead(ForLet(None), _2); StorageDead(_3); StorageLive(_5); StorageLive(_6); _6 = &_2; - _5 = std::mem::drop::<&i32>(move _6) -> [return: bb10, unwind: bb12]; + _5 = std::mem::drop::<&i32>(move _6) -> [return: bb12, unwind: bb14]; } - bb10: { + bb12: { StorageDead(_6); StorageDead(_5); _1 = const (); @@ -72,13 +80,13 @@ fn main() -> () { goto -> bb1; } - bb11: { + bb13: { StorageDead(_3); StorageDead(_2); return; } - bb12 (cleanup): { + bb14 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir index d7c758d8876..89572177b1d 100644 --- a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir +++ b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir @@ -19,13 +19,13 @@ fn test_complex() -> () { bb0: { StorageLive(_1); StorageLive(_2); - _2 = E::f() -> [return: bb1, unwind: bb33]; + _2 = E::f() -> [return: bb1, unwind: bb37]; } bb1: { PlaceMention(_2); _3 = discriminant(_2); - switchInt(move _3) -> [0: bb4, otherwise: bb3]; + switchInt(move _3) -> [0: bb5, otherwise: bb3]; } bb2: { @@ -34,163 +34,179 @@ fn test_complex() -> () { } bb3: { - goto -> bb20; + goto -> bb22; } bb4: { - falseEdge -> [real: bb5, imaginary: bb3]; + goto -> bb2; } bb5: { - StorageLive(_4); - _4 = always_true() -> [return: bb6, unwind: bb33]; + falseEdge -> [real: bb7, imaginary: bb3]; } bb6: { - switchInt(move _4) -> [0: bb8, otherwise: bb7]; + goto -> bb3; } bb7: { + StorageLive(_4); + _4 = always_true() -> [return: bb8, unwind: bb37]; + } + + bb8: { + switchInt(move _4) -> [0: bb10, otherwise: bb9]; + } + + bb9: { StorageLive(_5); StorageLive(_6); StorageLive(_7); _7 = Droppy(const 0_u8); _6 = (_7.0: u8); _5 = Gt(move _6, const 0_u8); - switchInt(move _5) -> [0: bb10, otherwise: bb9]; + switchInt(move _5) -> [0: bb12, otherwise: bb11]; } - bb8: { - goto -> bb14; + bb10: { + goto -> bb16; } - bb9: { - drop(_7) -> [return: bb11, unwind: bb33]; + bb11: { + drop(_7) -> [return: bb13, unwind: bb37]; } - bb10: { - goto -> bb12; + bb12: { + goto -> bb14; } - bb11: { + bb13: { StorageDead(_7); StorageDead(_6); - goto -> bb17; + goto -> bb19; } - bb12: { - drop(_7) -> [return: bb13, unwind: bb33]; + bb14: { + drop(_7) -> [return: bb15, unwind: bb37]; } - bb13: { + bb15: { StorageDead(_7); StorageDead(_6); - goto -> bb14; + goto -> bb16; } - bb14: { + bb16: { StorageLive(_8); StorageLive(_9); StorageLive(_10); _10 = Droppy(const 1_u8); _9 = (_10.0: u8); _8 = Gt(move _9, const 1_u8); - switchInt(move _8) -> [0: bb16, otherwise: bb15]; + switchInt(move _8) -> [0: bb18, otherwise: bb17]; } - bb15: { - drop(_10) -> [return: bb17, unwind: bb33]; + bb17: { + drop(_10) -> [return: bb19, unwind: bb37]; } - bb16: { - goto -> bb18; + bb18: { + goto -> bb20; } - bb17: { + bb19: { StorageDead(_10); StorageDead(_9); _1 = const (); - goto -> bb21; + goto -> bb23; } - bb18: { - drop(_10) -> [return: bb19, unwind: bb33]; + bb20: { + drop(_10) -> [return: bb21, unwind: bb37]; } - bb19: { + bb21: { StorageDead(_10); StorageDead(_9); - goto -> bb20; + goto -> bb22; } - bb20: { + bb22: { _1 = const (); - goto -> bb21; + goto -> bb23; } - bb21: { + bb23: { StorageDead(_8); StorageDead(_5); StorageDead(_4); StorageDead(_2); StorageDead(_1); StorageLive(_11); - _11 = always_true() -> [return: bb22, unwind: bb33]; + _11 = always_true() -> [return: bb24, unwind: bb37]; } - bb22: { - switchInt(move _11) -> [0: bb24, otherwise: bb23]; + bb24: { + switchInt(move _11) -> [0: bb26, otherwise: bb25]; } - bb23: { - goto -> bb31; + bb25: { + goto -> bb35; } - bb24: { - goto -> bb25; + bb26: { + goto -> bb27; } - bb25: { + bb27: { StorageLive(_12); - _12 = E::f() -> [return: bb26, unwind: bb33]; + _12 = E::f() -> [return: bb28, unwind: bb37]; } - bb26: { + bb28: { PlaceMention(_12); _13 = discriminant(_12); - switchInt(move _13) -> [1: bb29, otherwise: bb28]; + switchInt(move _13) -> [1: bb32, otherwise: bb30]; } - bb27: { + bb29: { FakeRead(ForMatchedPlace(None), _12); unreachable; } - bb28: { - goto -> bb31; + bb30: { + goto -> bb35; } - bb29: { - falseEdge -> [real: bb30, imaginary: bb28]; + bb31: { + goto -> bb29; } - bb30: { + bb32: { + falseEdge -> [real: bb34, imaginary: bb30]; + } + + bb33: { + goto -> bb30; + } + + bb34: { _0 = const (); - goto -> bb32; + goto -> bb36; } - bb31: { + bb35: { _0 = const (); - goto -> bb32; + goto -> bb36; } - bb32: { + bb36: { StorageDead(_11); StorageDead(_12); return; } - bb33 (cleanup): { + bb37 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir b/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir index 88292dd0597..4e91eb6f76f 100644 --- a/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir +++ b/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir @@ -28,7 +28,7 @@ fn full_tested_match() -> () { _2 = Option::::Some(const 42_i32); PlaceMention(_2); _3 = discriminant(_2); - switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; + switchInt(move _3) -> [0: bb2, 1: bb4, otherwise: bb1]; } bb1: { @@ -38,30 +38,38 @@ fn full_tested_match() -> () { bb2: { _1 = (const 3_i32, const 3_i32); - goto -> bb11; + goto -> bb13; } bb3: { - falseEdge -> [real: bb5, imaginary: bb4]; + goto -> bb1; } bb4: { - falseEdge -> [real: bb10, imaginary: bb2]; + falseEdge -> [real: bb7, imaginary: bb5]; } bb5: { + falseEdge -> [real: bb12, imaginary: bb2]; + } + + bb6: { + goto -> bb1; + } + + bb7: { StorageLive(_6); _6 = &((_2 as Some).0: i32); _4 = &fake _2; StorageLive(_7); - _7 = guard() -> [return: bb6, unwind: bb13]; + _7 = guard() -> [return: bb8, unwind: bb16]; } - bb6: { - switchInt(move _7) -> [0: bb8, otherwise: bb7]; + bb8: { + switchInt(move _7) -> [0: bb10, otherwise: bb9]; } - bb7: { + bb9: { StorageDead(_7); FakeRead(ForMatchGuard, _4); FakeRead(ForGuardBinding, _6); @@ -73,20 +81,20 @@ fn full_tested_match() -> () { StorageDead(_8); StorageDead(_5); StorageDead(_6); - goto -> bb11; + goto -> bb13; } - bb8: { - goto -> bb9; + bb10: { + goto -> bb11; } - bb9: { + bb11: { StorageDead(_7); StorageDead(_6); - goto -> bb4; + goto -> bb5; } - bb10: { + bb12: { StorageLive(_9); _9 = ((_2 as Some).0: i32); StorageLive(_10); @@ -94,10 +102,10 @@ fn full_tested_match() -> () { _1 = (const 2_i32, move _10); StorageDead(_10); StorageDead(_9); - goto -> bb11; + goto -> bb13; } - bb11: { + bb13: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -105,12 +113,16 @@ fn full_tested_match() -> () { return; } - bb12: { + bb14: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb13 (cleanup): { + bb15: { + goto -> bb14; + } + + bb16 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir b/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir index 205bb4980d9..0c67cc9f71e 100644 --- a/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir +++ b/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir @@ -28,7 +28,7 @@ fn full_tested_match2() -> () { _2 = Option::::Some(const 42_i32); PlaceMention(_2); _3 = discriminant(_2); - switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; + switchInt(move _3) -> [0: bb2, 1: bb4, otherwise: bb1]; } bb1: { @@ -37,14 +37,18 @@ fn full_tested_match2() -> () { } bb2: { - falseEdge -> [real: bb10, imaginary: bb4]; + falseEdge -> [real: bb12, imaginary: bb5]; } bb3: { - falseEdge -> [real: bb5, imaginary: bb2]; + goto -> bb1; } bb4: { + falseEdge -> [real: bb7, imaginary: bb2]; + } + + bb5: { StorageLive(_9); _9 = ((_2 as Some).0: i32); StorageLive(_10); @@ -52,22 +56,26 @@ fn full_tested_match2() -> () { _1 = (const 2_i32, move _10); StorageDead(_10); StorageDead(_9); - goto -> bb11; + goto -> bb13; } - bb5: { + bb6: { + goto -> bb1; + } + + bb7: { StorageLive(_6); _6 = &((_2 as Some).0: i32); _4 = &fake _2; StorageLive(_7); - _7 = guard() -> [return: bb6, unwind: bb13]; + _7 = guard() -> [return: bb8, unwind: bb16]; } - bb6: { - switchInt(move _7) -> [0: bb8, otherwise: bb7]; + bb8: { + switchInt(move _7) -> [0: bb10, otherwise: bb9]; } - bb7: { + bb9: { StorageDead(_7); FakeRead(ForMatchGuard, _4); FakeRead(ForGuardBinding, _6); @@ -79,25 +87,25 @@ fn full_tested_match2() -> () { StorageDead(_8); StorageDead(_5); StorageDead(_6); - goto -> bb11; + goto -> bb13; } - bb8: { - goto -> bb9; + bb10: { + goto -> bb11; } - bb9: { + bb11: { StorageDead(_7); StorageDead(_6); - falseEdge -> [real: bb4, imaginary: bb2]; + falseEdge -> [real: bb5, imaginary: bb2]; } - bb10: { + bb12: { _1 = (const 3_i32, const 3_i32); - goto -> bb11; + goto -> bb13; } - bb11: { + bb13: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -105,12 +113,16 @@ fn full_tested_match2() -> () { return; } - bb12: { + bb14: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb13 (cleanup): { + bb15: { + goto -> bb14; + } + + bb16 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match_false_edges.main.built.after.mir index 21f377a6404..b71b2412cdf 100644 --- a/tests/mir-opt/building/match_false_edges.main.built.after.mir +++ b/tests/mir-opt/building/match_false_edges.main.built.after.mir @@ -39,7 +39,7 @@ fn main() -> () { _2 = Option::::Some(const 1_i32); PlaceMention(_2); _4 = discriminant(_2); - switchInt(move _4) -> [1: bb7, otherwise: bb2]; + switchInt(move _4) -> [1: bb8, otherwise: bb2]; } bb1: { @@ -48,12 +48,12 @@ fn main() -> () { } bb2: { - falseEdge -> [real: bb14, imaginary: bb5]; + falseEdge -> [real: bb15, imaginary: bb6]; } bb3: { _3 = discriminant(_2); - switchInt(move _3) -> [1: bb5, otherwise: bb4]; + switchInt(move _3) -> [1: bb6, otherwise: bb4]; } bb4: { @@ -61,38 +61,42 @@ fn main() -> () { _14 = _2; _1 = const 4_i32; StorageDead(_14); - goto -> bb20; + goto -> bb21; } bb5: { - falseEdge -> [real: bb15, imaginary: bb4]; + goto -> bb1; } bb6: { - goto -> bb4; + falseEdge -> [real: bb16, imaginary: bb4]; } bb7: { - falseEdge -> [real: bb9, imaginary: bb2]; + goto -> bb4; } bb8: { - goto -> bb2; + falseEdge -> [real: bb10, imaginary: bb2]; } bb9: { + goto -> bb2; + } + + bb10: { StorageLive(_7); _7 = &((_2 as Some).0: i32); _5 = &fake _2; StorageLive(_8); - _8 = guard() -> [return: bb10, unwind: bb22]; + _8 = guard() -> [return: bb11, unwind: bb24]; } - bb10: { - switchInt(move _8) -> [0: bb12, otherwise: bb11]; + bb11: { + switchInt(move _8) -> [0: bb13, otherwise: bb12]; } - bb11: { + bb12: { StorageDead(_8); FakeRead(ForMatchGuard, _5); FakeRead(ForGuardBinding, _7); @@ -101,42 +105,42 @@ fn main() -> () { _1 = const 1_i32; StorageDead(_6); StorageDead(_7); - goto -> bb20; + goto -> bb21; } - bb12: { - goto -> bb13; + bb13: { + goto -> bb14; } - bb13: { + bb14: { StorageDead(_8); StorageDead(_7); - falseEdge -> [real: bb8, imaginary: bb2]; + falseEdge -> [real: bb9, imaginary: bb2]; } - bb14: { + bb15: { StorageLive(_9); _9 = _2; _1 = const 2_i32; StorageDead(_9); - goto -> bb20; + goto -> bb21; } - bb15: { + bb16: { StorageLive(_11); _11 = &((_2 as Some).0: i32); _5 = &fake _2; StorageLive(_12); StorageLive(_13); _13 = (*_11); - _12 = guard2(move _13) -> [return: bb16, unwind: bb22]; + _12 = guard2(move _13) -> [return: bb17, unwind: bb24]; } - bb16: { - switchInt(move _12) -> [0: bb18, otherwise: bb17]; + bb17: { + switchInt(move _12) -> [0: bb19, otherwise: bb18]; } - bb17: { + bb18: { StorageDead(_13); StorageDead(_12); FakeRead(ForMatchGuard, _5); @@ -146,21 +150,21 @@ fn main() -> () { _1 = const 3_i32; StorageDead(_10); StorageDead(_11); - goto -> bb20; + goto -> bb21; } - bb18: { - goto -> bb19; + bb19: { + goto -> bb20; } - bb19: { + bb20: { StorageDead(_13); StorageDead(_12); StorageDead(_11); - falseEdge -> [real: bb6, imaginary: bb4]; + falseEdge -> [real: bb7, imaginary: bb4]; } - bb20: { + bb21: { PlaceMention(_1); StorageDead(_2); StorageDead(_1); @@ -168,12 +172,16 @@ fn main() -> () { return; } - bb21: { + bb22: { FakeRead(ForMatchedPlace(None), _1); unreachable; } - bb22 (cleanup): { + bb23: { + goto -> bb22; + } + + bb24 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/simple_match.match_bool.built.after.mir b/tests/mir-opt/building/simple_match.match_bool.built.after.mir index cd51c942bee..faa2456fd10 100644 --- a/tests/mir-opt/building/simple_match.match_bool.built.after.mir +++ b/tests/mir-opt/building/simple_match.match_bool.built.after.mir @@ -6,7 +6,7 @@ fn match_bool(_1: bool) -> usize { bb0: { PlaceMention(_1); - switchInt(_1) -> [0: bb2, otherwise: bb3]; + switchInt(_1) -> [0: bb2, otherwise: bb4]; } bb1: { @@ -16,19 +16,27 @@ fn match_bool(_1: bool) -> usize { bb2: { _0 = const 20_usize; - goto -> bb5; + goto -> bb7; } bb3: { - falseEdge -> [real: bb4, imaginary: bb2]; + goto -> bb1; } bb4: { - _0 = const 10_usize; - goto -> bb5; + falseEdge -> [real: bb6, imaginary: bb2]; } bb5: { + goto -> bb2; + } + + bb6: { + _0 = const 10_usize; + goto -> bb7; + } + + bb7: { return; } } diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir index 282c9704ffc..128af9c5602 100644 --- a/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir +++ b/tests/mir-opt/building/uniform_array_move_out.move_out_by_subslice.built.after.mir @@ -30,7 +30,7 @@ fn move_out_by_subslice() -> () { StorageLive(_2); _3 = SizeOf(i32); _4 = AlignOf(i32); - _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb13]; + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb14]; } bb1: { @@ -38,7 +38,7 @@ fn move_out_by_subslice() -> () { _6 = ShallowInitBox(move _5, i32); (*_6) = const 1_i32; _2 = move _6; - drop(_6) -> [return: bb2, unwind: bb12]; + drop(_6) -> [return: bb2, unwind: bb13]; } bb2: { @@ -46,7 +46,7 @@ fn move_out_by_subslice() -> () { StorageLive(_7); _8 = SizeOf(i32); _9 = AlignOf(i32); - _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb12]; + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb13]; } bb3: { @@ -54,18 +54,18 @@ fn move_out_by_subslice() -> () { _11 = ShallowInitBox(move _10, i32); (*_11) = const 2_i32; _7 = move _11; - drop(_11) -> [return: bb4, unwind: bb11]; + drop(_11) -> [return: bb4, unwind: bb12]; } bb4: { StorageDead(_11); _1 = [move _2, move _7]; - drop(_7) -> [return: bb5, unwind: bb12]; + drop(_7) -> [return: bb5, unwind: bb13]; } bb5: { StorageDead(_7); - drop(_2) -> [return: bb6, unwind: bb13]; + drop(_2) -> [return: bb6, unwind: bb14]; } bb6: { @@ -75,7 +75,7 @@ fn move_out_by_subslice() -> () { StorageLive(_12); _12 = move _1[0..2]; _0 = const (); - drop(_12) -> [return: bb8, unwind: bb10]; + drop(_12) -> [return: bb9, unwind: bb11]; } bb7: { @@ -84,28 +84,32 @@ fn move_out_by_subslice() -> () { } bb8: { - StorageDead(_12); - drop(_1) -> [return: bb9, unwind: bb13]; + goto -> bb7; } bb9: { - StorageDead(_1); - return; + StorageDead(_12); + drop(_1) -> [return: bb10, unwind: bb14]; } - bb10 (cleanup): { - drop(_1) -> [return: bb13, unwind terminate(cleanup)]; + bb10: { + StorageDead(_1); + return; } bb11 (cleanup): { - drop(_7) -> [return: bb12, unwind terminate(cleanup)]; + drop(_1) -> [return: bb14, unwind terminate(cleanup)]; } bb12 (cleanup): { - drop(_2) -> [return: bb13, unwind terminate(cleanup)]; + drop(_7) -> [return: bb13, unwind terminate(cleanup)]; } bb13 (cleanup): { + drop(_2) -> [return: bb14, unwind terminate(cleanup)]; + } + + bb14 (cleanup): { resume; } } diff --git a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir index d1956c91b88..d50a6872a41 100644 --- a/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir +++ b/tests/mir-opt/building/uniform_array_move_out.move_out_from_end.built.after.mir @@ -30,7 +30,7 @@ fn move_out_from_end() -> () { StorageLive(_2); _3 = SizeOf(i32); _4 = AlignOf(i32); - _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb13]; + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb14]; } bb1: { @@ -38,7 +38,7 @@ fn move_out_from_end() -> () { _6 = ShallowInitBox(move _5, i32); (*_6) = const 1_i32; _2 = move _6; - drop(_6) -> [return: bb2, unwind: bb12]; + drop(_6) -> [return: bb2, unwind: bb13]; } bb2: { @@ -46,7 +46,7 @@ fn move_out_from_end() -> () { StorageLive(_7); _8 = SizeOf(i32); _9 = AlignOf(i32); - _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb12]; + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb13]; } bb3: { @@ -54,18 +54,18 @@ fn move_out_from_end() -> () { _11 = ShallowInitBox(move _10, i32); (*_11) = const 2_i32; _7 = move _11; - drop(_11) -> [return: bb4, unwind: bb11]; + drop(_11) -> [return: bb4, unwind: bb12]; } bb4: { StorageDead(_11); _1 = [move _2, move _7]; - drop(_7) -> [return: bb5, unwind: bb12]; + drop(_7) -> [return: bb5, unwind: bb13]; } bb5: { StorageDead(_7); - drop(_2) -> [return: bb6, unwind: bb13]; + drop(_2) -> [return: bb6, unwind: bb14]; } bb6: { @@ -75,7 +75,7 @@ fn move_out_from_end() -> () { StorageLive(_12); _12 = move _1[1 of 2]; _0 = const (); - drop(_12) -> [return: bb8, unwind: bb10]; + drop(_12) -> [return: bb9, unwind: bb11]; } bb7: { @@ -84,28 +84,32 @@ fn move_out_from_end() -> () { } bb8: { - StorageDead(_12); - drop(_1) -> [return: bb9, unwind: bb13]; + goto -> bb7; } bb9: { - StorageDead(_1); - return; + StorageDead(_12); + drop(_1) -> [return: bb10, unwind: bb14]; } - bb10 (cleanup): { - drop(_1) -> [return: bb13, unwind terminate(cleanup)]; + bb10: { + StorageDead(_1); + return; } bb11 (cleanup): { - drop(_7) -> [return: bb12, unwind terminate(cleanup)]; + drop(_1) -> [return: bb14, unwind terminate(cleanup)]; } bb12 (cleanup): { - drop(_2) -> [return: bb13, unwind terminate(cleanup)]; + drop(_7) -> [return: bb13, unwind terminate(cleanup)]; } bb13 (cleanup): { + drop(_2) -> [return: bb14, unwind terminate(cleanup)]; + } + + bb14 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_72181.bar.built.after.mir b/tests/mir-opt/issue_72181.bar.built.after.mir index b6cc7d22195..3ab9152f8bb 100644 --- a/tests/mir-opt/issue_72181.bar.built.after.mir +++ b/tests/mir-opt/issue_72181.bar.built.after.mir @@ -19,4 +19,8 @@ fn bar(_1: [(Never, u32); 1]) -> u32 { FakeRead(ForMatchedPlace(None), _1); unreachable; } + + bb2: { + goto -> bb1; + } } diff --git a/tests/mir-opt/issue_72181.main.built.after.mir b/tests/mir-opt/issue_72181.main.built.after.mir index 12c4a2b6325..cff20702bf7 100644 --- a/tests/mir-opt/issue_72181.main.built.after.mir +++ b/tests/mir-opt/issue_72181.main.built.after.mir @@ -22,7 +22,7 @@ fn main() -> () { bb0: { StorageLive(_1); - _1 = std::mem::size_of::() -> [return: bb1, unwind: bb5]; + _1 = std::mem::size_of::() -> [return: bb1, unwind: bb7]; } bb1: { @@ -42,7 +42,7 @@ fn main() -> () { _6 = const 0_usize; _7 = Len(_2); _8 = Lt(_6, _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb5]; + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb4, unwind: bb7]; } bb2: { @@ -51,6 +51,10 @@ fn main() -> () { } bb3: { + goto -> bb2; + } + + bb4: { _5 = (_2[_6].0: u64); PlaceMention(_5); StorageDead(_6); @@ -60,12 +64,16 @@ fn main() -> () { return; } - bb4: { + bb5: { FakeRead(ForMatchedPlace(None), _5); unreachable; } - bb5 (cleanup): { + bb6: { + goto -> bb5; + } + + bb7 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_91633.bar.built.after.mir b/tests/mir-opt/issue_91633.bar.built.after.mir index 53829588a1b..3dcdcab9dea 100644 --- a/tests/mir-opt/issue_91633.bar.built.after.mir +++ b/tests/mir-opt/issue_91633.bar.built.after.mir @@ -12,7 +12,7 @@ fn bar(_1: Box<[T]>) -> () { StorageLive(_2); StorageLive(_3); _3 = &(*_1); - _2 = <[T] as Index>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb4]; + _2 = <[T] as Index>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb5]; } bb1: { @@ -20,7 +20,7 @@ fn bar(_1: Box<[T]>) -> () { PlaceMention((*_2)); StorageDead(_2); _0 = const (); - drop(_1) -> [return: bb3, unwind: bb5]; + drop(_1) -> [return: bb4, unwind: bb6]; } bb2: { @@ -29,14 +29,18 @@ fn bar(_1: Box<[T]>) -> () { } bb3: { - return; + goto -> bb2; } - bb4 (cleanup): { - drop(_1) -> [return: bb5, unwind terminate(cleanup)]; + bb4: { + return; } bb5 (cleanup): { + drop(_1) -> [return: bb6, unwind terminate(cleanup)]; + } + + bb6 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_91633.hey.built.after.mir b/tests/mir-opt/issue_91633.hey.built.after.mir index a537e509996..e782f4d1a23 100644 --- a/tests/mir-opt/issue_91633.hey.built.after.mir +++ b/tests/mir-opt/issue_91633.hey.built.after.mir @@ -14,7 +14,7 @@ fn hey(_1: &[T]) -> () { StorageLive(_3); StorageLive(_4); _4 = &(*_1); - _3 = <[T] as Index>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb3]; + _3 = <[T] as Index>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb4]; } bb1: { @@ -32,7 +32,11 @@ fn hey(_1: &[T]) -> () { unreachable; } - bb3 (cleanup): { + bb3: { + goto -> bb2; + } + + bb4 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index 53254f76dbc..f8e195466ee 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -67,7 +67,7 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb23]; + _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb25]; } bb1: { @@ -91,7 +91,7 @@ fn main() -> () { _11 = &(*_8); StorageLive(_12); _12 = &(*_9); - _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb3, unwind: bb23]; + _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb4, unwind: bb25]; } bb2: { @@ -100,20 +100,24 @@ fn main() -> () { } bb3: { - switchInt(move _10) -> [0: bb5, otherwise: bb4]; + goto -> bb2; } bb4: { - StorageDead(_12); - StorageDead(_11); - goto -> bb9; + switchInt(move _10) -> [0: bb6, otherwise: bb5]; } bb5: { - goto -> bb6; + StorageDead(_12); + StorageDead(_11); + goto -> bb10; } bb6: { + goto -> bb7; + } + + bb7: { StorageDead(_12); StorageDead(_11); StorageLive(_14); @@ -132,10 +136,10 @@ fn main() -> () { _19 = &(*_20); StorageLive(_21); _21 = Option::>::None; - _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb23; + _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb25; } - bb7: { + bb8: { StorageDead(_21); StorageDead(_19); StorageDead(_17); @@ -147,23 +151,23 @@ fn main() -> () { unreachable; } - bb8: { - goto -> bb10; + bb9: { + goto -> bb11; } - bb9: { + bb10: { _1 = const (); - goto -> bb10; + goto -> bb11; } - bb10: { + bb11: { StorageDead(_10); StorageDead(_9); StorageDead(_8); - goto -> bb11; + goto -> bb12; } - bb11: { + bb12: { StorageDead(_7); StorageDead(_6); StorageDead(_4); @@ -173,10 +177,10 @@ fn main() -> () { StorageLive(_23); StorageLive(_24); StorageLive(_25); - _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb12, unwind: bb23]; + _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb13, unwind: bb25]; } - bb12: { + bb13: { _24 = &_25; StorageLive(_26); StorageLive(_27); @@ -195,29 +199,33 @@ fn main() -> () { _31 = &(*_28); StorageLive(_32); _32 = &(*_29); - _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb14, unwind: bb23]; + _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb16, unwind: bb25]; } - bb13: { + bb14: { FakeRead(ForMatchedPlace(None), _23); unreachable; } - bb14: { - switchInt(move _30) -> [0: bb16, otherwise: bb15]; + bb15: { + goto -> bb14; } - bb15: { + bb16: { + switchInt(move _30) -> [0: bb18, otherwise: bb17]; + } + + bb17: { StorageDead(_32); StorageDead(_31); - goto -> bb20; + goto -> bb22; } - bb16: { - goto -> bb17; + bb18: { + goto -> bb19; } - bb17: { + bb19: { StorageDead(_32); StorageDead(_31); StorageLive(_34); @@ -236,10 +244,10 @@ fn main() -> () { _39 = &(*_40); StorageLive(_41); _41 = Option::>::None; - _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb23; + _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb25; } - bb18: { + bb20: { StorageDead(_41); StorageDead(_39); StorageDead(_37); @@ -251,23 +259,23 @@ fn main() -> () { unreachable; } - bb19: { - goto -> bb21; + bb21: { + goto -> bb23; } - bb20: { + bb22: { _22 = const (); - goto -> bb21; + goto -> bb23; } - bb21: { + bb23: { StorageDead(_30); StorageDead(_29); StorageDead(_28); - goto -> bb22; + goto -> bb24; } - bb22: { + bb24: { StorageDead(_27); StorageDead(_25); StorageDead(_23); @@ -276,7 +284,7 @@ fn main() -> () { return; } - bb23 (cleanup): { + bb25 (cleanup): { resume; } } diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index 53254f76dbc..f8e195466ee 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -67,7 +67,7 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb23]; + _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb25]; } bb1: { @@ -91,7 +91,7 @@ fn main() -> () { _11 = &(*_8); StorageLive(_12); _12 = &(*_9); - _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb3, unwind: bb23]; + _10 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _11, move _12) -> [return: bb4, unwind: bb25]; } bb2: { @@ -100,20 +100,24 @@ fn main() -> () { } bb3: { - switchInt(move _10) -> [0: bb5, otherwise: bb4]; + goto -> bb2; } bb4: { - StorageDead(_12); - StorageDead(_11); - goto -> bb9; + switchInt(move _10) -> [0: bb6, otherwise: bb5]; } bb5: { - goto -> bb6; + StorageDead(_12); + StorageDead(_11); + goto -> bb10; } bb6: { + goto -> bb7; + } + + bb7: { StorageDead(_12); StorageDead(_11); StorageLive(_14); @@ -132,10 +136,10 @@ fn main() -> () { _19 = &(*_20); StorageLive(_21); _21 = Option::>::None; - _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb23; + _15 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _16, move _17, move _19, move _21) -> bb25; } - bb7: { + bb8: { StorageDead(_21); StorageDead(_19); StorageDead(_17); @@ -147,23 +151,23 @@ fn main() -> () { unreachable; } - bb8: { - goto -> bb10; + bb9: { + goto -> bb11; } - bb9: { + bb10: { _1 = const (); - goto -> bb10; + goto -> bb11; } - bb10: { + bb11: { StorageDead(_10); StorageDead(_9); StorageDead(_8); - goto -> bb11; + goto -> bb12; } - bb11: { + bb12: { StorageDead(_7); StorageDead(_6); StorageDead(_4); @@ -173,10 +177,10 @@ fn main() -> () { StorageLive(_23); StorageLive(_24); StorageLive(_25); - _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb12, unwind: bb23]; + _25 = function_with_bytes::<&*b"AAAA">() -> [return: bb13, unwind: bb25]; } - bb12: { + bb13: { _24 = &_25; StorageLive(_26); StorageLive(_27); @@ -195,29 +199,33 @@ fn main() -> () { _31 = &(*_28); StorageLive(_32); _32 = &(*_29); - _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb14, unwind: bb23]; + _30 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _31, move _32) -> [return: bb16, unwind: bb25]; } - bb13: { + bb14: { FakeRead(ForMatchedPlace(None), _23); unreachable; } - bb14: { - switchInt(move _30) -> [0: bb16, otherwise: bb15]; + bb15: { + goto -> bb14; } - bb15: { + bb16: { + switchInt(move _30) -> [0: bb18, otherwise: bb17]; + } + + bb17: { StorageDead(_32); StorageDead(_31); - goto -> bb20; + goto -> bb22; } - bb16: { - goto -> bb17; + bb18: { + goto -> bb19; } - bb17: { + bb19: { StorageDead(_32); StorageDead(_31); StorageLive(_34); @@ -236,10 +244,10 @@ fn main() -> () { _39 = &(*_40); StorageLive(_41); _41 = Option::>::None; - _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb23; + _35 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _36, move _37, move _39, move _41) -> bb25; } - bb18: { + bb20: { StorageDead(_41); StorageDead(_39); StorageDead(_37); @@ -251,23 +259,23 @@ fn main() -> () { unreachable; } - bb19: { - goto -> bb21; + bb21: { + goto -> bb23; } - bb20: { + bb22: { _22 = const (); - goto -> bb21; + goto -> bb23; } - bb21: { + bb23: { StorageDead(_30); StorageDead(_29); StorageDead(_28); - goto -> bb22; + goto -> bb24; } - bb22: { + bb24: { StorageDead(_27); StorageDead(_25); StorageDead(_23); @@ -276,7 +284,7 @@ fn main() -> () { return; } - bb23 (cleanup): { + bb25 (cleanup): { resume; } } -- cgit 1.4.1-3-g733a5 From b2edcc7130244872f8ad6e119c54ade008c3bbfe Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 03:04:00 +0100 Subject: Tweak the function boundary --- compiler/rustc_mir_build/src/build/matches/mod.rs | 28 ++++++++--------------- 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 0f681801815..917929de174 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1219,18 +1219,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("match_candidates: {:?} candidates fully matched", fully_matched); let (matched_candidates, unmatched_candidates) = candidates.split_at_mut(fully_matched); - let block = if !matched_candidates.is_empty() { - let otherwise_block = - self.select_matched_candidates(matched_candidates, start_block, fake_borrows); - - if let Some(last_otherwise_block) = otherwise_block { - last_otherwise_block - } else { - self.cfg.start_new_block() - } - } else { - start_block - }; + let block = self.select_matched_candidates(matched_candidates, start_block, fake_borrows); // If there are no candidates that still need testing, we're // done. Since all matches are exhaustive, execution should @@ -1282,11 +1271,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { matched_candidates: &mut [&mut Candidate<'_, 'tcx>], start_block: BasicBlock, fake_borrows: &mut Option>>, - ) -> Option { - debug_assert!( - !matched_candidates.is_empty(), - "select_matched_candidates called with no candidates", - ); + ) -> BasicBlock { + if matched_candidates.is_empty() { + return start_block; + } debug_assert!( matched_candidates.iter().all(|c| c.subcandidates.is_empty()), "subcandidates should be empty in select_matched_candidates", @@ -1356,7 +1344,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate.pre_binding_block = Some(self.cfg.start_new_block()); } - reachable_candidates.last_mut().unwrap().otherwise_block + reachable_candidates + .last_mut() + .unwrap() + .otherwise_block + .unwrap_or_else(|| self.cfg.start_new_block()) } /// Tests a candidate where there are only or-patterns left to test, or -- cgit 1.4.1-3-g733a5 From a0fa2874e64438f61875f6c2538fb7f2eee7d4ba Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 03:18:08 +0100 Subject: Merge the two loops --- compiler/rustc_mir_build/src/build/matches/mod.rs | 43 +++++++++-------------- 1 file changed, 17 insertions(+), 26 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 917929de174..97e45b74332 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1313,39 +1313,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let fully_matched_with_guard = matched_candidates - .iter() - .position(|c| !c.has_guard) - .unwrap_or(matched_candidates.len() - 1); - - let (reachable_candidates, unreachable_candidates) = - matched_candidates.split_at_mut(fully_matched_with_guard + 1); - let mut next_prebinding = start_block; + let mut reachable = true; + let mut last_reachable_candidate = None; - for candidate in reachable_candidates.iter_mut() { + for candidate in matched_candidates.iter_mut() { assert!(candidate.otherwise_block.is_none()); assert!(candidate.pre_binding_block.is_none()); - candidate.pre_binding_block = Some(next_prebinding); - if candidate.has_guard { - // Create the otherwise block for this candidate, which is the - // pre-binding block for the next candidate. - next_prebinding = self.cfg.start_new_block(); - candidate.otherwise_block = Some(next_prebinding); + if reachable { + candidate.pre_binding_block = Some(next_prebinding); + if candidate.has_guard { + // Create the otherwise block for this candidate, which is the + // pre-binding block for the next candidate. + next_prebinding = self.cfg.start_new_block(); + candidate.otherwise_block = Some(next_prebinding); + } else { + reachable = false; + } + last_reachable_candidate = Some(candidate); + } else { + candidate.pre_binding_block = Some(self.cfg.start_new_block()); } } - debug!( - "match_candidates: add pre_binding_blocks for unreachable {:?}", - unreachable_candidates, - ); - for candidate in unreachable_candidates { - assert!(candidate.pre_binding_block.is_none()); - candidate.pre_binding_block = Some(self.cfg.start_new_block()); - } - - reachable_candidates - .last_mut() + last_reachable_candidate .unwrap() .otherwise_block .unwrap_or_else(|| self.cfg.start_new_block()) -- cgit 1.4.1-3-g733a5 From a11abc634385bbaac00718cf095e92a55b8ce272 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 03:55:00 +0100 Subject: Simplify return block computation --- compiler/rustc_mir_build/src/build/matches/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 97e45b74332..5a5daa949b0 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1315,7 +1315,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut next_prebinding = start_block; let mut reachable = true; - let mut last_reachable_candidate = None; + let mut return_block = None; for candidate in matched_candidates.iter_mut() { assert!(candidate.otherwise_block.is_none()); @@ -1327,19 +1327,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // pre-binding block for the next candidate. next_prebinding = self.cfg.start_new_block(); candidate.otherwise_block = Some(next_prebinding); + return_block = Some(next_prebinding); } else { reachable = false; + return_block = Some(self.cfg.start_new_block()); } - last_reachable_candidate = Some(candidate); } else { candidate.pre_binding_block = Some(self.cfg.start_new_block()); } } - last_reachable_candidate - .unwrap() - .otherwise_block - .unwrap_or_else(|| self.cfg.start_new_block()) + return_block.unwrap() } /// Tests a candidate where there are only or-patterns left to test, or -- cgit 1.4.1-3-g733a5 From 105bdf708606258a5d70e8bed4b576663bcc2672 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 04:16:19 +0100 Subject: Reuse `next_prebinding` The moment we get a candidate without guard, the return block becomes a fresh block linked to nothing. So we can keep assigning a fresh block every iteration to reuse the `next_prebinding` logic. --- compiler/rustc_mir_build/src/build/matches/mod.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 5a5daa949b0..17f3d206232 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1315,29 +1315,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut next_prebinding = start_block; let mut reachable = true; - let mut return_block = None; for candidate in matched_candidates.iter_mut() { assert!(candidate.otherwise_block.is_none()); assert!(candidate.pre_binding_block.is_none()); + candidate.pre_binding_block = Some(next_prebinding); + next_prebinding = self.cfg.start_new_block(); if reachable { - candidate.pre_binding_block = Some(next_prebinding); if candidate.has_guard { // Create the otherwise block for this candidate, which is the // pre-binding block for the next candidate. - next_prebinding = self.cfg.start_new_block(); candidate.otherwise_block = Some(next_prebinding); - return_block = Some(next_prebinding); } else { reachable = false; - return_block = Some(self.cfg.start_new_block()); } - } else { - candidate.pre_binding_block = Some(self.cfg.start_new_block()); } } - return_block.unwrap() + next_prebinding } /// Tests a candidate where there are only or-patterns left to test, or -- cgit 1.4.1-3-g733a5 From b4f0e76021f3a8bb5f264d68d744d35ef867aa1a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 04:19:15 +0100 Subject: It's fine to assign `otherwise_block`s to unreachable candidates --- compiler/rustc_mir_build/src/build/matches/mod.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 17f3d206232..dc04d4e0922 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1314,24 +1314,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let mut next_prebinding = start_block; - let mut reachable = true; - for candidate in matched_candidates.iter_mut() { assert!(candidate.otherwise_block.is_none()); assert!(candidate.pre_binding_block.is_none()); candidate.pre_binding_block = Some(next_prebinding); next_prebinding = self.cfg.start_new_block(); - if reachable { - if candidate.has_guard { - // Create the otherwise block for this candidate, which is the - // pre-binding block for the next candidate. - candidate.otherwise_block = Some(next_prebinding); - } else { - reachable = false; - } + if candidate.has_guard { + // Create the otherwise block for this candidate, which is the + // pre-binding block for the next candidate. + candidate.otherwise_block = Some(next_prebinding); } } - next_prebinding } -- cgit 1.4.1-3-g733a5 From 0896a4963fa595043881184a4886c712706cc8af Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 03:22:16 +0100 Subject: No need for empty special case anymore --- compiler/rustc_mir_build/src/build/matches/mod.rs | 3 --- 1 file changed, 3 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index dc04d4e0922..27c2e9761ee 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1272,9 +1272,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { start_block: BasicBlock, fake_borrows: &mut Option>>, ) -> BasicBlock { - if matched_candidates.is_empty() { - return start_block; - } debug_assert!( matched_candidates.iter().all(|c| c.subcandidates.is_empty()), "subcandidates should be empty in select_matched_candidates", -- cgit 1.4.1-3-g733a5 From e561dbb0b6f930622fce24cfa99172e043e40468 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 04:22:32 +0100 Subject: Move everything into the loop --- compiler/rustc_mir_build/src/build/matches/mod.rs | 74 +++++++++++------------ 1 file changed, 36 insertions(+), 38 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 27c2e9761ee..17834f9152a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1272,48 +1272,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { start_block: BasicBlock, fake_borrows: &mut Option>>, ) -> BasicBlock { - debug_assert!( - matched_candidates.iter().all(|c| c.subcandidates.is_empty()), - "subcandidates should be empty in select_matched_candidates", - ); - - // Insert a borrows of prefixes of places that are bound and are - // behind a dereference projection. - // - // These borrows are taken to avoid situations like the following: - // - // match x[10] { - // _ if { x = &[0]; false } => (), - // y => (), // Out of bounds array access! - // } - // - // match *x { - // // y is bound by reference in the guard and then by copy in the - // // arm, so y is 2 in the arm! - // y if { y == 1 && (x = &2) == () } => y, - // _ => 3, - // } - if let Some(fake_borrows) = fake_borrows { - for Binding { source, .. } in - matched_candidates.iter().flat_map(|candidate| &candidate.bindings) - { - if let Some(i) = - source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref) - { - let proj_base = &source.projection[..i]; - - fake_borrows.insert(Place { - local: source.local, - projection: self.tcx.mk_place_elems(proj_base), - }); - } - } - } - let mut next_prebinding = start_block; for candidate in matched_candidates.iter_mut() { assert!(candidate.otherwise_block.is_none()); assert!(candidate.pre_binding_block.is_none()); + debug_assert!( + candidate.subcandidates.is_empty(), + "subcandidates should be empty in select_matched_candidates", + ); + + if let Some(fake_borrows) = fake_borrows { + // Insert a borrows of prefixes of places that are bound and are + // behind a dereference projection. + // + // These borrows are taken to avoid situations like the following: + // + // match x[10] { + // _ if { x = &[0]; false } => (), + // y => (), // Out of bounds array access! + // } + // + // match *x { + // // y is bound by reference in the guard and then by copy in the + // // arm, so y is 2 in the arm! + // y if { y == 1 && (x = &2) == () } => y, + // _ => 3, + // } + for Binding { source, .. } in &candidate.bindings { + if let Some(i) = + source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref) + { + let proj_base = &source.projection[..i]; + + fake_borrows.insert(Place { + local: source.local, + projection: self.tcx.mk_place_elems(proj_base), + }); + } + } + } + candidate.pre_binding_block = Some(next_prebinding); next_prebinding = self.cfg.start_new_block(); if candidate.has_guard { -- cgit 1.4.1-3-g733a5 From 998d0e9793a3adbe5d8fd35712c8b0517c9b53af Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 04:26:50 +0100 Subject: Move the loop out of the function --- compiler/rustc_mir_build/src/build/matches/mod.rs | 101 +++++++++++----------- 1 file changed, 50 insertions(+), 51 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 17834f9152a..c60997dc883 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1207,7 +1207,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, span: Span, scrutinee_span: Span, - start_block: BasicBlock, + mut start_block: BasicBlock, otherwise_block: BasicBlock, candidates: &mut [&mut Candidate<'_, 'tcx>], fake_borrows: &mut Option>>, @@ -1219,14 +1219,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("match_candidates: {:?} candidates fully matched", fully_matched); let (matched_candidates, unmatched_candidates) = candidates.split_at_mut(fully_matched); - let block = self.select_matched_candidates(matched_candidates, start_block, fake_borrows); + for candidate in matched_candidates.iter_mut() { + start_block = self.select_matched_candidate(candidate, start_block, fake_borrows); + } // If there are no candidates that still need testing, we're // done. Since all matches are exhaustive, execution should // never reach this point. if unmatched_candidates.is_empty() { let source_info = self.source_info(span); - self.cfg.goto(block, source_info, otherwise_block); + self.cfg.goto(start_block, source_info, otherwise_block); return; } @@ -1235,7 +1237,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span, scrutinee_span, unmatched_candidates, - block, + start_block, otherwise_block, fake_borrows, ); @@ -1260,67 +1262,64 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// * the [otherwise block] of the third pattern to a block with an /// [`Unreachable` terminator](TerminatorKind::Unreachable). /// - /// In addition, we add fake edges from the otherwise blocks to the + /// In addition, we later add fake edges from the otherwise blocks to the /// pre-binding block of the next candidate in the original set of /// candidates. /// /// [pre-binding block]: Candidate::pre_binding_block /// [otherwise block]: Candidate::otherwise_block - fn select_matched_candidates( + fn select_matched_candidate( &mut self, - matched_candidates: &mut [&mut Candidate<'_, 'tcx>], + candidate: &mut Candidate<'_, 'tcx>, start_block: BasicBlock, fake_borrows: &mut Option>>, ) -> BasicBlock { - let mut next_prebinding = start_block; - for candidate in matched_candidates.iter_mut() { - assert!(candidate.otherwise_block.is_none()); - assert!(candidate.pre_binding_block.is_none()); - debug_assert!( - candidate.subcandidates.is_empty(), - "subcandidates should be empty in select_matched_candidates", - ); + assert!(candidate.otherwise_block.is_none()); + assert!(candidate.pre_binding_block.is_none()); + debug_assert!( + candidate.subcandidates.is_empty(), + "subcandidates should be empty in select_matched_candidates", + ); - if let Some(fake_borrows) = fake_borrows { - // Insert a borrows of prefixes of places that are bound and are - // behind a dereference projection. - // - // These borrows are taken to avoid situations like the following: - // - // match x[10] { - // _ if { x = &[0]; false } => (), - // y => (), // Out of bounds array access! - // } - // - // match *x { - // // y is bound by reference in the guard and then by copy in the - // // arm, so y is 2 in the arm! - // y if { y == 1 && (x = &2) == () } => y, - // _ => 3, - // } - for Binding { source, .. } in &candidate.bindings { - if let Some(i) = - source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref) - { - let proj_base = &source.projection[..i]; - - fake_borrows.insert(Place { - local: source.local, - projection: self.tcx.mk_place_elems(proj_base), - }); - } + if let Some(fake_borrows) = fake_borrows { + // Insert a borrows of prefixes of places that are bound and are + // behind a dereference projection. + // + // These borrows are taken to avoid situations like the following: + // + // match x[10] { + // _ if { x = &[0]; false } => (), + // y => (), // Out of bounds array access! + // } + // + // match *x { + // // y is bound by reference in the guard and then by copy in the + // // arm, so y is 2 in the arm! + // y if { y == 1 && (x = &2) == () } => y, + // _ => 3, + // } + for Binding { source, .. } in &candidate.bindings { + if let Some(i) = + source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref) + { + let proj_base = &source.projection[..i]; + + fake_borrows.insert(Place { + local: source.local, + projection: self.tcx.mk_place_elems(proj_base), + }); } } + } - candidate.pre_binding_block = Some(next_prebinding); - next_prebinding = self.cfg.start_new_block(); - if candidate.has_guard { - // Create the otherwise block for this candidate, which is the - // pre-binding block for the next candidate. - candidate.otherwise_block = Some(next_prebinding); - } + candidate.pre_binding_block = Some(start_block); + let otherwise_block = self.cfg.start_new_block(); + if candidate.has_guard { + // Create the otherwise block for this candidate, which is the + // pre-binding block for the next candidate. + candidate.otherwise_block = Some(otherwise_block); } - next_prebinding + otherwise_block } /// Tests a candidate where there are only or-patterns left to test, or -- cgit 1.4.1-3-g733a5 From cd0fc78c952b3d2b0589d3d2d2d2096858f43578 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Feb 2024 04:45:35 +0100 Subject: Replace the loop with recursive calls for clarity --- compiler/rustc_mir_build/src/build/matches/mod.rs | 59 ++++++++++++----------- 1 file changed, 31 insertions(+), 28 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index c60997dc883..2585e731ab0 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1212,35 +1212,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates: &mut [&mut Candidate<'_, 'tcx>], fake_borrows: &mut Option>>, ) { - // The candidates are sorted by priority. Check to see whether the - // higher priority candidates (and hence at the front of the slice) - // have satisfied all their match pairs. - let fully_matched = candidates.iter().take_while(|c| c.match_pairs.is_empty()).count(); - debug!("match_candidates: {:?} candidates fully matched", fully_matched); - let (matched_candidates, unmatched_candidates) = candidates.split_at_mut(fully_matched); - - for candidate in matched_candidates.iter_mut() { - start_block = self.select_matched_candidate(candidate, start_block, fake_borrows); - } - - // If there are no candidates that still need testing, we're - // done. Since all matches are exhaustive, execution should - // never reach this point. - if unmatched_candidates.is_empty() { - let source_info = self.source_info(span); - self.cfg.goto(start_block, source_info, otherwise_block); - return; + match candidates { + [] => { + // If there are no candidates that still need testing, we're done. Since all matches are + // exhaustive, execution should never reach this point. + let source_info = self.source_info(span); + self.cfg.goto(start_block, source_info, otherwise_block); + } + [first, remaining @ ..] if first.match_pairs.is_empty() => { + // The first candidate has satisfied all its match pairs; we link it up and continue + // with the remaining candidates. + start_block = self.select_matched_candidate(first, start_block, fake_borrows); + self.match_simplified_candidates( + span, + scrutinee_span, + start_block, + otherwise_block, + remaining, + fake_borrows, + ) + } + candidates => { + // The first candidate has some unsatisfied match pairs; we proceed to do more tests. + self.test_candidates_with_or( + span, + scrutinee_span, + candidates, + start_block, + otherwise_block, + fake_borrows, + ); + } } - - // Test for the remaining candidates. - self.test_candidates_with_or( - span, - scrutinee_span, - unmatched_candidates, - start_block, - otherwise_block, - fake_borrows, - ); } /// Link up matched candidates. -- cgit 1.4.1-3-g733a5 From c17539c0684db0011f96ed652e58481de3e65c63 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 17 Feb 2024 12:42:21 +0100 Subject: Extend Level API --- compiler/rustc_lint_defs/src/lib.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 09b1f03f151..d4e5c78c492 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -227,8 +227,8 @@ impl Level { } /// Converts a lower-case string to a level. This will never construct the expect - /// level as that would require a [`LintExpectationId`] - pub fn from_str(x: &str) -> Option { + /// level as that would require a [`LintExpectationId`]. + pub fn from_str(x: &str) -> Option { match x { "allow" => Some(Level::Allow), "warn" => Some(Level::Warn), @@ -238,17 +238,21 @@ impl Level { } } - /// Converts a symbol to a level. - pub fn from_attr(attr: &Attribute) -> Option { - match attr.name_or_empty() { - sym::allow => Some(Level::Allow), - sym::expect => Some(Level::Expect(LintExpectationId::Unstable { - attr_id: attr.id, - lint_index: None, - })), - sym::warn => Some(Level::Warn), - sym::deny => Some(Level::Deny), - sym::forbid => Some(Level::Forbid), + /// Converts an `Attribute` to a level. + pub fn from_attr(attr: &Attribute) -> Option { + Self::from_symbol(attr.name_or_empty(), Some(attr.id)) + } + + /// Converts a `Symbol` to a level. + pub fn from_symbol(s: Symbol, id: Option) -> Option { + match (s, id) { + (sym::allow, _) => Some(Level::Allow), + (sym::expect, Some(attr_id)) => { + Some(Level::Expect(LintExpectationId::Unstable { attr_id, lint_index: None })) + } + (sym::warn, _) => Some(Level::Warn), + (sym::deny, _) => Some(Level::Deny), + (sym::forbid, _) => Some(Level::Forbid), _ => None, } } -- cgit 1.4.1-3-g733a5 From 24cffbf703dd70c0718d0c99be37d42eadd39011 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 14 Feb 2024 21:40:45 +0300 Subject: resolve: Scale back unloading of speculatively loaded crates --- compiler/rustc_metadata/src/creader.rs | 10 ---------- compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 10 ++++++++++ compiler/rustc_middle/src/query/mod.rs | 7 +++++++ compiler/rustc_passes/src/lang_items.rs | 2 +- compiler/rustc_resolve/src/late.rs | 5 ----- compiler/rustc_resolve/src/lib.rs | 1 - tests/ui/extern-flag/empty-extern-arg.stderr | 9 ++++++++- 7 files changed, 26 insertions(+), 18 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index c18f0e7b7b9..f6d3dba2470 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1070,16 +1070,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option { self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok() } - - pub fn unload_unused_crates(&mut self) { - for opt_cdata in &mut self.cstore.metas { - if let Some(cdata) = opt_cdata - && !cdata.used() - { - *opt_cdata = None; - } - } - } } fn global_allocator_spans(krate: &ast::Crate) -> Vec { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 9df28799f4f..2f507b258fe 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -519,6 +519,16 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { tcx.untracked().cstore.freeze(); tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum)) }, + used_crates: |tcx, ()| { + // The list of loaded crates is now frozen in query cache, + // so make sure cstore is not mutably accessed from here on. + tcx.untracked().cstore.freeze(); + tcx.arena.alloc_from_iter( + CStore::from_tcx(tcx) + .iter_crate_data() + .filter_map(|(cnum, data)| data.used().then_some(cnum)), + ) + }, ..providers.queries }; provide_extern(&mut providers.extern_queries); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5be45c33e11..5ed1ccc49cb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1872,6 +1872,13 @@ rustc_queries! { eval_always desc { "fetching all foreign CrateNum instances" } } + // Crates that are loaded non-speculatively (not for diagnostics or doc links). + // FIXME: This is currently only used for collecting lang items, but should be used instead of + // `crates` in most other cases too. + query used_crates(_: ()) -> &'tcx [CrateNum] { + eval_always + desc { "fetching `CrateNum`s for all crates loaded non-speculatively" } + } /// A list of all traits in a crate, used by rustdoc and error reporting. query traits(_: CrateNum) -> &'tcx [DefId] { diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 9a21397789d..d3e3e183845 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -250,7 +250,7 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { let mut collector = LanguageItemCollector::new(tcx, resolver); // Collect lang items in other crates. - for &cnum in tcx.crates(()).iter() { + for &cnum in tcx.used_crates(()).iter() { for &(def_id, lang_item) in tcx.defined_lang_items(cnum).iter() { collector.collect_item(lang_item, def_id, None); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1cf3fecc289..6aacb0e17d5 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -23,7 +23,6 @@ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{PrimTy, TraitCandidate}; -use rustc_metadata::creader::CStore; use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; @@ -4574,10 +4573,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Encoding foreign def ids in proc macro crate metadata will ICE. return None; } - // Doc paths should be resolved speculatively and should not produce any - // diagnostics, but if they are indeed resolved, then we need to keep the - // corresponding crate alive. - CStore::from_tcx_mut(self.r.tcx).set_used_recursively(def_id.krate); } res }); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1c625f49e3e..a9b6703f3ab 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1651,7 +1651,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.tcx .sess .time("resolve_postprocess", || self.crate_loader(|c| c.postprocess(krate))); - self.crate_loader(|c| c.unload_unused_crates()); }); // Make sure we don't mutate the cstore from here on. diff --git a/tests/ui/extern-flag/empty-extern-arg.stderr b/tests/ui/extern-flag/empty-extern-arg.stderr index 6ad3effe0e2..2785b12a0ae 100644 --- a/tests/ui/extern-flag/empty-extern-arg.stderr +++ b/tests/ui/extern-flag/empty-extern-arg.stderr @@ -1,6 +1,13 @@ error: extern location for std does not exist: +error: `#[panic_handler]` function required, but not found + +error: unwinding panics are not supported without std + | + = help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding + = note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem + error: requires `sized` lang_item -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From eee9d2a773f8c38c83f251c41ea2ec879d7c825c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 6 Feb 2024 15:22:13 -0300 Subject: Change leak check lint message to behavior is likely to change in the future --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- tests/ui/coherence/coherence-fn-implied-bounds.rs | 2 +- tests/ui/coherence/coherence-fn-implied-bounds.stderr | 2 +- tests/ui/coherence/coherence-free-vs-bound-region.rs | 2 +- tests/ui/coherence/coherence-free-vs-bound-region.stderr | 2 +- tests/ui/coherence/coherence-subtyping.rs | 4 ++-- tests/ui/coherence/coherence-subtyping.stderr | 2 +- tests/ui/coherence/coherence-wasm-bindgen.rs | 2 +- tests/ui/coherence/coherence-wasm-bindgen.stderr | 2 +- ...aceholder-region-constraints-on-unification.explicit.stderr | 2 +- ...-coherence-placeholder-region-constraints-on-unification.rs | 2 +- tests/ui/const-generics/invariant.rs | 10 ++++------ tests/ui/const-generics/invariant.stderr | 4 ++-- 13 files changed, 18 insertions(+), 20 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 3f5d3c25971..8ba5942898c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1503,7 +1503,7 @@ declare_lint! { Warn, "distinct impls distinguished only by the leak-check code", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::Custom("the behavior may change in a future release"), reference: "issue #56105 ", }; } diff --git a/tests/ui/coherence/coherence-fn-implied-bounds.rs b/tests/ui/coherence/coherence-fn-implied-bounds.rs index 4539af9a32e..0ae54284102 100644 --- a/tests/ui/coherence/coherence-fn-implied-bounds.rs +++ b/tests/ui/coherence/coherence-fn-implied-bounds.rs @@ -20,7 +20,7 @@ impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {} impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 { //~^ ERROR conflicting implementations - //~| WARNING this was previously accepted by the compiler + //~| WARN the behavior may change in a future release } fn main() {} diff --git a/tests/ui/coherence/coherence-fn-implied-bounds.stderr b/tests/ui/coherence/coherence-fn-implied-bounds.stderr index b0dea746709..ece3288989d 100644 --- a/tests/ui/coherence/coherence-fn-implied-bounds.stderr +++ b/tests/ui/coherence/coherence-fn-implied-bounds.stderr @@ -7,7 +7,7 @@ LL | LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: the behavior may change in a future release = note: for more information, see issue #56105 = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details note: the lint level is defined here diff --git a/tests/ui/coherence/coherence-free-vs-bound-region.rs b/tests/ui/coherence/coherence-free-vs-bound-region.rs index 2f5c49d293d..89d0005fb79 100644 --- a/tests/ui/coherence/coherence-free-vs-bound-region.rs +++ b/tests/ui/coherence/coherence-free-vs-bound-region.rs @@ -15,7 +15,7 @@ impl<'a> TheTrait for fn(&'a u8) {} impl TheTrait for fn(&u8) { //~^ ERROR conflicting implementations of trait - //~| WARNING this was previously accepted by the compiler + //~| WARN the behavior may change in a future release } fn main() {} diff --git a/tests/ui/coherence/coherence-free-vs-bound-region.stderr b/tests/ui/coherence/coherence-free-vs-bound-region.stderr index c97b32e429d..e45cf5ad3a4 100644 --- a/tests/ui/coherence/coherence-free-vs-bound-region.stderr +++ b/tests/ui/coherence/coherence-free-vs-bound-region.stderr @@ -7,7 +7,7 @@ LL | LL | impl TheTrait for fn(&u8) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&u8)` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: the behavior may change in a future release = note: for more information, see issue #56105 = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details note: the lint level is defined here diff --git a/tests/ui/coherence/coherence-subtyping.rs b/tests/ui/coherence/coherence-subtyping.rs index da0cc2d0265..4365ad5c884 100644 --- a/tests/ui/coherence/coherence-subtyping.rs +++ b/tests/ui/coherence/coherence-subtyping.rs @@ -13,8 +13,8 @@ trait TheTrait { impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {} impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { - //~^ WARNING conflicting implementation - //~^^ WARNING this was previously accepted by the compiler but is being phased out + //~^ WARN conflicting implementation + //~| WARN the behavior may change in a future release } fn main() {} diff --git a/tests/ui/coherence/coherence-subtyping.stderr b/tests/ui/coherence/coherence-subtyping.stderr index 9d90019a50f..42f256ace78 100644 --- a/tests/ui/coherence/coherence-subtyping.stderr +++ b/tests/ui/coherence/coherence-subtyping.stderr @@ -7,7 +7,7 @@ LL | LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: the behavior may change in a future release = note: for more information, see issue #56105 = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = note: `#[warn(coherence_leak_check)]` on by default diff --git a/tests/ui/coherence/coherence-wasm-bindgen.rs b/tests/ui/coherence/coherence-wasm-bindgen.rs index ee09a72449b..57daaa134d4 100644 --- a/tests/ui/coherence/coherence-wasm-bindgen.rs +++ b/tests/ui/coherence/coherence-wasm-bindgen.rs @@ -31,7 +31,7 @@ where R: ReturnWasmAbi, { //~^^^^^ ERROR conflicting implementation - //~| WARNING this was previously accepted + //~| WARN the behavior may change in a future release } fn main() {} diff --git a/tests/ui/coherence/coherence-wasm-bindgen.stderr b/tests/ui/coherence/coherence-wasm-bindgen.stderr index b3c3dac612d..939f1fce9a4 100644 --- a/tests/ui/coherence/coherence-wasm-bindgen.stderr +++ b/tests/ui/coherence/coherence-wasm-bindgen.stderr @@ -13,7 +13,7 @@ LL | | A: RefFromWasmAbi, LL | | R: ReturnWasmAbi, | |_____________________^ conflicting implementation for `&dyn Fn(&_) -> _` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: the behavior may change in a future release = note: for more information, see issue #56105 = note: downstream crates may implement trait `FromWasmAbi` for type `&_` = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details diff --git a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr index 5368db29338..832c56a4554 100644 --- a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr +++ b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr @@ -6,7 +6,7 @@ LL | impl FnMarker for fn(T) {} LL | impl FnMarker for fn(&T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&_)` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: the behavior may change in a future release = note: for more information, see issue #56105 = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details note: the lint level is defined here diff --git a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.rs b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.rs index 7967002e021..e487dcc3c0e 100644 --- a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.rs +++ b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.rs @@ -20,6 +20,6 @@ trait FnMarker {} impl FnMarker for fn(T) {} impl FnMarker for fn(&T) {} //[explicit]~^ ERROR conflicting implementations of trait `FnMarker` for type `fn(&_)` -//[explicit]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//[explicit]~| WARN the behavior may change in a future release fn main() {} diff --git a/tests/ui/const-generics/invariant.rs b/tests/ui/const-generics/invariant.rs index 39d658be67d..ee4ad4e7c4e 100644 --- a/tests/ui/const-generics/invariant.rs +++ b/tests/ui/const-generics/invariant.rs @@ -12,18 +12,16 @@ impl SadBee for for<'a> fn(&'a ()) { const ASSOC: usize = 0; } impl SadBee for fn(&'static ()) { - //~^ WARNING conflicting implementations of trait - //~| WARNING this was previously accepted + //~^ WARN conflicting implementations of trait + //~| WARN the behavior may change in a future release const ASSOC: usize = 100; } struct Foo([u8; ::ASSOC], PhantomData) where - [(); ::ASSOC]: ; + [(); ::ASSOC]:; -fn covariant( - v: &'static Foo fn(&'a ())> -) -> &'static Foo { +fn covariant(v: &'static Foo fn(&'a ())>) -> &'static Foo { v //~^ ERROR mismatched types } diff --git a/tests/ui/const-generics/invariant.stderr b/tests/ui/const-generics/invariant.stderr index f631e131146..b4e46e55268 100644 --- a/tests/ui/const-generics/invariant.stderr +++ b/tests/ui/const-generics/invariant.stderr @@ -7,13 +7,13 @@ LL | impl SadBee for for<'a> fn(&'a ()) { LL | impl SadBee for fn(&'static ()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a> fn(&'a ())` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = warning: the behavior may change in a future release = note: for more information, see issue #56105 = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = note: `#[warn(coherence_leak_check)]` on by default error[E0308]: mismatched types - --> $DIR/invariant.rs:27:5 + --> $DIR/invariant.rs:25:5 | LL | v | ^ one type is more general than the other -- cgit 1.4.1-3-g733a5 From 61509914a3debdf6ff809c35af15cc5cabcc32a0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 19 Feb 2024 06:02:14 +0200 Subject: make "custom attribute panicked" translatable --- compiler/rustc_expand/messages.ftl | 4 ++++ compiler/rustc_expand/src/errors.rs | 15 +++++++++++++++ compiler/rustc_expand/src/proc_macro.rs | 11 ++++++----- 3 files changed, 25 insertions(+), 5 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 3e3b4814300..cae4df6cd4b 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -22,6 +22,10 @@ expand_collapse_debuginfo_illegal = expand_count_repetition_misplaced = `count` can not be placed inside the inner-most repetition +expand_custom_attribute_panicked = + custom attribute panicked + .help = message: {$message} + expand_duplicate_matcher_binding = duplicate matcher binding .label = duplicate binding .label2 = previous binding diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 2584ff62e98..5bbf4411bc3 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -392,6 +392,21 @@ pub(crate) struct ProcMacroPanickedHelp { pub message: String, } +#[derive(Diagnostic)] +#[diag(expand_custom_attribute_panicked)] +pub(crate) struct CustomAttributePanicked { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub message: Option, +} + +#[derive(Subdiagnostic)] +#[help(expand_help)] +pub(crate) struct CustomAttributePanickedHelp { + pub message: String, +} + #[derive(Diagnostic)] #[diag(expand_proc_macro_derive_tokens)] pub struct ProcMacroDeriveTokens { diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 2233cad2e63..170857e62ff 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -93,11 +93,12 @@ impl base::AttrProcMacro for AttrProcMacro { let server = proc_macro_server::Rustc::new(ecx); self.client.run(&strategy, server, annotation, annotated, proc_macro_backtrace).map_err( |e| { - let mut err = ecx.dcx().struct_span_err(span, "custom attribute panicked"); - if let Some(s) = e.as_str() { - err.help(format!("message: {s}")); - } - err.emit() + ecx.dcx().emit_err(errors::CustomAttributePanicked { + span, + message: e.as_str().map(|message| errors::CustomAttributePanickedHelp { + message: message.into(), + }), + }) }, ) } -- cgit 1.4.1-3-g733a5 From 486c7b6a50ba53d8a38b6a2391fdd318dbe81497 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 Jan 2024 09:24:19 +0100 Subject: never normalize without eager inference replacement --- .../rustc_trait_selection/src/traits/fulfill.rs | 2 +- .../rustc_trait_selection/src/traits/project.rs | 88 +++------------------- .../rustc_trait_selection/src/traits/select/mod.rs | 3 +- 3 files changed, 11 insertions(+), 82 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 7ad94274634..0fd0fc001e7 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -312,7 +312,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { if obligation.predicate.has_projections() { let mut obligations = Vec::new(); - let predicate = crate::traits::project::try_normalize_with_depth_to( + let predicate = crate::traits::project::normalize_with_depth_to( &mut self.selcx, obligation.param_env, obligation.cause.clone(), diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 279c0003187..908886a5b42 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -374,32 +374,6 @@ where result } -#[instrument(level = "info", skip(selcx, param_env, cause, obligations))] -pub(crate) fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: T, - obligations: &mut Vec>, -) -> T -where - T: TypeFoldable>, -{ - debug!(obligations.len = obligations.len()); - let mut normalizer = AssocTypeNormalizer::new_without_eager_inference_replacement( - selcx, - param_env, - cause, - depth, - obligations, - ); - let result = ensure_sufficient_stack(|| normalizer.fold(value)); - debug!(?result, obligations.len = normalizer.obligations.len()); - debug!(?normalizer.obligations,); - result -} - pub(crate) fn needs_normalization<'tcx, T: TypeVisitable>>( value: &T, reveal: Reveal, @@ -426,10 +400,6 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> { obligations: &'a mut Vec>, depth: usize, universes: Vec>, - /// If true, when a projection is unable to be completed, an inference - /// variable will be created and an obligation registered to project to that - /// inference variable. Also, constants will be eagerly evaluated. - eager_inference_replacement: bool, } impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { @@ -441,33 +411,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { obligations: &'a mut Vec>, ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { debug_assert!(!selcx.infcx.next_trait_solver()); - AssocTypeNormalizer { - selcx, - param_env, - cause, - obligations, - depth, - universes: vec![], - eager_inference_replacement: true, - } - } - - fn new_without_eager_inference_replacement( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &'a mut Vec>, - ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { - AssocTypeNormalizer { - selcx, - param_env, - cause, - obligations, - depth, - universes: vec![], - eager_inference_replacement: false, - } + AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] } } fn fold>>(&mut self, value: T) -> T { @@ -570,28 +514,14 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx // register an obligation to *later* project, since we know // there won't be bound vars there. let data = data.fold_with(self); - let normalized_ty = if self.eager_inference_replacement { - normalize_projection_type( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ) - } else { - opt_normalize_projection_type( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ) - .ok() - .flatten() - .unwrap_or_else(|| ty.super_fold_with(self).into()) - }; + let normalized_ty = normalize_projection_type( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + self.obligations, + ); debug!( ?self.depth, ?ty, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5bcf46a96ed..c2566f27c1f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -22,7 +22,6 @@ use super::{ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt; use crate::traits::error_reporting::TypeErrCtxtExt; -use crate::traits::project::try_normalize_with_depth_to; use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; @@ -1070,7 +1069,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { && fresh_trait_pred.is_global() { let mut nested_obligations = Vec::new(); - let predicate = try_normalize_with_depth_to( + let predicate = normalize_with_depth_to( this, param_env, obligation.cause.clone(), -- cgit 1.4.1-3-g733a5 From 399a258f46074740862568b124c02f7b7d04638c Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 Jan 2024 10:11:30 +0100 Subject: remove `pred_known_to_hold_modulo_regions` --- compiler/rustc_trait_selection/src/traits/mod.rs | 50 ++---------------------- 1 file changed, 3 insertions(+), 47 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 7caaccab63b..bd993d308ac 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -119,9 +119,7 @@ pub fn predicates_for_generics<'tcx>( /// Determines whether the type `ty` is known to meet `bound` and /// returns true if so. Returns false if `ty` either does not meet -/// `bound` or is not known to meet bound (note that this is -/// conservative towards *no impl*, which is the opposite of the -/// `evaluate` methods). +/// `bound` or is not known to meet bound. pub fn type_known_to_meet_bound_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -129,50 +127,8 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( def_id: DefId, ) -> bool { let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]); - pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref) -} - -/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist? -/// -/// Ping me on zulip if you want to use this method and need help with finding -/// an appropriate replacement. -#[instrument(level = "debug", skip(infcx, param_env, pred), ret)] -fn pred_known_to_hold_modulo_regions<'tcx>( - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - pred: impl ToPredicate<'tcx>, -) -> bool { - let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred); - - let result = infcx.evaluate_obligation_no_overflow(&obligation); - debug!(?result); - - if result.must_apply_modulo_regions() { - true - } else if result.may_apply() { - // Sometimes obligations are ambiguous because the recursive evaluator - // is not smart enough, so we fall back to fulfillment when we're not certain - // that an obligation holds or not. Even still, we must make sure that - // the we do no inference in the process of checking this obligation. - let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); - infcx.probe(|_| { - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligation(obligation); - - let errors = ocx.select_all_or_error(); - match errors.as_slice() { - // Only known to hold if we did no inference. - [] => infcx.shallow_resolve(goal) == goal, - - errors => { - debug!(?errors); - false - } - } - }) - } else { - false - } + let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, trait_ref); + infcx.predicate_must_hold_modulo_regions(&obligation) } #[instrument(level = "debug", skip(tcx, elaborated_env))] -- cgit 1.4.1-3-g733a5 From df55f56283d3e92a2fb1710b12cd891ca6a4e863 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 5 Feb 2024 13:12:53 +0100 Subject: `normalize_projection_ty` is not used with next-solver --- .../rustc_traits/src/normalize_projection_ty.rs | 27 +++++++++++----------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 07089d5f19e..94df28a1454 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -25,10 +25,10 @@ fn normalize_projection_ty<'tcx>( goal: CanonicalProjectionGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { debug!("normalize_provider(goal={:#?})", goal); - tcx.infer_ctxt().enter_canonical_trait_query( &goal, |ocx, ParamEnvAnd { param_env, value: goal }| { + debug_assert!(!ocx.infcx.next_trait_solver()); let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = vec![]; @@ -45,23 +45,22 @@ fn normalize_projection_ty<'tcx>( // are recursive (given some generic parameters of the opaque's type variables). // In that case, we may only realize a cycle error when calling // `normalize_erasing_regions` in mono. - if !ocx.infcx.next_trait_solver() { - let errors = ocx.select_where_possible(); - if !errors.is_empty() { - // Rustdoc may attempt to normalize type alias types which are not - // well-formed. Rustdoc also normalizes types that are just not - // well-formed, since we don't do as much HIR analysis (checking - // that impl vars are constrained by the signature, for example). - if !tcx.sess.opts.actually_rustdoc { - for error in &errors { - if let FulfillmentErrorCode::Cycle(cycle) = &error.code { - ocx.infcx.err_ctxt().report_overflow_obligation_cycle(cycle); - } + let errors = ocx.select_where_possible(); + if !errors.is_empty() { + // Rustdoc may attempt to normalize type alias types which are not + // well-formed. Rustdoc also normalizes types that are just not + // well-formed, since we don't do as much HIR analysis (checking + // that impl vars are constrained by the signature, for example). + if !tcx.sess.opts.actually_rustdoc { + for error in &errors { + if let FulfillmentErrorCode::Cycle(cycle) = &error.code { + ocx.infcx.err_ctxt().report_overflow_obligation_cycle(cycle); } } - return Err(NoSolution); } + return Err(NoSolution); } + // FIXME(associated_const_equality): All users of normalize_projection_ty expected // a type, but there is the possibility it could've been a const now. Maybe change // it to a Term later? -- cgit 1.4.1-3-g733a5 From 9771fb08b62d966a705a827e1177fa1b2308577c Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 5 Feb 2024 13:40:32 +0100 Subject: split `project` into multiple files --- compiler/rustc_hir_analysis/src/astconv/mod.rs | 21 +- .../rustc_trait_selection/src/solve/normalize.rs | 5 +- .../rustc_trait_selection/src/traits/fulfill.rs | 3 +- compiler/rustc_trait_selection/src/traits/mod.rs | 6 +- .../rustc_trait_selection/src/traits/normalize.rs | 423 ++++++++++++ .../rustc_trait_selection/src/traits/project.rs | 765 +-------------------- .../src/traits/query/normalize.rs | 5 +- .../src/traits/select/confirmation.rs | 2 +- .../rustc_trait_selection/src/traits/select/mod.rs | 11 +- compiler/rustc_trait_selection/src/traits/util.rs | 338 ++++++++- compiler/rustc_trait_selection/src/traits/wf.rs | 2 +- 11 files changed, 797 insertions(+), 784 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/traits/normalize.rs (limited to 'compiler') diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 3ccf78567ed..296b63a8292 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1425,17 +1425,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { vec![] }; - let (impl_, (assoc_item, def_scope)) = - crate::traits::project::with_replaced_escaping_bound_vars( - infcx, - &mut universes, - self_ty, - |self_ty| { - self.select_inherent_assoc_type_candidates( - infcx, name, span, self_ty, param_env, candidates, - ) - }, - )?; + let (impl_, (assoc_item, def_scope)) = crate::traits::with_replaced_escaping_bound_vars( + infcx, + &mut universes, + self_ty, + |self_ty| { + self.select_inherent_assoc_type_candidates( + infcx, name, span, self_ty, param_env, candidates, + ) + }, + )?; self.check_assoc_ty(assoc_item, name, def_scope, block, span); diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index d87cc89954a..b07702e8421 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,6 +1,6 @@ use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; +use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -205,10 +205,9 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { } fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result, Self::Error> { - let reveal = self.at.param_env.reveal(); let infcx = self.at.infcx; debug_assert_eq!(ct, infcx.shallow_resolve(ct)); - if !needs_normalization(&ct, reveal) { + if !ct.has_projections() { return Ok(ct); } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 0fd0fc001e7..fd981130af8 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,5 +1,6 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; use crate::traits::error_reporting::TypeErrCtxtExt; +use crate::traits::normalize::normalize_with_depth_to; use rustc_data_structures::captures::Captures; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; @@ -312,7 +313,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { if obligation.predicate.has_projections() { let mut obligations = Vec::new(); - let predicate = crate::traits::project::normalize_with_depth_to( + let predicate = normalize_with_depth_to( &mut self.selcx, obligation.param_env, obligation.cause.clone(), diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index bd993d308ac..9eec60ea06c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -9,6 +9,7 @@ mod engine; pub mod error_reporting; mod fulfill; pub mod misc; +pub mod normalize; mod object_safety; pub mod outlives_bounds; pub mod project; @@ -40,17 +41,15 @@ use rustc_span::Span; use std::fmt::Debug; use std::ops::ControlFlow; -pub(crate) use self::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; - pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; pub use self::coherence::{OrphanCheckErr, OverlapResult}; pub use self::engine::{ObligationCtxt, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; +pub use self::normalize::NormalizeExt; pub use self::object_safety::astconv_object_safety_violations; pub use self::object_safety::is_vtable_safe_method; pub use self::object_safety::object_safety_violations_for_assoc_item; pub use self::object_safety::ObjectSafetyViolation; -pub use self::project::NormalizeExt; pub use self::project::{normalize_inherent_projection, normalize_projection_type}; pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; @@ -68,6 +67,7 @@ pub use self::util::{ }; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; +pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; pub use rustc_infer::traits::*; diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs new file mode 100644 index 00000000000..0df6f36f115 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -0,0 +1,423 @@ +//! Deeply normalize types using the old trait solver. +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_infer::infer::at::At; +use rustc_infer::infer::InferOk; +use rustc_infer::traits::PredicateObligation; +use rustc_infer::traits::{FulfillmentError, Normalized, Obligation, TraitEngine}; +use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder}; +use rustc_middle::ty::{TypeFoldable, TypeSuperFoldable, TypeVisitable, TypeVisitableExt}; + +use super::error_reporting::TypeErrCtxtExt; +use super::SelectionContext; +use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; + +#[extension(pub trait NormalizeExt<'tcx>)] +impl<'tcx> At<'_, 'tcx> { + /// Normalize a value using the `AssocTypeNormalizer`. + /// + /// This normalization should be used when the type contains inference variables or the + /// projection may be fallible. + fn normalize>>(&self, value: T) -> InferOk<'tcx, T> { + if self.infcx.next_trait_solver() { + InferOk { value, obligations: Vec::new() } + } else { + let mut selcx = SelectionContext::new(self.infcx); + let Normalized { value, obligations } = + normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value); + InferOk { value, obligations } + } + } + + /// Deeply normalizes `value`, replacing all aliases which can by normalized in + /// the current environment. In the new solver this errors in case normalization + /// fails or is ambiguous. This only normalizes opaque types with `Reveal::All`. + /// + /// In the old solver this simply uses `normalizes` and adds the nested obligations + /// to the `fulfill_cx`. This is necessary as we otherwise end up recomputing the + /// same goals in both a temporary and the shared context which negatively impacts + /// performance as these don't share caching. + /// + /// FIXME(-Znext-solver): This has the same behavior as `traits::fully_normalize` + /// in the new solver, but because of performance reasons, we currently reuse an + /// existing fulfillment context in the old solver. Once we also eagerly prove goals with + /// the old solver or have removed the old solver, remove `traits::fully_normalize` and + /// rename this function to `At::fully_normalize`. + fn deeply_normalize>>( + self, + value: T, + fulfill_cx: &mut dyn TraitEngine<'tcx>, + ) -> Result>> { + if self.infcx.next_trait_solver() { + crate::solve::deeply_normalize(self, value) + } else { + let value = self + .normalize(value) + .into_value_registering_obligations(self.infcx, &mut *fulfill_cx); + let errors = fulfill_cx.select_where_possible(self.infcx); + let value = self.infcx.resolve_vars_if_possible(value); + if errors.is_empty() { Ok(value) } else { Err(errors) } + } + } +} + +/// As `normalize`, but with a custom depth. +pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + value: T, +) -> Normalized<'tcx, T> +where + T: TypeFoldable>, +{ + let mut obligations = Vec::new(); + let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations); + Normalized { value, obligations } +} + +#[instrument(level = "info", skip(selcx, param_env, cause, obligations))] +pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + value: T, + obligations: &mut Vec>, +) -> T +where + T: TypeFoldable>, +{ + debug!(obligations.len = obligations.len()); + let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); + let result = ensure_sufficient_stack(|| normalizer.fold(value)); + debug!(?result, obligations.len = normalizer.obligations.len()); + debug!(?normalizer.obligations,); + result +} + +pub(super) fn needs_normalization<'tcx, T: TypeVisitable>>( + value: &T, + reveal: Reveal, +) -> bool { + match reveal { + Reveal::UserFacing => value.has_type_flags( + ty::TypeFlags::HAS_TY_PROJECTION + | ty::TypeFlags::HAS_TY_INHERENT + | ty::TypeFlags::HAS_CT_PROJECTION, + ), + Reveal::All => value.has_type_flags( + ty::TypeFlags::HAS_TY_PROJECTION + | ty::TypeFlags::HAS_TY_INHERENT + | ty::TypeFlags::HAS_TY_OPAQUE + | ty::TypeFlags::HAS_CT_PROJECTION, + ), + } +} + +struct AssocTypeNormalizer<'a, 'b, 'tcx> { + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + obligations: &'a mut Vec>, + depth: usize, + universes: Vec>, +} + +impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { + fn new( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + obligations: &'a mut Vec>, + ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { + debug_assert!(!selcx.infcx.next_trait_solver()); + AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] } + } + + fn fold>>(&mut self, value: T) -> T { + let value = self.selcx.infcx.resolve_vars_if_possible(value); + debug!(?value); + + assert!( + !value.has_escaping_bound_vars(), + "Normalizing {value:?} without wrapping in a `Binder`" + ); + + if !needs_normalization(&value, self.param_env.reveal()) { + value + } else { + value.fold_with(self) + } + } +} + +impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.selcx.tcx() + } + + fn fold_binder>>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { + self.universes.push(None); + let t = t.super_fold_with(self); + self.universes.pop(); + t + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !needs_normalization(&ty, self.param_env.reveal()) { + return ty; + } + + let (kind, data) = match *ty.kind() { + ty::Alias(kind, alias_ty) => (kind, alias_ty), + _ => return ty.super_fold_with(self), + }; + + // We try to be a little clever here as a performance optimization in + // cases where there are nested projections under binders. + // For example: + // ``` + // for<'a> fn(::One<'a, Box::Two<'a>>>>) + // ``` + // We normalize the args on the projection before the projecting, but + // if we're naive, we'll + // replace bound vars on inner, project inner, replace placeholders on inner, + // replace bound vars on outer, project outer, replace placeholders on outer + // + // However, if we're a bit more clever, we can replace the bound vars + // on the entire type before normalizing nested projections, meaning we + // replace bound vars on outer, project inner, + // project outer, replace placeholders on outer + // + // This is possible because the inner `'a` will already be a placeholder + // when we need to normalize the inner projection + // + // On the other hand, this does add a bit of complexity, since we only + // replace bound vars if the current type is a `Projection` and we need + // to make sure we don't forget to fold the args regardless. + + match kind { + ty::Opaque => { + // Only normalize `impl Trait` outside of type inference, usually in codegen. + match self.param_env.reveal() { + Reveal::UserFacing => ty.super_fold_with(self), + + Reveal::All => { + let recursion_limit = self.interner().recursion_limit(); + if !recursion_limit.value_within_limit(self.depth) { + self.selcx.infcx.err_ctxt().report_overflow_error( + &ty, + self.cause.span, + true, + |_| {}, + ); + } + + let args = data.args.fold_with(self); + let generic_ty = self.interner().type_of(data.def_id); + let concrete_ty = generic_ty.instantiate(self.interner(), args); + self.depth += 1; + let folded_ty = self.fold_ty(concrete_ty); + self.depth -= 1; + folded_ty + } + } + } + + ty::Projection if !data.has_escaping_bound_vars() => { + // This branch is *mostly* just an optimization: when we don't + // have escaping bound vars, we don't need to replace them with + // placeholders (see branch below). *Also*, we know that we can + // register an obligation to *later* project, since we know + // there won't be bound vars there. + let data = data.fold_with(self); + let normalized_ty = project::normalize_projection_type( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + self.obligations, + ); + debug!( + ?self.depth, + ?ty, + ?normalized_ty, + obligations.len = ?self.obligations.len(), + "AssocTypeNormalizer: normalized type" + ); + normalized_ty.ty().unwrap() + } + + ty::Projection => { + // If there are escaping bound vars, we temporarily replace the + // bound vars with placeholders. Note though, that in the case + // that we still can't project for whatever reason (e.g. self + // type isn't known enough), we *can't* register an obligation + // and return an inference variable (since then that obligation + // would have bound vars and that's a can of worms). Instead, + // we just give up and fall back to pretending like we never tried! + // + // Note: this isn't necessarily the final approach here; we may + // want to figure out how to register obligations with escaping vars + // or handle this some other way. + + let infcx = self.selcx.infcx; + let (data, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); + let data = data.fold_with(self); + let normalized_ty = project::opt_normalize_projection_type( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + self.obligations, + ) + .ok() + .flatten() + .map(|term| term.ty().unwrap()) + .map(|normalized_ty| { + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + normalized_ty, + ) + }) + .unwrap_or_else(|| ty.super_fold_with(self)); + + debug!( + ?self.depth, + ?ty, + ?normalized_ty, + obligations.len = ?self.obligations.len(), + "AssocTypeNormalizer: normalized type" + ); + normalized_ty + } + ty::Weak => { + let recursion_limit = self.interner().recursion_limit(); + if !recursion_limit.value_within_limit(self.depth) { + self.selcx.infcx.err_ctxt().report_overflow_error( + &ty, + self.cause.span, + false, + |diag| { + diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow); + }, + ); + } + + let infcx = self.selcx.infcx; + self.obligations.extend( + infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( + |(mut predicate, span)| { + if data.has_escaping_bound_vars() { + (predicate, ..) = BoundVarReplacer::replace_bound_vars( + infcx, + &mut self.universes, + predicate, + ); + } + let mut cause = self.cause.clone(); + cause.map_code(|code| { + ObligationCauseCode::TypeAlias(code, span, data.def_id) + }); + Obligation::new(infcx.tcx, cause, self.param_env, predicate) + }, + ), + ); + self.depth += 1; + let res = infcx + .tcx + .type_of(data.def_id) + .instantiate(infcx.tcx, data.args) + .fold_with(self); + self.depth -= 1; + res + } + + ty::Inherent if !data.has_escaping_bound_vars() => { + // This branch is *mostly* just an optimization: when we don't + // have escaping bound vars, we don't need to replace them with + // placeholders (see branch below). *Also*, we know that we can + // register an obligation to *later* project, since we know + // there won't be bound vars there. + + let data = data.fold_with(self); + + // FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement` + // here like `ty::Projection`? + project::normalize_inherent_projection( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + self.obligations, + ) + } + + ty::Inherent => { + let infcx = self.selcx.infcx; + let (data, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); + let data = data.fold_with(self); + let ty = project::normalize_inherent_projection( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + self.obligations, + ); + + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + ty, + ) + } + } + } + + #[instrument(skip(self), level = "debug")] + fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { + let tcx = self.selcx.tcx(); + if tcx.features().generic_const_exprs + || !needs_normalization(&constant, self.param_env.reveal()) + { + constant + } else { + let constant = constant.super_fold_with(self); + debug!(?constant, ?self.param_env); + with_replaced_escaping_bound_vars( + self.selcx.infcx, + &mut self.universes, + constant, + |constant| constant.normalize(tcx, self.param_env), + ) + } + } + + #[inline] + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { + p.super_fold_with(self) + } else { + p + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 908886a5b42..9c532ea4d8d 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1,5 +1,7 @@ //! Code for projecting associated types out of trait references. +use std::ops::ControlFlow; + use super::check_args_compatible; use super::specialization_graph; use super::translate_args; @@ -18,8 +20,9 @@ use rustc_middle::traits::ImplSourceUserDefinedData; use crate::errors::InherentProjectionNormalizationOverflow; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::infer::{BoundRegionConversionTime, InferCtxt, InferOk}; -use crate::traits::error_reporting::TypeErrCtxtExt as _; +use crate::infer::{BoundRegionConversionTime, InferOk}; +use crate::traits::normalize::normalize_with_depth; +use crate::traits::normalize::normalize_with_depth_to; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::select::ProjectionMatchesProjection; use rustc_data_structures::sso::SsoHashSet; @@ -27,21 +30,14 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::at::At; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::infer::DefineOpaqueTypes; -use rustc_infer::traits::FulfillmentError; -use rustc_infer::traits::ObligationCauseCode; -use rustc_infer::traits::TraitEngine; use rustc_middle::traits::select::OverflowError; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; -use std::collections::BTreeMap; -use std::ops::ControlFlow; - pub use rustc_middle::traits::Reveal; pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; @@ -52,55 +48,6 @@ pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::AliasTy<'tcx>>; pub(super) struct InProgress; -#[extension(pub trait NormalizeExt<'tcx>)] -impl<'tcx> At<'_, 'tcx> { - /// Normalize a value using the `AssocTypeNormalizer`. - /// - /// This normalization should be used when the type contains inference variables or the - /// projection may be fallible. - fn normalize>>(&self, value: T) -> InferOk<'tcx, T> { - if self.infcx.next_trait_solver() { - InferOk { value, obligations: Vec::new() } - } else { - let mut selcx = SelectionContext::new(self.infcx); - let Normalized { value, obligations } = - normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value); - InferOk { value, obligations } - } - } - - /// Deeply normalizes `value`, replacing all aliases which can by normalized in - /// the current environment. In the new solver this errors in case normalization - /// fails or is ambiguous. This only normalizes opaque types with `Reveal::All`. - /// - /// In the old solver this simply uses `normalizes` and adds the nested obligations - /// to the `fulfill_cx`. This is necessary as we otherwise end up recomputing the - /// same goals in both a temporary and the shared context which negatively impacts - /// performance as these don't share caching. - /// - /// FIXME(-Znext-solver): This has the same behavior as `traits::fully_normalize` - /// in the new solver, but because of performance reasons, we currently reuse an - /// existing fulfillment context in the old solver. Once we also eagerly prove goals with - /// the old solver or have removed the old solver, remove `traits::fully_normalize` and - /// rename this function to `At::fully_normalize`. - fn deeply_normalize>>( - self, - value: T, - fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Result>> { - if self.infcx.next_trait_solver() { - crate::solve::deeply_normalize(self, value) - } else { - let value = self - .normalize(value) - .into_value_registering_obligations(self.infcx, &mut *fulfill_cx); - let errors = fulfill_cx.select_where_possible(self.infcx); - let value = self.infcx.resolve_vars_if_possible(value); - if errors.is_empty() { Ok(value) } else { Err(errors) } - } - } -} - /// When attempting to resolve `::Name` ... #[derive(Debug)] pub enum ProjectionError<'tcx> { @@ -338,700 +285,6 @@ fn project_and_unify_type<'cx, 'tcx>( } } -/// As `normalize`, but with a custom depth. -pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: T, -) -> Normalized<'tcx, T> -where - T: TypeFoldable>, -{ - let mut obligations = Vec::new(); - let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations); - Normalized { value, obligations } -} - -#[instrument(level = "info", skip(selcx, param_env, cause, obligations))] -pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: T, - obligations: &mut Vec>, -) -> T -where - T: TypeFoldable>, -{ - debug!(obligations.len = obligations.len()); - let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); - let result = ensure_sufficient_stack(|| normalizer.fold(value)); - debug!(?result, obligations.len = normalizer.obligations.len()); - debug!(?normalizer.obligations,); - result -} - -pub(crate) fn needs_normalization<'tcx, T: TypeVisitable>>( - value: &T, - reveal: Reveal, -) -> bool { - match reveal { - Reveal::UserFacing => value.has_type_flags( - ty::TypeFlags::HAS_TY_PROJECTION - | ty::TypeFlags::HAS_TY_INHERENT - | ty::TypeFlags::HAS_CT_PROJECTION, - ), - Reveal::All => value.has_type_flags( - ty::TypeFlags::HAS_TY_PROJECTION - | ty::TypeFlags::HAS_TY_INHERENT - | ty::TypeFlags::HAS_TY_OPAQUE - | ty::TypeFlags::HAS_CT_PROJECTION, - ), - } -} - -struct AssocTypeNormalizer<'a, 'b, 'tcx> { - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - obligations: &'a mut Vec>, - depth: usize, - universes: Vec>, -} - -impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { - fn new( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &'a mut Vec>, - ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { - debug_assert!(!selcx.infcx.next_trait_solver()); - AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] } - } - - fn fold>>(&mut self, value: T) -> T { - let value = self.selcx.infcx.resolve_vars_if_possible(value); - debug!(?value); - - assert!( - !value.has_escaping_bound_vars(), - "Normalizing {value:?} without wrapping in a `Binder`" - ); - - if !needs_normalization(&value, self.param_env.reveal()) { - value - } else { - value.fold_with(self) - } - } -} - -impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.selcx.tcx() - } - - fn fold_binder>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - self.universes.push(None); - let t = t.super_fold_with(self); - self.universes.pop(); - t - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !needs_normalization(&ty, self.param_env.reveal()) { - return ty; - } - - let (kind, data) = match *ty.kind() { - ty::Alias(kind, alias_ty) => (kind, alias_ty), - _ => return ty.super_fold_with(self), - }; - - // We try to be a little clever here as a performance optimization in - // cases where there are nested projections under binders. - // For example: - // ``` - // for<'a> fn(::One<'a, Box::Two<'a>>>>) - // ``` - // We normalize the args on the projection before the projecting, but - // if we're naive, we'll - // replace bound vars on inner, project inner, replace placeholders on inner, - // replace bound vars on outer, project outer, replace placeholders on outer - // - // However, if we're a bit more clever, we can replace the bound vars - // on the entire type before normalizing nested projections, meaning we - // replace bound vars on outer, project inner, - // project outer, replace placeholders on outer - // - // This is possible because the inner `'a` will already be a placeholder - // when we need to normalize the inner projection - // - // On the other hand, this does add a bit of complexity, since we only - // replace bound vars if the current type is a `Projection` and we need - // to make sure we don't forget to fold the args regardless. - - match kind { - ty::Opaque => { - // Only normalize `impl Trait` outside of type inference, usually in codegen. - match self.param_env.reveal() { - Reveal::UserFacing => ty.super_fold_with(self), - - Reveal::All => { - let recursion_limit = self.interner().recursion_limit(); - if !recursion_limit.value_within_limit(self.depth) { - self.selcx.infcx.err_ctxt().report_overflow_error( - &ty, - self.cause.span, - true, - |_| {}, - ); - } - - let args = data.args.fold_with(self); - let generic_ty = self.interner().type_of(data.def_id); - let concrete_ty = generic_ty.instantiate(self.interner(), args); - self.depth += 1; - let folded_ty = self.fold_ty(concrete_ty); - self.depth -= 1; - folded_ty - } - } - } - - ty::Projection if !data.has_escaping_bound_vars() => { - // This branch is *mostly* just an optimization: when we don't - // have escaping bound vars, we don't need to replace them with - // placeholders (see branch below). *Also*, we know that we can - // register an obligation to *later* project, since we know - // there won't be bound vars there. - let data = data.fold_with(self); - let normalized_ty = normalize_projection_type( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ); - debug!( - ?self.depth, - ?ty, - ?normalized_ty, - obligations.len = ?self.obligations.len(), - "AssocTypeNormalizer: normalized type" - ); - normalized_ty.ty().unwrap() - } - - ty::Projection => { - // If there are escaping bound vars, we temporarily replace the - // bound vars with placeholders. Note though, that in the case - // that we still can't project for whatever reason (e.g. self - // type isn't known enough), we *can't* register an obligation - // and return an inference variable (since then that obligation - // would have bound vars and that's a can of worms). Instead, - // we just give up and fall back to pretending like we never tried! - // - // Note: this isn't necessarily the final approach here; we may - // want to figure out how to register obligations with escaping vars - // or handle this some other way. - - let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); - let normalized_ty = opt_normalize_projection_type( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ) - .ok() - .flatten() - .map(|term| term.ty().unwrap()) - .map(|normalized_ty| { - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - normalized_ty, - ) - }) - .unwrap_or_else(|| ty.super_fold_with(self)); - - debug!( - ?self.depth, - ?ty, - ?normalized_ty, - obligations.len = ?self.obligations.len(), - "AssocTypeNormalizer: normalized type" - ); - normalized_ty - } - ty::Weak => { - let recursion_limit = self.interner().recursion_limit(); - if !recursion_limit.value_within_limit(self.depth) { - self.selcx.infcx.err_ctxt().report_overflow_error( - &ty, - self.cause.span, - false, - |diag| { - diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow); - }, - ); - } - - let infcx = self.selcx.infcx; - self.obligations.extend( - infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( - |(mut predicate, span)| { - if data.has_escaping_bound_vars() { - (predicate, ..) = BoundVarReplacer::replace_bound_vars( - infcx, - &mut self.universes, - predicate, - ); - } - let mut cause = self.cause.clone(); - cause.map_code(|code| { - ObligationCauseCode::TypeAlias(code, span, data.def_id) - }); - Obligation::new(infcx.tcx, cause, self.param_env, predicate) - }, - ), - ); - self.depth += 1; - let res = infcx - .tcx - .type_of(data.def_id) - .instantiate(infcx.tcx, data.args) - .fold_with(self); - self.depth -= 1; - res - } - - ty::Inherent if !data.has_escaping_bound_vars() => { - // This branch is *mostly* just an optimization: when we don't - // have escaping bound vars, we don't need to replace them with - // placeholders (see branch below). *Also*, we know that we can - // register an obligation to *later* project, since we know - // there won't be bound vars there. - - let data = data.fold_with(self); - - // FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement` - // here like `ty::Projection`? - normalize_inherent_projection( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ) - } - - ty::Inherent => { - let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); - let ty = normalize_inherent_projection( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ); - - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - ty, - ) - } - } - } - - #[instrument(skip(self), level = "debug")] - fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { - let tcx = self.selcx.tcx(); - if tcx.features().generic_const_exprs - || !needs_normalization(&constant, self.param_env.reveal()) - { - constant - } else { - let constant = constant.super_fold_with(self); - debug!(?constant, ?self.param_env); - with_replaced_escaping_bound_vars( - self.selcx.infcx, - &mut self.universes, - constant, - |constant| constant.normalize(tcx, self.param_env), - ) - } - } - - #[inline] - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { - p.super_fold_with(self) - } else { - p - } - } -} - -pub struct BoundVarReplacer<'me, 'tcx> { - infcx: &'me InferCtxt<'tcx>, - // These three maps track the bound variable that were replaced by placeholders. It might be - // nice to remove these since we already have the `kind` in the placeholder; we really just need - // the `var` (but we *could* bring that into scope if we were to track them as we pass them). - mapped_regions: BTreeMap, - mapped_types: BTreeMap, - mapped_consts: BTreeMap, - // The current depth relative to *this* folding, *not* the entire normalization. In other words, - // the depth of binders we've passed here. - current_index: ty::DebruijnIndex, - // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy: - // we don't actually create a universe until we see a bound var we have to replace. - universe_indices: &'me mut Vec>, -} - -/// Executes `f` on `value` after replacing all escaping bound variables with placeholders -/// and then replaces these placeholders with the original bound variables in the result. -/// -/// In most places, bound variables should be replaced right when entering a binder, making -/// this function unnecessary. However, normalization currently does not do that, so we have -/// to do this lazily. -/// -/// You should not add any additional uses of this function, at least not without first -/// discussing it with t-types. -/// -/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during -/// normalization as well, at which point this function will be unnecessary and can be removed. -pub fn with_replaced_escaping_bound_vars< - 'a, - 'tcx, - T: TypeFoldable>, - R: TypeFoldable>, ->( - infcx: &'a InferCtxt<'tcx>, - universe_indices: &'a mut Vec>, - value: T, - f: impl FnOnce(T) -> R, -) -> R { - if value.has_escaping_bound_vars() { - let (value, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value); - let result = f(value); - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - universe_indices, - result, - ) - } else { - f(value) - } -} - -impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { - /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that - /// use a binding level above `universe_indices.len()`, we fail. - pub fn replace_bound_vars>>( - infcx: &'me InferCtxt<'tcx>, - universe_indices: &'me mut Vec>, - value: T, - ) -> ( - T, - BTreeMap, - BTreeMap, - BTreeMap, - ) { - let mapped_regions: BTreeMap = BTreeMap::new(); - let mapped_types: BTreeMap = BTreeMap::new(); - let mapped_consts: BTreeMap = BTreeMap::new(); - - let mut replacer = BoundVarReplacer { - infcx, - mapped_regions, - mapped_types, - mapped_consts, - current_index: ty::INNERMOST, - universe_indices, - }; - - let value = value.fold_with(&mut replacer); - - (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts) - } - - fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex { - let infcx = self.infcx; - let index = - self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1; - let universe = self.universe_indices[index].unwrap_or_else(|| { - for i in self.universe_indices.iter_mut().take(index + 1) { - *i = i.or_else(|| Some(infcx.create_next_universe())) - } - self.universe_indices[index].unwrap() - }); - universe - } -} - -impl<'tcx> TypeFolder> for BoundVarReplacer<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_binder>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReBound(debruijn, _) - if debruijn.as_usize() - >= self.current_index.as_usize() + self.universe_indices.len() => - { - bug!( - "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}", - self.universe_indices - ); - } - ty::ReBound(debruijn, br) if debruijn >= self.current_index => { - let universe = self.universe_for(debruijn); - let p = ty::PlaceholderRegion { universe, bound: br }; - self.mapped_regions.insert(p, br); - ty::Region::new_placeholder(self.infcx.tcx, p) - } - _ => r, - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match *t.kind() { - ty::Bound(debruijn, _) - if debruijn.as_usize() + 1 - > self.current_index.as_usize() + self.universe_indices.len() => - { - bug!( - "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}", - self.universe_indices - ); - } - ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { - let universe = self.universe_for(debruijn); - let p = ty::PlaceholderType { universe, bound: bound_ty }; - self.mapped_types.insert(p, bound_ty); - Ty::new_placeholder(self.infcx.tcx, p) - } - _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), - _ => t, - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - match ct.kind() { - ty::ConstKind::Bound(debruijn, _) - if debruijn.as_usize() + 1 - > self.current_index.as_usize() + self.universe_indices.len() => - { - bug!( - "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}", - self.universe_indices - ); - } - ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { - let universe = self.universe_for(debruijn); - let p = ty::PlaceholderConst { universe, bound: bound_const }; - self.mapped_consts.insert(p, bound_const); - ty::Const::new_placeholder(self.infcx.tcx, p, ct.ty()) - } - _ => ct.super_fold_with(self), - } - } - - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } - } -} - -/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came. -pub struct PlaceholderReplacer<'me, 'tcx> { - infcx: &'me InferCtxt<'tcx>, - mapped_regions: BTreeMap, - mapped_types: BTreeMap, - mapped_consts: BTreeMap, - universe_indices: &'me [Option], - current_index: ty::DebruijnIndex, -} - -impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { - pub fn replace_placeholders>>( - infcx: &'me InferCtxt<'tcx>, - mapped_regions: BTreeMap, - mapped_types: BTreeMap, - mapped_consts: BTreeMap, - universe_indices: &'me [Option], - value: T, - ) -> T { - let mut replacer = PlaceholderReplacer { - infcx, - mapped_regions, - mapped_types, - mapped_consts, - universe_indices, - current_index: ty::INNERMOST, - }; - value.fold_with(&mut replacer) - } -} - -impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_binder>>( - &mut self, - t: ty::Binder<'tcx, T>, - ) -> ty::Binder<'tcx, T> { - if !t.has_placeholders() && !t.has_infer() { - return t; - } - self.current_index.shift_in(1); - let t = t.super_fold_with(self); - self.current_index.shift_out(1); - t - } - - fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { - let r1 = match *r0 { - ty::ReVar(vid) => self - .infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .opportunistic_resolve_var(self.infcx.tcx, vid), - _ => r0, - }; - - let r2 = match *r1 { - ty::RePlaceholder(p) => { - let replace_var = self.mapped_regions.get(&p); - match replace_var { - Some(replace_var) => { - let index = self - .universe_indices - .iter() - .position(|u| matches!(u, Some(pu) if *pu == p.universe)) - .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); - let db = ty::DebruijnIndex::from_usize( - self.universe_indices.len() - index + self.current_index.as_usize() - 1, - ); - ty::Region::new_bound(self.interner(), db, *replace_var) - } - None => r1, - } - } - _ => r1, - }; - - debug!(?r0, ?r1, ?r2, "fold_region"); - - r2 - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.infcx.shallow_resolve(ty); - match *ty.kind() { - ty::Placeholder(p) => { - let replace_var = self.mapped_types.get(&p); - match replace_var { - Some(replace_var) => { - let index = self - .universe_indices - .iter() - .position(|u| matches!(u, Some(pu) if *pu == p.universe)) - .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); - let db = ty::DebruijnIndex::from_usize( - self.universe_indices.len() - index + self.current_index.as_usize() - 1, - ); - Ty::new_bound(self.infcx.tcx, db, *replace_var) - } - None => { - if ty.has_infer() { - ty.super_fold_with(self) - } else { - ty - } - } - } - } - - _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self), - _ => ty, - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - let ct = self.infcx.shallow_resolve(ct); - if let ty::ConstKind::Placeholder(p) = ct.kind() { - let replace_var = self.mapped_consts.get(&p); - match replace_var { - Some(replace_var) => { - let index = self - .universe_indices - .iter() - .position(|u| matches!(u, Some(pu) if *pu == p.universe)) - .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); - let db = ty::DebruijnIndex::from_usize( - self.universe_indices.len() - index + self.current_index.as_usize() - 1, - ); - ty::Const::new_bound(self.infcx.tcx, db, *replace_var, ct.ty()) - } - None => { - if ct.has_infer() { - ct.super_fold_with(self) - } else { - ct - } - } - } - } else { - ct.super_fold_with(self) - } - } -} - /// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly /// additional obligations). If ambiguity arises, which implies that @@ -1076,7 +329,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>( /// function takes an obligations vector and appends to it directly, which is /// slightly uglier but avoids the need for an extra short-lived allocation. #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] -fn opt_normalize_projection_type<'a, 'b, 'tcx>( +pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, projection_ty: ty::AliasTy<'tcx>, @@ -1180,14 +433,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term); let mut result = if projected_term.has_projections() { - let mut normalizer = AssocTypeNormalizer::new( + let normalized_ty = normalize_with_depth_to( selcx, param_env, cause, depth + 1, + projected_term, &mut projected_obligations, ); - let normalized_ty = normalizer.fold(projected_term); Normalized { value: normalized_ty, obligations: projected_obligations } } else { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 0f6c0abd280..26da065246d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -6,7 +6,8 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::TypeErrCtxtExt; -use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; +use crate::traits::normalize::needs_normalization; +use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; use crate::traits::{ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -335,7 +336,7 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> let constant = constant.try_super_fold_with(self)?; debug!(?constant, ?self.param_env); - Ok(crate::traits::project::with_replaced_escaping_bound_vars( + Ok(crate::traits::with_replaced_escaping_bound_vars( self.infcx, &mut self.universes, constant, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index e4a70c537d2..f76be876948 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{ }; use rustc_span::def_id::DefId; -use crate::traits::project::{normalize_with_depth, normalize_with_depth_to}; +use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::vtable::{ count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c2566f27c1f..65cb9e1c1f4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -8,7 +8,6 @@ use self::SelectionCandidate::*; use super::coherence::{self, Conflict}; use super::const_evaluatable; use super::project; -use super::project::normalize_with_depth_to; use super::project::ProjectionTyObligation; use super::util; use super::util::closure_trait_ref_and_return_type; @@ -22,6 +21,8 @@ use super::{ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt; use crate::traits::error_reporting::TypeErrCtxtExt; +use crate::traits::normalize::normalize_with_depth; +use crate::traits::normalize::normalize_with_depth_to; use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; @@ -1661,7 +1662,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| { - project::normalize_with_depth( + normalize_with_depth( self, obligation.param_env, obligation.cause.clone(), @@ -1717,7 +1718,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); let infer_projection = if potentially_unnormalized_candidates { ensure_sufficient_stack(|| { - project::normalize_with_depth_to( + normalize_with_depth_to( self, obligation.param_env, obligation.cause.clone(), @@ -2382,7 +2383,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let placeholder_ty = self.infcx.enter_forall_and_leak_universe(ty); let Normalized { value: normalized_ty, mut obligations } = ensure_sufficient_stack(|| { - project::normalize_with_depth( + normalize_with_depth( self, param_env, cause.clone(), @@ -2479,7 +2480,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = ensure_sufficient_stack(|| { - project::normalize_with_depth( + normalize_with_depth( self, obligation.param_env, obligation.cause.clone(), diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index af172eb0713..23c86a2feef 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,11 +1,14 @@ +use std::collections::BTreeMap; + use super::NormalizeExt; use super::{ObligationCause, PredicateObligation, SelectionContext}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::DefId; -use rustc_infer::infer::InferOk; +use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_span::Span; use smallvec::SmallVec; @@ -382,3 +385,336 @@ pub fn check_args_compatible<'tcx>( let args = &args[0..generics.count().min(args.len())]; check_args_compatible_inner(tcx, generics, args) } + +/// Executes `f` on `value` after replacing all escaping bound variables with placeholders +/// and then replaces these placeholders with the original bound variables in the result. +/// +/// In most places, bound variables should be replaced right when entering a binder, making +/// this function unnecessary. However, normalization currently does not do that, so we have +/// to do this lazily. +/// +/// You should not add any additional uses of this function, at least not without first +/// discussing it with t-types. +/// +/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during +/// normalization as well, at which point this function will be unnecessary and can be removed. +pub fn with_replaced_escaping_bound_vars< + 'a, + 'tcx, + T: TypeFoldable>, + R: TypeFoldable>, +>( + infcx: &'a InferCtxt<'tcx>, + universe_indices: &'a mut Vec>, + value: T, + f: impl FnOnce(T) -> R, +) -> R { + if value.has_escaping_bound_vars() { + let (value, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value); + let result = f(value); + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + universe_indices, + result, + ) + } else { + f(value) + } +} + +pub struct BoundVarReplacer<'me, 'tcx> { + infcx: &'me InferCtxt<'tcx>, + // These three maps track the bound variable that were replaced by placeholders. It might be + // nice to remove these since we already have the `kind` in the placeholder; we really just need + // the `var` (but we *could* bring that into scope if we were to track them as we pass them). + mapped_regions: BTreeMap, + mapped_types: BTreeMap, + mapped_consts: BTreeMap, + // The current depth relative to *this* folding, *not* the entire normalization. In other words, + // the depth of binders we've passed here. + current_index: ty::DebruijnIndex, + // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy: + // we don't actually create a universe until we see a bound var we have to replace. + universe_indices: &'me mut Vec>, +} + +impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { + /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that + /// use a binding level above `universe_indices.len()`, we fail. + pub fn replace_bound_vars>>( + infcx: &'me InferCtxt<'tcx>, + universe_indices: &'me mut Vec>, + value: T, + ) -> ( + T, + BTreeMap, + BTreeMap, + BTreeMap, + ) { + let mapped_regions: BTreeMap = BTreeMap::new(); + let mapped_types: BTreeMap = BTreeMap::new(); + let mapped_consts: BTreeMap = BTreeMap::new(); + + let mut replacer = BoundVarReplacer { + infcx, + mapped_regions, + mapped_types, + mapped_consts, + current_index: ty::INNERMOST, + universe_indices, + }; + + let value = value.fold_with(&mut replacer); + + (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts) + } + + fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex { + let infcx = self.infcx; + let index = + self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1; + let universe = self.universe_indices[index].unwrap_or_else(|| { + for i in self.universe_indices.iter_mut().take(index + 1) { + *i = i.or_else(|| Some(infcx.create_next_universe())) + } + self.universe_indices[index].unwrap() + }); + universe + } +} + +impl<'tcx> TypeFolder> for BoundVarReplacer<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_binder>>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + ty::ReBound(debruijn, _) + if debruijn.as_usize() + >= self.current_index.as_usize() + self.universe_indices.len() => + { + bug!( + "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); + } + ty::ReBound(debruijn, br) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = ty::PlaceholderRegion { universe, bound: br }; + self.mapped_regions.insert(p, br); + ty::Region::new_placeholder(self.infcx.tcx, p) + } + _ => r, + } + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match *t.kind() { + ty::Bound(debruijn, _) + if debruijn.as_usize() + 1 + > self.current_index.as_usize() + self.universe_indices.len() => + { + bug!( + "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); + } + ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = ty::PlaceholderType { universe, bound: bound_ty }; + self.mapped_types.insert(p, bound_ty); + Ty::new_placeholder(self.infcx.tcx, p) + } + _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), + _ => t, + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + match ct.kind() { + ty::ConstKind::Bound(debruijn, _) + if debruijn.as_usize() + 1 + > self.current_index.as_usize() + self.universe_indices.len() => + { + bug!( + "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); + } + ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { + let universe = self.universe_for(debruijn); + let p = ty::PlaceholderConst { universe, bound: bound_const }; + self.mapped_consts.insert(p, bound_const); + ty::Const::new_placeholder(self.infcx.tcx, p, ct.ty()) + } + _ => ct.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } + } +} + +/// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came. +pub struct PlaceholderReplacer<'me, 'tcx> { + infcx: &'me InferCtxt<'tcx>, + mapped_regions: BTreeMap, + mapped_types: BTreeMap, + mapped_consts: BTreeMap, + universe_indices: &'me [Option], + current_index: ty::DebruijnIndex, +} + +impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { + pub fn replace_placeholders>>( + infcx: &'me InferCtxt<'tcx>, + mapped_regions: BTreeMap, + mapped_types: BTreeMap, + mapped_consts: BTreeMap, + universe_indices: &'me [Option], + value: T, + ) -> T { + let mut replacer = PlaceholderReplacer { + infcx, + mapped_regions, + mapped_types, + mapped_consts, + universe_indices, + current_index: ty::INNERMOST, + }; + value.fold_with(&mut replacer) + } +} + +impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_binder>>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { + if !t.has_placeholders() && !t.has_infer() { + return t; + } + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { + let r1 = match *r0 { + ty::ReVar(vid) => self + .infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(self.infcx.tcx, vid), + _ => r0, + }; + + let r2 = match *r1 { + ty::RePlaceholder(p) => { + let replace_var = self.mapped_regions.get(&p); + match replace_var { + Some(replace_var) => { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(pu) if *pu == p.universe)) + .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); + let db = ty::DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ); + ty::Region::new_bound(self.interner(), db, *replace_var) + } + None => r1, + } + } + _ => r1, + }; + + debug!(?r0, ?r1, ?r2, "fold_region"); + + r2 + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.infcx.shallow_resolve(ty); + match *ty.kind() { + ty::Placeholder(p) => { + let replace_var = self.mapped_types.get(&p); + match replace_var { + Some(replace_var) => { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(pu) if *pu == p.universe)) + .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); + let db = ty::DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ); + Ty::new_bound(self.infcx.tcx, db, *replace_var) + } + None => { + if ty.has_infer() { + ty.super_fold_with(self) + } else { + ty + } + } + } + } + + _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self), + _ => ty, + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + let ct = self.infcx.shallow_resolve(ct); + if let ty::ConstKind::Placeholder(p) = ct.kind() { + let replace_var = self.mapped_consts.get(&p); + match replace_var { + Some(replace_var) => { + let index = self + .universe_indices + .iter() + .position(|u| matches!(u, Some(pu) if *pu == p.universe)) + .unwrap_or_else(|| bug!("Unexpected placeholder universe.")); + let db = ty::DebruijnIndex::from_usize( + self.universe_indices.len() - index + self.current_index.as_usize() - 1, + ); + ty::Const::new_bound(self.infcx.tcx, db, *replace_var, ct.ty()) + } + None => { + if ct.has_infer() { + ct.super_fold_with(self) + } else { + ct + } + } + } + } else { + ct.super_fold_with(self) + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index c727ef53d55..15059bc6613 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -313,7 +313,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // Don't normalize the whole obligation, the param env is either // already normalized, or we're currently normalizing the // param_env. Either way we should only normalize the predicate. - let normalized_predicate = traits::project::normalize_with_depth_to( + let normalized_predicate = traits::normalize::normalize_with_depth_to( &mut selcx, param_env, cause.clone(), -- cgit 1.4.1-3-g733a5 From 0c7672a5322ad9de365e383b4f6235a9a6dce5aa Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 5 Feb 2024 13:45:01 +0100 Subject: remove outdated comment --- compiler/rustc_trait_selection/src/traits/normalize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'compiler') diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 0df6f36f115..ac62f875fb9 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -31,7 +31,7 @@ impl<'tcx> At<'_, 'tcx> { /// Deeply normalizes `value`, replacing all aliases which can by normalized in /// the current environment. In the new solver this errors in case normalization - /// fails or is ambiguous. This only normalizes opaque types with `Reveal::All`. + /// fails or is ambiguous. /// /// In the old solver this simply uses `normalizes` and adds the nested obligations /// to the `fulfill_cx`. This is necessary as we otherwise end up recomputing the -- cgit 1.4.1-3-g733a5 From b18f3e11fa9c2d6fb8a6c4807229bebc3608d3ac Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Feb 2024 10:13:24 +1100 Subject: Prefer `DiagnosticBuilder` over `Diagnostic` in diagnostic modifiers. There are lots of functions that modify a diagnostic. This can be via a `&mut Diagnostic` or a `&mut DiagnosticBuilder`, because the latter type wraps the former and impls `DerefMut`. This commit converts all the `&mut Diagnostic` occurrences to `&mut DiagnosticBuilder`. This is a step towards greatly simplifying `Diagnostic`. Some of the relevant function are made generic, because they deal with both errors and warnings. No function bodies are changed, because all the modifier methods are available on both `Diagnostic` and `DiagnosticBuilder`. --- .../src/diagnostics/conflict_errors.rs | 35 +++-- .../src/diagnostics/explain_borrow.rs | 8 +- compiler/rustc_borrowck/src/diagnostics/mod.rs | 12 +- .../rustc_borrowck/src/diagnostics/move_errors.rs | 17 ++- .../src/diagnostics/mutability_errors.rs | 17 ++- .../src/diagnostics/outlives_suggestion.rs | 6 +- .../src/diagnostics/region_errors.rs | 12 +- .../rustc_borrowck/src/diagnostics/region_name.rs | 4 +- compiler/rustc_borrowck/src/region_infer/mod.rs | 4 +- compiler/rustc_borrowck/src/universal_regions.rs | 4 +- compiler/rustc_errors/src/lib.rs | 4 +- compiler/rustc_expand/src/mbe/diagnostics.rs | 10 +- compiler/rustc_hir_analysis/src/astconv/errors.rs | 6 +- .../rustc_hir_analysis/src/astconv/generics.rs | 4 +- compiler/rustc_hir_analysis/src/astconv/lint.rs | 12 +- compiler/rustc_hir_analysis/src/astconv/mod.rs | 6 +- compiler/rustc_hir_analysis/src/check/check.rs | 2 +- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../wrong_number_of_generic_args.rs | 28 ++-- compiler/rustc_hir_typeck/src/_match.rs | 8 +- compiler/rustc_hir_typeck/src/callee.rs | 8 +- compiler/rustc_hir_typeck/src/cast.rs | 8 +- compiler/rustc_hir_typeck/src/coercion.rs | 10 +- compiler/rustc_hir_typeck/src/demand.rs | 18 +-- compiler/rustc_hir_typeck/src/expr.rs | 20 +-- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 4 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 4 +- .../rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 74 ++++++----- compiler/rustc_hir_typeck/src/method/mod.rs | 4 +- compiler/rustc_hir_typeck/src/method/suggest.rs | 43 ++++--- compiler/rustc_hir_typeck/src/op.rs | 4 +- compiler/rustc_hir_typeck/src/pat.rs | 12 +- .../rustc_infer/src/infer/error_reporting/mod.rs | 32 +++-- .../nice_region_error/different_lifetimes.rs | 4 +- .../nice_region_error/static_impl_trait.rs | 8 +- .../rustc_infer/src/infer/error_reporting/note.rs | 10 +- .../src/infer/error_reporting/note_and_explain.rs | 18 +-- .../src/infer/error_reporting/suggest.rs | 16 +-- compiler/rustc_middle/src/lint.rs | 8 +- compiler/rustc_middle/src/middle/stability.rs | 4 +- compiler/rustc_middle/src/traits/mod.rs | 4 +- compiler/rustc_middle/src/ty/diagnostics.rs | 8 +- compiler/rustc_parse/src/lexer/diagnostics.rs | 6 +- compiler/rustc_parse/src/parser/attr.rs | 4 +- compiler/rustc_parse/src/parser/diagnostics.rs | 12 +- compiler/rustc_parse/src/parser/expr.rs | 8 +- compiler/rustc_resolve/src/diagnostics.rs | 16 +-- compiler/rustc_resolve/src/late/diagnostics.rs | 143 ++++++++++++--------- compiler/rustc_session/src/parse.rs | 13 +- .../rustc_trait_selection/src/traits/coherence.rs | 4 +- .../src/traits/error_reporting/suggestions.rs | 113 ++++++++-------- .../traits/error_reporting/type_err_ctxt_ext.rs | 45 ++++--- .../rustc_trait_selection/src/traits/select/mod.rs | 7 +- .../src/traits/specialize/mod.rs | 6 +- compiler/rustc_trait_selection/src/traits/util.rs | 4 +- src/librustdoc/passes/collect_intra_doc_links.rs | 37 +++--- .../src/casts/cast_possible_truncation.rs | 4 +- .../clippy/clippy_lints/src/functions/result.rs | 4 +- src/tools/clippy/clippy_lints/src/if_let_mutex.rs | 4 +- .../clippy/clippy_lints/src/implicit_hasher.rs | 4 +- src/tools/clippy/clippy_lints/src/manual_clamp.rs | 4 +- .../src/matches/significant_drop_in_scrutinee.rs | 4 +- .../src/methods/suspicious_command_arg_space.rs | 4 +- .../src/missing_asserts_for_indexing.rs | 4 +- .../clippy_lints/src/needless_pass_by_value.rs | 4 +- src/tools/clippy/clippy_utils/src/diagnostics.rs | 12 +- 66 files changed, 535 insertions(+), 453 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2b0c0e939f5..e1509da913a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -6,9 +6,7 @@ use either::Either; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{ - codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, -}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; @@ -635,7 +633,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn suggest_assign_value( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, moved_place: PlaceRef<'tcx>, sugg_span: Span, ) { @@ -674,7 +672,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn suggest_borrow_fn_like( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ty: Ty<'tcx>, move_sites: &[MoveSite], value_name: &str, @@ -742,7 +740,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn suggest_cloning( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, span: Span, @@ -778,7 +776,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) { + fn suggest_adding_copy_bounds( + &self, + err: &mut DiagnosticBuilder<'_>, + ty: Ty<'tcx>, + span: Span, + ) { let tcx = self.infcx.tcx; let generics = tcx.generics_of(self.mir_def_id()); @@ -1225,7 +1228,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { #[instrument(level = "debug", skip(self, err))] fn suggest_using_local_if_applicable( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, location: Location, issued_borrow: &BorrowData<'tcx>, explanation: BorrowExplanation<'tcx>, @@ -1321,7 +1324,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn suggest_slice_method_if_applicable( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, place: Place<'tcx>, borrowed_place: Place<'tcx>, ) { @@ -1430,7 +1433,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// ``` pub(crate) fn explain_iterator_advancement_in_for_loop_if_applicable( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, span: Span, issued_spans: &UseSpans<'tcx>, ) { @@ -1617,7 +1620,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// ``` fn suggest_using_closure_argument_instead_of_capture( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, borrowed_place: Place<'tcx>, issued_spans: &UseSpans<'tcx>, ) { @@ -1751,7 +1754,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn suggest_binding_for_closure_capture_self( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, issued_spans: &UseSpans<'tcx>, ) { let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return }; @@ -2997,7 +3000,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.buffer_error(err); } - fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) { + fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) { let tcx = self.infcx.tcx; if let ( Some(Terminator { @@ -3532,7 +3535,11 @@ enum AnnotatedBorrowFnSignature<'tcx> { impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { /// Annotate the provided diagnostic with information about borrow from the fn signature that /// helps explain. - pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diagnostic) -> String { + pub(crate) fn emit( + &self, + cx: &mut MirBorrowckCtxt<'_, 'tcx>, + diag: &mut DiagnosticBuilder<'_>, + ) -> String { match self { &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => { diag.span_label( diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 483ecee850b..f7b59ec5fe0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -3,7 +3,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_index::IndexSlice; @@ -65,7 +65,7 @@ impl<'tcx> BorrowExplanation<'tcx> { tcx: TyCtxt<'tcx>, body: &Body<'tcx>, local_names: &IndexSlice>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, borrow_desc: &str, borrow_span: Option, multiple_borrow_span: Option<(Span, Span)>, @@ -306,7 +306,7 @@ impl<'tcx> BorrowExplanation<'tcx> { fn add_object_lifetime_default_note( &self, tcx: TyCtxt<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, unsize_ty: Ty<'tcx>, ) { if let ty::Adt(def, args) = unsize_ty.kind() { @@ -359,7 +359,7 @@ impl<'tcx> BorrowExplanation<'tcx> { fn add_lifetime_bound_suggestion_to_diagnostic( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, category: &ConstraintCategory<'tcx>, span: Span, region_name: &RegionName, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 4ca854c857d..db0d69b6eaa 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -5,7 +5,7 @@ use crate::session_diagnostics::{ CaptureVarKind, CaptureVarPathUseCause, OnClosureNote, }; use itertools::Itertools; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::CoroutineKind; @@ -80,7 +80,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, location: Location, place: PlaceRef<'tcx>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) -> bool { debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); let mut target = place.local_or_deref_local(); @@ -588,7 +588,7 @@ impl UseSpans<'_> { pub(super) fn args_subdiag( self, dcx: &rustc_errors::DiagCtxt, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, f: impl FnOnce(Span) -> CaptureArgLabel, ) { if let UseSpans::ClosureUse { args_span, .. } = self { @@ -601,7 +601,7 @@ impl UseSpans<'_> { pub(super) fn var_path_only_subdiag( self, dcx: &rustc_errors::DiagCtxt, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, action: crate::InitializationRequiringAction, ) { use crate::InitializationRequiringAction::*; @@ -638,7 +638,7 @@ impl UseSpans<'_> { pub(super) fn var_subdiag( self, dcx: &rustc_errors::DiagCtxt, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, kind: Option, f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause, ) { @@ -1010,7 +1010,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn explain_captures( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, span: Span, move_span: Span, move_spans: UseSpans<'tcx>, diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index dad20690d02..3478a73254a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1,7 +1,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; @@ -437,7 +437,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err } - fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) { + fn add_move_hints( + &self, + error: GroupedMoveError<'tcx>, + err: &mut DiagnosticBuilder<'_>, + span: Span, + ) { match error { GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { self.add_borrow_suggestions(err, span); @@ -500,7 +505,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - fn add_borrow_suggestions(&self, err: &mut Diagnostic, span: Span) { + fn add_borrow_suggestions(&self, err: &mut DiagnosticBuilder<'_>, span: Span) { match self.infcx.tcx.sess.source_map().span_to_snippet(span) { Ok(snippet) if snippet.starts_with('*') => { err.span_suggestion_verbose( @@ -521,7 +526,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) { + fn add_move_error_suggestions(&self, err: &mut DiagnosticBuilder<'_>, binds_to: &[Local]) { let mut suggestions: Vec<(Span, String, String)> = Vec::new(); for local in binds_to { let bind_to = &self.body.local_decls[*local]; @@ -573,7 +578,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - fn add_move_error_details(&self, err: &mut Diagnostic, binds_to: &[Local]) { + fn add_move_error_details(&self, err: &mut DiagnosticBuilder<'_>, binds_to: &[Local]) { for (j, local) in binds_to.iter().enumerate() { let bind_to = &self.body.local_decls[*local]; let binding_span = bind_to.source_info.span; @@ -610,7 +615,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// expansion of a packed struct. /// Such errors happen because derive macro expansions shy away from taking /// references to the struct's fields since doing so would be undefined behaviour - fn add_note_for_packed_struct_derive(&self, err: &mut Diagnostic, local: Local) { + fn add_note_for_packed_struct_derive(&self, err: &mut DiagnosticBuilder<'_>, local: Local) { let local_place: PlaceRef<'tcx> = local.into(); let local_ty = local_place.ty(self.body.local_decls(), self.infcx.tcx).ty.peel_refs(); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 514e9c39eb4..b8257ba0adc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -2,7 +2,7 @@ #![allow(rustc::untranslatable_diagnostic)] use hir::ExprKind; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; @@ -540,7 +540,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) { + fn suggest_map_index_mut_alternatives( + &self, + ty: Ty<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + span: Span, + ) { let Some(adt) = ty.ty_adt_def() else { return }; let did = adt.did(); if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did) @@ -548,7 +553,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { struct V<'a, 'tcx> { assign_span: Span, - err: &'a mut Diagnostic, + err: &'a mut DiagnosticBuilder<'tcx>, ty: Ty<'tcx>, suggested: bool, } @@ -790,7 +795,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { tcx: TyCtxt<'_>, closure_local_def_id: hir::def_id::LocalDefId, the_place_err: PlaceRef<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) { let tables = tcx.typeck(closure_local_def_id); if let Some((span, closure_kind_origin)) = tcx.closure_kind_origin(closure_local_def_id) { @@ -852,7 +857,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Attempt to search similar mutable associated items for suggestion. // In the future, attempt in all path but initially for RHS of for_loop - fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic, span: Span) { + fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>, span: Span) { use hir::{ BorrowKind, Expr, ExprKind::{AddrOf, Block, Call, MethodCall}, @@ -936,7 +941,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected. - fn expected_fn_found_fn_mut_call(&self, err: &mut Diagnostic, sp: Span, act: &str) { + fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) { err.span_label(sp, format!("cannot {act}")); let hir = self.infcx.tcx.hir(); diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index 93e28a5f3f3..b2c7a98142e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -5,7 +5,7 @@ #![allow(rustc::untranslatable_diagnostic)] use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::Diagnostic; +use rustc_errors::DiagnosticBuilder; use rustc_middle::ty::RegionVid; use smallvec::SmallVec; use std::collections::BTreeMap; @@ -158,13 +158,13 @@ impl OutlivesSuggestionBuilder { self.constraints_to_add.entry(fr).or_default().push(outlived_fr); } - /// Emit an intermediate note on the given `Diagnostic` if the involved regions are + /// Emit an intermediate note on the given `DiagnosticBuilder` if the involved regions are /// suggestable. pub(crate) fn intermediate_suggestion( &mut self, mbcx: &MirBorrowckCtxt<'_, '_>, errci: &ErrorConstraintInfo<'_>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { // Emit an intermediate note. let fr_name = self.region_vid_to_name(mbcx, errci.fr); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index e8effd5c163..1b88d5046d9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1,7 +1,7 @@ //! Error reporting machinery for lifetime errors. use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::Res::Def; use rustc_hir::def_id::DefId; @@ -808,7 +808,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// ``` fn add_static_impl_trait_suggestion( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, fr: RegionVid, // We need to pass `fr_name` - computing it again will label it twice. fr_name: RegionName, @@ -897,7 +897,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn maybe_suggest_constrain_dyn_trait_impl( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, f: Region<'tcx>, o: Region<'tcx>, category: &ConstraintCategory<'tcx>, @@ -959,7 +959,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { #[instrument(skip(self, err), level = "debug")] fn suggest_constrain_dyn_trait_in_impl( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, found_dids: &FxIndexSet, ident: Ident, self_ty: &hir::Ty<'_>, @@ -994,7 +994,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn suggest_adding_lifetime_params( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, sub: RegionVid, sup: RegionVid, ) { @@ -1023,7 +1023,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { suggest_adding_lifetime_params(self.infcx.tcx, sub, ty_sup, ty_sub, diag); } - fn suggest_move_on_borrowing_closure(&self, diag: &mut Diagnostic) { + fn suggest_move_on_borrowing_closure(&self, diag: &mut DiagnosticBuilder<'_>) { let map = self.infcx.tcx.hir(); let body_id = map.body_owned_by(self.mir_def_id()); let expr = &map.body(body_id).value.peel_blocks(); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index e008d230656..5b235066ea6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -5,7 +5,7 @@ use std::fmt::{self, Display}; use std::iter; use rustc_data_structures::fx::IndexEntry; -use rustc_errors::Diagnostic; +use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::print::RegionHighlightMode; @@ -106,7 +106,7 @@ impl RegionName { } } - pub(crate) fn highlight_region_name(&self, diag: &mut Diagnostic) { + pub(crate) fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) { match &self.source { RegionNameSource::NamedLateParamRegion(span) | RegionNameSource::NamedEarlyParamRegion(span) => { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 34d60fc8f6e..ce2c0dbaff7 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -5,7 +5,7 @@ use rustc_data_structures::binary_search_util; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::scc::Sccs; -use rustc_errors::Diagnostic; +use rustc_errors::DiagnosticBuilder; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::outlives::test_type_match; @@ -592,7 +592,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`. - pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { + pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_, ()>) { self.universal_regions.annotate(tcx, err) } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index a69f5335f71..e7439481034 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -16,7 +16,7 @@ #![allow(rustc::untranslatable_diagnostic)] use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::Diagnostic; +use rustc_errors::DiagnosticBuilder; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::BodyOwnerKind; @@ -343,7 +343,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// that this region imposes on others. The methods in this file /// handle the part about dumping the inference context internal /// state. - pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) { + pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut DiagnosticBuilder<'_, ()>) { match self.defining_ty { DefiningTy::Closure(def_id, args) => { let v = with_no_trimmed_paths!( diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 064ea8d7516..8643596b446 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1745,9 +1745,9 @@ impl Level { } // FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite. -pub fn add_elided_lifetime_in_path_suggestion( +pub fn add_elided_lifetime_in_path_suggestion( source_map: &SourceMap, - diag: &mut DiagnosticBuilder<'_, E>, + diag: &mut DiagnosticBuilder<'_, G>, n: usize, path_span: Span, incl_angl_brckt: bool, diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index e7197c5768b..25af974d326 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -7,7 +7,7 @@ use crate::mbe::{ use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, DiagnosticMessage}; +use rustc_errors::{Applicability, DiagCtxt, DiagnosticBuilder, DiagnosticMessage}; use rustc_parse::parser::{Parser, Recovery}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Ident; @@ -285,7 +285,11 @@ pub(super) fn emit_frag_parse_err( e.emit(); } -pub(crate) fn annotate_err_with_kind(err: &mut Diagnostic, kind: AstFragmentKind, span: Span) { +pub(crate) fn annotate_err_with_kind( + err: &mut DiagnosticBuilder<'_>, + kind: AstFragmentKind, + span: Span, +) { match kind { AstFragmentKind::Ty => { err.span_label(span, "this macro call doesn't expand to a type"); @@ -313,7 +317,7 @@ enum ExplainDocComment { pub(super) fn annotate_doc_comment( dcx: &DiagCtxt, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, sm: &SourceMap, span: Span, ) { diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index ad34c31ef8f..214d9602968 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed, + codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, }; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -371,7 +371,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate. fn note_ambiguous_inherent_assoc_type( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, candidates: Vec, span: Span, ) { @@ -429,7 +429,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let tcx = self.tcx(); let adt_did = self_ty.ty_adt_def().map(|def| def.did()); - let add_def_label = |err: &mut Diagnostic| { + let add_def_label = |err: &mut DiagnosticBuilder<'_>| { if let Some(did) = adt_did { err.span_label( tcx.def_span(did), diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 614e5f9d32b..b20326ae5e1 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -6,7 +6,7 @@ use crate::astconv::{ use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs}; use rustc_ast::ast::ParamKindOrd; use rustc_errors::{ - codes::*, struct_span_code_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, + codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -47,7 +47,7 @@ fn generic_arg_mismatch_err( } } - let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut Diagnostic| { + let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut DiagnosticBuilder<'_>| { let suggestions = vec![ (arg.span().shrink_to_lo(), String::from("{ ")), (arg.span().shrink_to_hi(), String::from(" }")), diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index cee7c84adb2..cee29b152e8 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -1,5 +1,5 @@ use rustc_ast::TraitObjectSyntax; -use rustc_errors::{codes::*, Diagnostic, StashKey}; +use rustc_errors::{codes::*, DiagnosticBuilder, EmissionGuarantee, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability}; @@ -10,10 +10,10 @@ use super::AstConv; impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Make sure that we are in the condition to suggest the blanket implementation. - pub(super) fn maybe_lint_blanket_trait_impl( + pub(super) fn maybe_lint_blanket_trait_impl( &self, self_ty: &hir::Ty<'_>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_, G>, ) { let tcx = self.tcx(); let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; @@ -75,7 +75,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } /// Make sure that we are in the condition to suggest `impl Trait`. - fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) -> bool { + fn maybe_lint_impl_trait( + &self, + self_ty: &hir::Ty<'_>, + diag: &mut DiagnosticBuilder<'_>, + ) -> bool { let tcx = self.tcx(); let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) { diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 3ccf78567ed..6eafdb42226 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -18,8 +18,8 @@ use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{ - codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - FatalError, MultiSpan, + codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, + MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -1725,7 +1725,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn prohibit_generics<'a>( &self, segments: impl Iterator> + Clone, - extend: impl Fn(&mut Diagnostic), + extend: impl Fn(&mut DiagnosticBuilder<'_>), ) -> bool { let args = segments.clone().flat_map(|segment| segment.args().args); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index c3948b1b6bd..b3700013f9c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1248,7 +1248,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) { // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate. // Here `idx` refers to the order of which the discriminant appears, and its index in `vs` - let report = |dis: Discr<'tcx>, idx, err: &mut Diagnostic| { + let report = |dis: Discr<'tcx>, idx, err: &mut DiagnosticBuilder<'_>| { let var = adt.variant(idx); // HIR for the duplicate discriminant let (span, display_discr) = match var.discr { ty::VariantDiscr::Explicit(discr_def_id) => { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b9052672a26..36a92a4cf7c 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -78,7 +78,7 @@ use std::num::NonZero; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::ErrorGuaranteed; -use rustc_errors::{pluralize, struct_span_code_err, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{pluralize, struct_span_code_err, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index f9d57d402b1..8e0c2ea5ca7 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -1,5 +1,5 @@ use crate::structured_errors::StructuredDiagnostic; -use rustc_errors::{codes::*, pluralize, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan}; +use rustc_errors::{codes::*, pluralize, Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; use rustc_session::Session; @@ -525,7 +525,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Builds the `expected 1 type argument / supplied 2 type arguments` message. - fn notify(&self, err: &mut Diagnostic) { + fn notify(&self, err: &mut DiagnosticBuilder<'_>) { let (quantifier, bound) = self.get_quantifier_and_bound(); let provided_args = self.num_provided_args(); @@ -577,7 +577,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest(&self, err: &mut Diagnostic) { + fn suggest(&self, err: &mut DiagnosticBuilder<'_>) { debug!( "suggest(self.provided {:?}, self.gen_args.span(): {:?})", self.num_provided_args(), @@ -605,7 +605,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```text /// type Map = HashMap; /// ``` - fn suggest_adding_args(&self, err: &mut Diagnostic) { + fn suggest_adding_args(&self, err: &mut DiagnosticBuilder<'_>) { if self.gen_args.parenthesized != hir::GenericArgsParentheses::No { return; } @@ -624,7 +624,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_adding_lifetime_args(&self, err: &mut Diagnostic) { + fn suggest_adding_lifetime_args(&self, err: &mut DiagnosticBuilder<'_>) { debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment); let num_missing_args = self.num_missing_lifetime_args(); let num_params_to_take = num_missing_args; @@ -678,7 +678,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_adding_type_and_const_args(&self, err: &mut Diagnostic) { + fn suggest_adding_type_and_const_args(&self, err: &mut DiagnosticBuilder<'_>) { let num_missing_args = self.num_missing_type_or_const_args(); let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args)); @@ -738,7 +738,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```compile_fail /// Into::into::>(42) // suggests considering `Into::>::into(42)` /// ``` - fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diagnostic) { + fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut DiagnosticBuilder<'_>) { let trait_ = match self.tcx.trait_of_item(self.def_id) { Some(def_id) => def_id, None => return, @@ -794,7 +794,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, qpath: &'tcx hir::QPath<'tcx>, msg: String, num_assoc_fn_excess_args: usize, @@ -827,7 +827,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_def_id: DefId, expr: &'tcx hir::Expr<'tcx>, msg: String, @@ -881,7 +881,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```text /// type Map = HashMap; /// ``` - fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) { + fn suggest_removing_args_or_generics(&self, err: &mut DiagnosticBuilder<'_>) { let num_provided_lt_args = self.num_provided_lifetime_args(); let num_provided_type_const_args = self.num_provided_type_or_const_args(); let unbound_types = self.get_unbound_associated_types(); @@ -899,7 +899,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let provided_args_matches_unbound_traits = unbound_types.len() == num_redundant_type_or_const_args; - let remove_lifetime_args = |err: &mut Diagnostic| { + let remove_lifetime_args = |err: &mut DiagnosticBuilder<'_>| { let mut lt_arg_spans = Vec::new(); let mut found_redundant = false; for arg in self.gen_args.args { @@ -940,7 +940,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { ); }; - let remove_type_or_const_args = |err: &mut Diagnostic| { + let remove_type_or_const_args = |err: &mut DiagnosticBuilder<'_>| { let mut gen_arg_spans = Vec::new(); let mut found_redundant = false; for arg in self.gen_args.args { @@ -1037,7 +1037,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Builds the `type defined here` message. - fn show_definition(&self, err: &mut Diagnostic) { + fn show_definition(&self, err: &mut DiagnosticBuilder<'_>) { let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) { if self.tcx.sess.source_map().is_span_accessible(def_span) { def_span.into() @@ -1088,7 +1088,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Add note if `impl Trait` is explicitly specified. - fn note_synth_provided(&self, err: &mut Diagnostic) { + fn note_synth_provided(&self, err: &mut DiagnosticBuilder<'_>) { if !self.is_synth_provided() { return; } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 18adf37d08c..cb131f1d166 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -1,6 +1,6 @@ use crate::coercion::{AsCoercionSite, CoerceMany}; use crate::{Diverges, Expectation, FnCtxt, Needs}; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir::{ self as hir, def::{CtorOf, DefKind, Res}, @@ -177,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn explain_never_type_coerced_to_unit( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, arm: &hir::Arm<'tcx>, arm_ty: Ty<'tcx>, prior_arm: Option<(Option, Ty<'tcx>, Span)>, @@ -209,7 +209,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_removing_semicolon_for_coerce( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'tcx>, arm_ty: Ty<'tcx>, prior_arm: Option<(Option, Ty<'tcx>, Span)>, @@ -303,7 +303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// `if let PAT = EXPR {}` expressions that could be turned into `let PAT = EXPR;`. fn explain_if_expr( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ret_reason: Option<(Span, String)>, if_span: Span, cond_expr: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 27614634c6b..69bcb6b8c15 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -4,7 +4,7 @@ use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::errors; use rustc_ast::util::parser::PREC_POSTFIX; -use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, StashKey}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, Namespace, Res}; use rustc_hir::def_id::DefId; @@ -347,7 +347,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// likely intention is to call the closure, suggest `(||{})()`. (#55851) fn identify_bad_closure_def_and_call( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, hir_id: hir::HirId, callee_node: &hir::ExprKind<'_>, callee_span: Span, @@ -410,7 +410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// likely intention is to create an array containing tuples. fn maybe_suggest_bad_array_definition( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, call_expr: &'tcx hir::Expr<'tcx>, callee_expr: &'tcx hir::Expr<'tcx>, ) -> bool { @@ -601,7 +601,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// and suggesting the fix if the method probe is successful. fn suggest_call_as_method( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_, ()>, segment: &'tcx hir::PathSegment<'tcx>, arg_exprs: &'tcx [hir::Expr<'tcx>], call_expr: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 042dd576c5b..48fc2900b0d 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -33,7 +33,7 @@ use super::FnCtxt; use crate::errors; use crate::type_error_struct; use hir::ExprKind; -use rustc_errors::{codes::*, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{codes::*, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::mir::Mutability; @@ -983,7 +983,11 @@ impl<'a, 'tcx> CastCheck<'tcx> { /// Attempt to suggest using `.is_empty` when trying to cast from a /// collection type to a boolean. - fn try_suggest_collection_to_bool(&self, fcx: &FnCtxt<'a, 'tcx>, err: &mut Diagnostic) { + fn try_suggest_collection_to_bool( + &self, + fcx: &FnCtxt<'a, 'tcx>, + err: &mut DiagnosticBuilder<'_>, + ) { if self.cast_ty.is_bool() { let derefed = fcx .autoderef(self.expr_span, self.expr_ty) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6bab8f75d24..9f6175eac13 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -36,9 +36,7 @@ //! ``` use crate::FnCtxt; -use rustc_errors::{ - codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, -}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -1439,7 +1437,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { &mut self, fcx: &FnCtxt<'a, 'tcx>, cause: &ObligationCause<'tcx>, - augment_error: impl FnOnce(&mut Diagnostic), + augment_error: impl FnOnce(&mut DiagnosticBuilder<'_>), label_unit_as_expected: bool, ) { self.coerce_inner( @@ -1462,7 +1460,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { cause: &ObligationCause<'tcx>, expression: Option<&'tcx hir::Expr<'tcx>>, mut expression_ty: Ty<'tcx>, - augment_error: impl FnOnce(&mut Diagnostic), + augment_error: impl FnOnce(&mut DiagnosticBuilder<'_>), label_expression_as_expected: bool, ) { // Incorporate whatever type inference information we have @@ -1673,7 +1671,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fn note_unreachable_loop_return( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, tcx: TyCtxt<'tcx>, expr: &hir::Expr<'tcx>, ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index fdb2cb69ee7..98e3fbb8b11 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1,6 +1,6 @@ use crate::FnCtxt; use rustc_errors::MultiSpan; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::Visitor; @@ -19,7 +19,7 @@ use super::method::probe; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn emit_type_mismatch_suggestions( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, @@ -70,7 +70,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn emit_coerce_suggestions( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, @@ -280,7 +280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// with some expectation given by `source`. pub fn note_source_of_type_mismatch_constraint( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, source: TypeMismatchSource<'tcx>, ) -> bool { @@ -550,7 +550,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // expected type. pub fn annotate_loop_expected_due_to_inference( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, error: Option>, ) { @@ -673,7 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn annotate_expected_due_to_let_ty( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, error: Option>, ) { @@ -782,7 +782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn annotate_alternative_method_deref( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, error: Option>, ) { @@ -1029,7 +1029,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn explain_self_literal( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -1082,7 +1082,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn note_wrong_return_ty_due_to_generic_arg( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, ) { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index a946d59ff2b..0f6544c3e1f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -26,8 +26,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic, - DiagnosticBuilder, ErrorGuaranteed, StashKey, + codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, DiagnosticBuilder, + ErrorGuaranteed, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -69,7 +69,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, expected_ty: Ty<'tcx>, - extend_err: impl FnOnce(&mut Diagnostic), + extend_err: impl FnOnce(&mut DiagnosticBuilder<'_>), ) -> Ty<'tcx> { let mut ty = self.check_expr_with_expectation(expr, ExpectHasType(expected_ty)); @@ -958,7 +958,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs: &'tcx hir::Expr<'tcx>, code: ErrCode, op_span: Span, - adjust_err: impl FnOnce(&mut Diagnostic), + adjust_err: impl FnOnce(&mut DiagnosticBuilder<'_>), ) { if lhs.is_syntactic_place_expr() { return; @@ -1223,7 +1223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let lhs_ty = self.check_expr_with_needs(lhs, Needs::MutPlace); - let suggest_deref_binop = |err: &mut Diagnostic, rhs_ty: Ty<'tcx>| { + let suggest_deref_binop = |err: &mut DiagnosticBuilder<'_>, rhs_ty: Ty<'tcx>| { if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) { // Can only assign if the type is sized, so if `DerefMut` yields a type that is // unsized, do not suggest dereferencing it. @@ -2008,7 +2008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { last_expr_field: &hir::ExprField<'tcx>, variant: &ty::VariantDef, args: GenericArgsRef<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) { // I don't use 'is_range_literal' because only double-sided, half-open ranges count. if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [range_start, range_end], _) = @@ -2524,7 +2524,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_await_on_field_access( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, field_ident: Ident, base: &'tcx hir::Expr<'tcx>, ty: Ty<'tcx>, @@ -2723,7 +2723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit() } - fn point_at_param_definition(&self, err: &mut Diagnostic, param: ty::ParamTy) { + fn point_at_param_definition(&self, err: &mut DiagnosticBuilder<'_>, param: ty::ParamTy) { let generics = self.tcx.generics_of(self.body_id); let generic_param = generics.type_param(¶m, self.tcx); if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param.kind { @@ -2742,7 +2742,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn maybe_suggest_array_indexing( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, base: &hir::Expr<'_>, field: Ident, @@ -2766,7 +2766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_first_deref_field( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, base: &hir::Expr<'_>, field: Ident, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ce8b62d19b4..986af2f5c9e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -5,7 +5,7 @@ use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -1020,7 +1020,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn note_internal_mutation_in_method( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, expected: Option>, found: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index d8d3d45dd40..4d91d799886 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -13,7 +13,7 @@ use itertools::Itertools; use rustc_ast as ast; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ - codes::*, pluralize, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey, + codes::*, pluralize, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -1935,7 +1935,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn label_fn_like( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, callable_def_id: Option, callee_ty: Option>, call_expr: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index c1a32a1afa3..e57717c25d9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -12,7 +12,7 @@ use core::cmp::min; use core::iter; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; use rustc_data_structures::packed::Pu128; -use rustc_errors::{Applicability, Diagnostic, MultiSpan}; +use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; @@ -48,7 +48,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .copied() } - pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) { + pub(in super::super) fn suggest_semicolon_at_end( + &self, + span: Span, + err: &mut DiagnosticBuilder<'_>, + ) { // This suggestion is incorrect for // fn foo() -> bool { match () { () => true } || match () { () => true } } err.span_suggestion_short( @@ -66,7 +70,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - Possible missing return type if the return type is the default, and not `fn main()`. pub fn suggest_mismatched_types_on_tail( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -97,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// ``` pub(crate) fn suggest_fn_call( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, found: Ty<'tcx>, can_satisfy: impl FnOnce(Ty<'tcx>) -> bool, @@ -179,7 +183,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn suggest_two_fn_call( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, lhs_expr: &'tcx hir::Expr<'tcx>, lhs_ty: Ty<'tcx>, rhs_expr: &'tcx hir::Expr<'tcx>, @@ -253,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn suggest_remove_last_method_call( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'tcx>, expected: Ty<'tcx>, ) -> bool { @@ -282,7 +286,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn suggest_deref_ref_or_into( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -540,7 +544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// in the heap by calling `Box::new()`. pub(in super::super) fn suggest_boxing_when_appropriate( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, span: Span, hir_id: HirId, expected: Ty<'tcx>, @@ -583,7 +587,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// suggest a non-capturing closure pub(in super::super) fn suggest_no_capture_closure( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool { @@ -620,7 +624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self, err))] pub(in super::super) fn suggest_calling_boxed_future_when_appropriate( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -732,7 +736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// block is needed to be added too (`|| { expr; }`). This is denoted by `needs_block`. pub fn suggest_missing_semicolon( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expression: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, needs_block: bool, @@ -791,7 +795,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(level = "trace", skip(self, err))] pub(in super::super) fn suggest_missing_return_type( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, fn_decl: &hir::FnDecl<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -909,7 +913,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// ``` fn try_suggest_return_impl_trait( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, fn_id: hir::HirId, @@ -1014,7 +1018,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn suggest_missing_break_or_return_expr( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &'tcx hir::Expr<'tcx>, fn_decl: &hir::FnDecl<'tcx>, expected: Ty<'tcx>, @@ -1118,7 +1122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn suggest_missing_parentheses( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, ) -> bool { let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None); @@ -1136,7 +1140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// if it was possibly mistaken array syntax. pub(crate) fn suggest_block_to_brackets_peeling_refs( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, mut expr: &hir::Expr<'_>, mut expr_ty: Ty<'tcx>, mut expected_ty: Ty<'tcx>, @@ -1163,7 +1167,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_clone_for_ref( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, @@ -1198,7 +1202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_copied_cloned_or_as_ref( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, @@ -1248,7 +1252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_into( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, @@ -1311,7 +1315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// When expecting a `bool` and finding an `Option`, suggests using `let Some(..)` or `.is_some()` pub(crate) fn suggest_option_to_bool( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, expr_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, @@ -1368,7 +1372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`. pub(crate) fn suggest_block_to_brackets( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, blk: &hir::Block<'_>, blk_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, @@ -1408,7 +1412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self, err))] pub(crate) fn suggest_floating_point_literal( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, expected_ty: Ty<'tcx>, ) -> bool { @@ -1479,7 +1483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self, err))] pub(crate) fn suggest_null_ptr_for_literal_zero_given_to_ptr_arg( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, expected_ty: Ty<'tcx>, ) -> bool { @@ -1517,7 +1521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_associated_const( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'tcx>, expected_ty: Ty<'tcx>, ) -> bool { @@ -1611,7 +1615,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// which is a side-effect of autoref. pub(crate) fn note_type_is_not_clone( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, expected_ty: Ty<'tcx>, found_ty: Ty<'tcx>, expr: &hir::Expr<'_>, @@ -1811,7 +1815,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) -> bool { if let Some((span_semi, boxed)) = self.err_ctxt().could_remove_semicolon(blk, expected_ty) { if let StatementAsExpression::NeedsBoxing = boxed { @@ -1856,7 +1860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_missing_unwrap_expect( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -1939,7 +1943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_coercing_result_via_try_operator( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -1986,7 +1990,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// sole field is of the found type, suggest such variants. (Issue #42764) pub(crate) fn suggest_compatible_variants( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, expected: Ty<'tcx>, expr_ty: Ty<'tcx>, @@ -2175,7 +2179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_non_zero_new_unwrap( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, expected: Ty<'tcx>, expr_ty: Ty<'tcx>, @@ -2719,7 +2723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_cast( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, @@ -2847,7 +2851,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id); let suggest_fallible_into_or_lhs_from = - |err: &mut Diagnostic, exp_to_found_is_fallible: bool| { + |err: &mut DiagnosticBuilder<'_>, exp_to_found_is_fallible: bool| { // If we know the expression the expected type is derived from, we might be able // to suggest a widening conversion rather than a narrowing one (which may // panic). For example, given x: u8 and y: u32, if we know the span of "x", @@ -2887,7 +2891,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let suggest_to_change_suffix_or_into = - |err: &mut Diagnostic, + |err: &mut DiagnosticBuilder<'_>, found_to_exp_is_fallible: bool, exp_to_found_is_fallible: bool| { let exp_is_lhs = expected_ty_expr.is_some_and(|e| self.tcx.hir().is_lhs(e.hir_id)); @@ -3085,7 +3089,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Identify when the user has written `foo..bar()` instead of `foo.bar()`. pub(crate) fn suggest_method_call_on_range_literal( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, @@ -3163,7 +3167,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// block without a tail expression. pub(crate) fn suggest_return_binding_for_missing_tail_expr( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index fb969c82d8a..f8d0911a2eb 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -11,7 +11,7 @@ pub use self::suggest::SelfSource; pub use self::MethodError::*; use crate::FnCtxt; -use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage}; +use rustc_errors::{Applicability, DiagnosticBuilder, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; @@ -126,7 +126,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self, err, call_expr))] pub(crate) fn suggest_method_call( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, msg: impl Into + std::fmt::Debug, method_name: Ident, self_ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 4151298b42f..005d217fdc4 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -12,8 +12,8 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, - MultiSpan, StashKey, + codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, MultiSpan, + StashKey, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -1127,7 +1127,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let label_span_not_found = |err: &mut Diagnostic| { + let label_span_not_found = |err: &mut DiagnosticBuilder<'_>| { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); let is_string_or_ref_str = match rcvr_ty.kind() { @@ -1438,7 +1438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_source: SelfSource<'tcx>, args: Option<&'tcx [hir::Expr<'tcx>]>, span: Span, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, sources: &mut Vec, sugg_span: Option, ) { @@ -1584,7 +1584,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Look at all the associated functions without receivers in the type's inherent impls /// to look for builders that return `Self`, `Option` or `Result`. - fn find_builder_fn(&self, err: &mut Diagnostic, rcvr_ty: Ty<'tcx>) { + fn find_builder_fn(&self, err: &mut DiagnosticBuilder<'_>, rcvr_ty: Ty<'tcx>) { let ty::Adt(adt_def, _) = rcvr_ty.kind() else { return; }; @@ -1665,7 +1665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// doesn't take a `self` receiver. fn suggest_associated_call_syntax( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, static_candidates: &Vec, rcvr_ty: Ty<'tcx>, source: SelfSource<'tcx>, @@ -1809,7 +1809,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty: Ty<'tcx>, expr: &hir::Expr<'_>, item_name: Ident, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) -> bool { let tcx = self.tcx; let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() { @@ -2132,7 +2132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Suggest calling a method on a field i.e. `a.field.bar()` instead of `a.bar()` fn suggest_calling_method_on_field( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: SelfSource<'tcx>, span: Span, actual: Ty<'tcx>, @@ -2212,7 +2212,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_unwrapping_inner_self( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: SelfSource<'tcx>, actual: Ty<'tcx>, item_name: Ident, @@ -2401,7 +2401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn note_unmet_impls_on_type( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, errors: Vec>, suggest_derive: bool, ) { @@ -2484,7 +2484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn note_predicate_source_and_get_derives( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, unsatisfied_predicates: &[( ty::Predicate<'tcx>, Option>, @@ -2566,7 +2566,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_derive( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, unsatisfied_predicates: &[( ty::Predicate<'tcx>, Option>, @@ -2602,7 +2602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn note_derefed_ty_has_method( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, self_source: SelfSource<'tcx>, rcvr_ty: Ty<'tcx>, item_name: Ident, @@ -2682,7 +2682,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_await_before_method( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, item_name: Ident, ty: Ty<'tcx>, call: &hir::Expr<'_>, @@ -2705,7 +2705,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn suggest_use_candidates(&self, err: &mut Diagnostic, msg: String, candidates: Vec) { + fn suggest_use_candidates( + &self, + err: &mut DiagnosticBuilder<'_>, + msg: String, + candidates: Vec, + ) { let parent_map = self.tcx.visible_parent_map(()); // Separate out candidates that must be imported with a glob, because they are named `_` @@ -2752,7 +2757,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_valid_traits( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, valid_out_of_scope_traits: Vec, explain: bool, ) -> bool { @@ -2793,7 +2798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_traits_to_import( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, @@ -3332,7 +3337,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// FIXME: currently not working for suggesting `map_or_else`, see #102408 pub(crate) fn suggest_else_fn_with_closure( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, found: Ty<'tcx>, expected: Ty<'tcx>, @@ -3458,7 +3463,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec { fn print_disambiguation_help<'tcx>( tcx: TyCtxt<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: SelfSource<'tcx>, args: Option<&'tcx [hir::Expr<'tcx>]>, trait_ref: ty::TraitRef<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 929b3557f52..fba240bf752 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -5,7 +5,7 @@ use super::FnCtxt; use crate::Expectation; use rustc_ast as ast; use rustc_data_structures::packed::Pu128; -use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::ObligationCauseCode; @@ -695,7 +695,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_expr: &'tcx hir::Expr<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, is_assign: IsAssign, op: hir::BinOp, ) -> bool { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 5026fbe4b80..73689b45b95 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -3,8 +3,8 @@ use crate::{errors, FnCtxt, LoweredTy}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, MultiSpan, + codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, + MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - fn endpoint_has_type(&self, err: &mut Diagnostic, span: Span, ty: Ty<'_>) { + fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) { if !ty.references_error() { err.span_label(span, format!("this is of type `{ty}`")); } @@ -683,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_adding_missing_ref_or_removing_ref( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, @@ -715,7 +715,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Precondition: pat is a Ref(_) pattern - fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) { + fn borrow_pat_suggestion(&self, err: &mut DiagnosticBuilder<'_>, pat: &Pat<'_>) { let tcx = self.tcx; if let PatKind::Ref(inner, mutbl) = pat.kind && let PatKind::Binding(_, _, binding, ..) = inner.kind @@ -933,7 +933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn maybe_suggest_range_literal( &self, - e: &mut Diagnostic, + e: &mut DiagnosticBuilder<'_>, opt_def_id: Option, ident: Ident, ) -> bool { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9bfaeb5ee32..4f2a576c573 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -60,8 +60,8 @@ use crate::traits::{ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, Applicability, DiagCtxt, Diagnostic, - DiagnosticBuilder, DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg, + codes::*, pluralize, struct_span_code_err, Applicability, DiagCtxt, DiagnosticBuilder, + DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -155,7 +155,7 @@ impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> { pub(super) fn note_and_explain_region<'tcx>( tcx: TyCtxt<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, prefix: &str, region: ty::Region<'tcx>, suffix: &str, @@ -180,7 +180,7 @@ pub(super) fn note_and_explain_region<'tcx>( fn explain_free_region<'tcx>( tcx: TyCtxt<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, prefix: &str, region: ty::Region<'tcx>, suffix: &str, @@ -262,7 +262,7 @@ fn msg_span_from_named_region<'tcx>( } fn emit_msg_span( - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, prefix: &str, description: String, span: Option, @@ -278,7 +278,7 @@ fn emit_msg_span( } fn label_msg_span( - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, prefix: &str, description: String, span: Option, @@ -577,7 +577,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } /// Adds a note if the types come from similarly named crates - fn check_and_note_conflicting_crates(&self, err: &mut Diagnostic, terr: TypeError<'tcx>) { + fn check_and_note_conflicting_crates( + &self, + err: &mut DiagnosticBuilder<'_>, + terr: TypeError<'tcx>, + ) { use hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; use ty::print::Printer; @@ -651,7 +655,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - let report_path_match = |err: &mut Diagnostic, did1: DefId, did2: DefId| { + let report_path_match = |err: &mut DiagnosticBuilder<'_>, did1: DefId, did2: DefId| { // Only report definitions from different crates. If both definitions // are from a local module we could have false positives, e.g. // let _ = [{struct Foo; Foo}, {struct Foo; Foo}]; @@ -701,7 +705,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn note_error_origin( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, cause: &ObligationCause<'tcx>, exp_found: Option>>, terr: TypeError<'tcx>, @@ -1535,7 +1539,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { )] pub fn note_type_err( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, cause: &ObligationCause<'tcx>, secondary_span: Option<(Span, Cow<'static, str>)>, mut values: Option>, @@ -1582,14 +1586,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { types_visitor } - fn report(&self, err: &mut Diagnostic) { + fn report(&self, err: &mut DiagnosticBuilder<'_>) { self.add_labels_for_types(err, "expected", &self.expected); self.add_labels_for_types(err, "found", &self.found); } fn add_labels_for_types( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, target: &str, types: &FxIndexMap>, ) { @@ -1803,7 +1807,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { |prim: Ty<'tcx>, shadow: Ty<'tcx>, defid: DefId, - diagnostic: &mut Diagnostic| { + diagnostic: &mut DiagnosticBuilder<'_>| { let name = shadow.sort_string(self.tcx); diagnostic.note(format!( "{prim} and {name} have similar names, but are actually distinct types" @@ -1823,7 +1827,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let diagnose_adts = |expected_adt: ty::AdtDef<'tcx>, found_adt: ty::AdtDef<'tcx>, - diagnostic: &mut Diagnostic| { + diagnostic: &mut DiagnosticBuilder<'_>| { let found_name = values.found.sort_string(self.tcx); let expected_name = values.expected.sort_string(self.tcx); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index adb3267d5be..cf8ac544106 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -12,7 +12,7 @@ use crate::infer::SubregionOrigin; use crate::infer::TyCtxt; use rustc_errors::AddToDiagnostic; -use rustc_errors::{Diagnostic, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir::Ty; use rustc_middle::ty::Region; @@ -142,7 +142,7 @@ pub fn suggest_adding_lifetime_params<'tcx>( sub: Region<'tcx>, ty_sup: &'tcx Ty<'_>, ty_sub: &'tcx Ty<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) { let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false }; suggestion.add_to_diagnostic(err); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index c8fd4e3a692..83e0b763d24 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -9,7 +9,7 @@ use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{AddToDiagnostic, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{ @@ -261,7 +261,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub fn suggest_new_region_bound( tcx: TyCtxt<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, fn_returns: Vec<&rustc_hir::Ty<'_>>, lifetime_name: String, arg: Option, @@ -488,7 +488,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// `'static` obligation. Suggest relaxing that implicit bound. fn find_impl_on_dyn_trait( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, ctxt: &UnifyReceiverContext<'tcx>, ) -> bool { @@ -521,7 +521,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { fn suggest_constrain_dyn_trait_in_impl( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, found_dids: &FxIndexSet, ident: Ident, self_ty: &hir::Ty<'_>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 50ac6235deb..0878505e85e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -5,7 +5,7 @@ use crate::errors::{ use crate::fluent_generated as fluent; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; -use rustc_errors::{AddToDiagnostic, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{AddToDiagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; @@ -15,7 +15,11 @@ use rustc_span::symbol::kw; use super::ObligationCauseAsDiagArg; impl<'tcx> TypeErrCtxt<'_, 'tcx> { - pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { + pub(super) fn note_region_origin( + &self, + err: &mut DiagnosticBuilder<'_>, + origin: &SubregionOrigin<'tcx>, + ) { match *origin { infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { span: trace.cause.span, @@ -290,7 +294,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, trait_item_def_id: DefId, impl_item_def_id: LocalDefId, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) { // FIXME(compiler-errors): Right now this is only being used for region // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches, diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 3c42f13141d..9df2f929501 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -1,6 +1,6 @@ use super::TypeErrCtxt; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; -use rustc_errors::{pluralize, Diagnostic, MultiSpan}; +use rustc_errors::{pluralize, DiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::traits::ObligationCauseCode; @@ -15,7 +15,7 @@ use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol}; impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub fn note_and_explain_type_err( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, err: TypeError<'tcx>, cause: &ObligationCause<'tcx>, sp: Span, @@ -522,7 +522,7 @@ impl Trait for X { fn suggest_constraint( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, msg: impl Fn() -> String, body_owner_def_id: DefId, proj_ty: &ty::AliasTy<'tcx>, @@ -595,7 +595,7 @@ impl Trait for X { /// fn that returns the type. fn expected_projection( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, proj_ty: &ty::AliasTy<'tcx>, values: ExpectedFound>, body_owner_def_id: DefId, @@ -705,7 +705,7 @@ fn foo(&self) -> Self::T { String::new() } /// a return type. This can occur when dealing with `TryStream` (#71035). fn suggest_constraining_opaque_associated_type( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, msg: impl Fn() -> String, proj_ty: &ty::AliasTy<'tcx>, ty: Ty<'tcx>, @@ -740,7 +740,7 @@ fn foo(&self) -> Self::T { String::new() } fn point_at_methods_that_satisfy_associated_type( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, assoc_container_id: DefId, current_method_ident: Option, proj_ty_item_def_id: DefId, @@ -798,7 +798,7 @@ fn foo(&self) -> Self::T { String::new() } fn point_at_associated_type( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, body_owner_def_id: DefId, found: Ty<'tcx>, ) -> bool { @@ -879,7 +879,7 @@ fn foo(&self) -> Self::T { String::new() } /// type is defined on a supertrait of the one present in the bounds. fn constrain_generic_bound_associated_type_structured_suggestion( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, assoc: ty::AssocItem, @@ -916,7 +916,7 @@ fn foo(&self) -> Self::T { String::new() } /// associated type to a given type `ty`. fn constrain_associated_type_structured_suggestion( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, span: Span, assoc: ty::AssocItem, assoc_args: &[ty::GenericArg<'tcx>], diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 15834c78413..f7102ab6205 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -1,7 +1,7 @@ use hir::def::CtorKind; use hir::intravisit::{walk_expr, walk_stmt, Visitor}; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_middle::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, @@ -76,7 +76,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub(super) fn suggest_boxing_for_return_impl_trait( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, return_sp: Span, arm_spans: impl Iterator, ) { @@ -100,7 +100,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, cause: &ObligationCause<'tcx>, exp_found: &ty::error::ExpectedFound>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { // Heavily inspired by `FnCtxt::suggest_compatible_variants`, with // some modifications due to that being in typeck and this being in infer. @@ -177,7 +177,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause: &ObligationCause<'tcx>, exp_span: Span, exp_found: &ty::error::ExpectedFound>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { debug!( "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}", @@ -258,7 +258,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, cause: &ObligationCause<'tcx>, exp_found: &ty::error::ExpectedFound>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { debug!( "suggest_accessing_field_where_appropriate(cause={:?}, exp_found={:?})", @@ -298,7 +298,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause: &ObligationCause<'tcx>, span: Span, exp_found: &ty::error::ExpectedFound>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found); let ty::error::ExpectedFound { expected, found } = exp_found; @@ -532,7 +532,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: Span, hir: hir::Node<'_>, exp_found: &ty::error::ExpectedFound>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, ) { // 0. Extract fn_decl from hir let hir::Node::Expr(hir::Expr { @@ -818,7 +818,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) -> bool { let diag = self.consider_returning_binding_diag(blk, expected_ty); match diag { diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 2a6f473cd32..1e9e9947db5 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -2,7 +2,7 @@ use std::cmp; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; -use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; +use rustc_errors::{DiagnosticBuilder, DiagnosticMessage, MultiSpan}; use rustc_hir::{HirId, ItemLocalId}; use rustc_session::lint::{ builtin::{self, FORBIDDEN_LINT_GROUPS}, @@ -204,7 +204,7 @@ pub fn explain_lint_level_source( lint: &'static Lint, level: Level, src: LintLevelSource, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, ()>, ) { let name = lint.name_lower(); if let Level::Allow = level { @@ -359,7 +359,7 @@ pub fn lint_level( // Lint diagnostics that are covered by the expect level will not be emitted outside // the compiler. It is therefore not necessary to add any information for the user. // This will therefore directly call the decorate function which will in turn emit - // the `Diagnostic`. + // the diagnostic. if let Level::Expect(_) = level { decorate(&mut err); err.emit(); @@ -401,7 +401,7 @@ pub fn lint_level( // Finally, run `decorate`. decorate(&mut err); - explain_lint_level_source(lint, level, src, &mut *err); + explain_lint_level_source(lint, level, src, &mut err); err.emit() } lint_level_impl(sess, lint, level, src, span, msg, Box::new(decorate)) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 2f624ab0527..5f3ecf34416 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -9,7 +9,7 @@ use rustc_attr::{ self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, }; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_feature::GateIssue; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; @@ -125,7 +125,7 @@ pub fn report_unstable( } pub fn deprecation_suggestion( - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_, ()>, kind: &str, suggestion: Option, span: Span, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 119e0a49acf..b3c09d1d152 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -16,7 +16,7 @@ use crate::ty::GenericArgsRef; use crate::ty::{self, AdtKind, Ty}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -908,7 +908,7 @@ pub enum ObjectSafetyViolationSolution { } impl ObjectSafetyViolationSolution { - pub fn add_to(self, err: &mut Diagnostic) { + pub fn add_to(self, err: &mut DiagnosticBuilder<'_, G>) { match self { ObjectSafetyViolationSolution::None => {} ObjectSafetyViolationSolution::AddSelfOrMakeSized { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 7cb326ce696..f379cf27a5f 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -11,7 +11,7 @@ use crate::ty::{ }; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg}; +use rustc_errors::{Applicability, DiagnosticArgValue, DiagnosticBuilder, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -111,7 +111,7 @@ where pub fn suggest_arbitrary_trait_bound<'tcx>( tcx: TyCtxt<'tcx>, generics: &hir::Generics<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_pred: PolyTraitPredicate<'tcx>, associated_ty: Option<(&'static str, Ty<'tcx>)>, ) -> bool { @@ -216,7 +216,7 @@ fn suggest_changing_unsized_bound( pub fn suggest_constraining_type_param( tcx: TyCtxt<'_>, generics: &hir::Generics<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, param_name: &str, constraint: &str, def_id: Option, @@ -235,7 +235,7 @@ pub fn suggest_constraining_type_param( pub fn suggest_constraining_type_params<'a>( tcx: TyCtxt<'_>, generics: &hir::Generics<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, param_names_and_constraints: impl Iterator)>, span_to_replace: Option, ) -> bool { diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index b1bd4ac75e5..52a029b20f6 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -1,6 +1,6 @@ use super::UnmatchedDelim; use rustc_ast::token::Delimiter; -use rustc_errors::Diagnostic; +use rustc_errors::DiagnosticBuilder; use rustc_span::source_map::SourceMap; use rustc_span::Span; @@ -31,7 +31,7 @@ pub fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> // When we get a `)` or `]` for `{`, we should emit help message here // it's more friendly compared to report `unmatched error` in later phase pub fn report_missing_open_delim( - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, unmatched_delims: &[UnmatchedDelim], ) -> bool { let mut reported_missing_open = false; @@ -55,7 +55,7 @@ pub fn report_missing_open_delim( } pub fn report_suspicious_mismatch_block( - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, diag_info: &TokenTreeDiagInfo, sm: &SourceMap, delim: Delimiter, diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 98e062dd784..6545429b95b 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -8,7 +8,7 @@ use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::token::{self, Delimiter, Nonterminal}; -use rustc_errors::{codes::*, Diagnostic, PResult}; +use rustc_errors::{codes::*, DiagnosticBuilder, PResult}; use rustc_span::{sym, BytePos, Span}; use thin_vec::ThinVec; use tracing::debug; @@ -141,7 +141,7 @@ impl<'a> Parser<'a> { fn annotate_following_item_if_applicable( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, span: Span, attr_type: OuterAttributeType, ) -> Option { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 659716548d9..0cc2170714c 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -34,8 +34,8 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, FatalError, PErr, PResult, + pluralize, AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, + FatalError, PErr, PResult, }; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; @@ -208,11 +208,11 @@ struct MultiSugg { } impl MultiSugg { - fn emit(self, err: &mut Diagnostic) { + fn emit(self, err: &mut DiagnosticBuilder<'_>) { err.multipart_suggestion(self.msg, self.patches, self.applicability); } - fn emit_verbose(self, err: &mut Diagnostic) { + fn emit_verbose(self, err: &mut DiagnosticBuilder<'_>) { err.multipart_suggestion_verbose(self.msg, self.patches, self.applicability); } } @@ -846,7 +846,7 @@ impl<'a> Parser<'a> { err.emit(); } - fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool { + fn check_too_many_raw_str_terminators(&mut self, err: &mut DiagnosticBuilder<'_>) -> bool { let sm = self.sess.source_map(); match (&self.prev_token.kind, &self.token.kind) { ( @@ -2179,7 +2179,7 @@ impl<'a> Parser<'a> { pub(super) fn parameter_without_type( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, pat: P, require_name: bool, first_param: bool, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 20b9581f2ef..8826c06bebd 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -25,9 +25,7 @@ use rustc_ast::{Arm, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLim use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{ - AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, PResult, StashKey, -}; +use rustc_errors::{AddToDiagnostic, Applicability, DiagnosticBuilder, PResult, StashKey}; use rustc_lexer::unescape::unescape_char; use rustc_macros::Subdiagnostic; use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; @@ -865,7 +863,7 @@ impl<'a> Parser<'a> { ); let mut err = self.dcx().struct_span_err(span, msg); - let suggest_parens = |err: &mut Diagnostic| { + let suggest_parens = |err: &mut DiagnosticBuilder<'_>| { let suggestions = vec![ (span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), ")".to_string()), @@ -3437,7 +3435,7 @@ impl<'a> Parser<'a> { let mut recover_async = false; let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD); - let mut async_block_err = |e: &mut Diagnostic, span: Span| { + let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| { recover_async = true; errors::AsyncBlockIn2015 { span }.add_to_diagnostic(e); errors::HelpUseLatestEdition::new().add_to_diagnostic(e); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 4b978fefa10..d64a3b43aad 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -7,7 +7,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ codes::*, pluralize, report_ambiguity_error, struct_span_code_err, Applicability, DiagCtxt, - Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, SuggestionStyle, + DiagnosticBuilder, ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; @@ -360,7 +360,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// ``` fn add_suggestion_for_rename_of_use( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, name: Symbol, import: Import<'_>, binding_span: Span, @@ -436,7 +436,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// as characters expected by span manipulations won't be present. fn add_suggestion_for_duplicate_nested_use( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, import: Import<'_>, binding_span: Span, ) { @@ -1399,7 +1399,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn unresolved_macro_suggestions( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, macro_kind: MacroKind, parent_scope: &ParentScope<'a>, ident: Ident, @@ -1515,7 +1515,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn add_typo_suggestion( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, suggestion: Option, span: Span, ) -> bool { @@ -2461,7 +2461,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Finds a cfg-ed out item inside `module` with the matching name. pub(crate) fn find_cfg_stripped( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, segment: &Symbol, module: DefId, ) { @@ -2670,7 +2670,7 @@ pub(crate) enum DiagnosticMode { pub(crate) fn import_candidates( tcx: TyCtxt<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, // This is `None` if all placement locations are inside expansions use_placement_span: Option, candidates: &[ImportSuggestion], @@ -2696,7 +2696,7 @@ pub(crate) fn import_candidates( /// found and suggested, returns `true`, otherwise returns `false`. fn show_candidates( tcx: TyCtxt<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, // This is `None` if all placement locations are inside expansions use_placement_span: Option, candidates: &[ImportSuggestion], diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index f71f7ccecab..335bf0949d6 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion}; use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind}; use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet}; @@ -16,8 +18,8 @@ use rustc_ast::{ use rustc_ast_pretty::pprust::where_bound_predicate_to_string; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, MultiSpan, SuggestionStyle, + codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, + MultiSpan, SuggestionStyle, }; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; @@ -496,7 +498,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn detect_assoc_type_constraint_meant_as_path( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, base_error: &BaseError, ) { let Some(ty) = self.diagnostic_metadata.current_type_path else { @@ -537,7 +539,12 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } - fn suggest_self_or_self_ref(&mut self, err: &mut Diagnostic, path: &[Segment], span: Span) { + fn suggest_self_or_self_ref( + &mut self, + err: &mut DiagnosticBuilder<'_>, + path: &[Segment], + span: Span, + ) { if !self.self_type_is_available() { return; } @@ -582,7 +589,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn try_lookup_name_relaxed( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: PathSource<'_>, path: &[Segment], following_seg: Option<&Segment>, @@ -786,7 +793,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn suggest_trait_and_bounds( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: PathSource<'_>, res: Option, span: Span, @@ -863,7 +870,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn suggest_typo( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: PathSource<'_>, path: &[Segment], following_seg: Option<&Segment>, @@ -903,7 +910,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn suggest_shadowed( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: PathSource<'_>, path: &[Segment], following_seg: Option<&Segment>, @@ -936,7 +943,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn err_code_special_cases( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: PathSource<'_>, path: &[Segment], span: Span, @@ -981,7 +988,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { /// Emit special messages for unresolved `Self` and `self`. fn suggest_self_ty( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: PathSource<'_>, path: &[Segment], span: Span, @@ -1008,7 +1015,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn suggest_self_value( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: PathSource<'_>, path: &[Segment], span: Span, @@ -1090,7 +1097,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn suggest_at_operator_in_slice_pat_with_range( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, path: &[Segment], ) { let Some(pat) = self.diagnostic_metadata.current_pat else { return }; @@ -1129,7 +1136,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn suggest_swapping_misplaced_self_ty_and_trait( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: PathSource<'_>, res: Option, span: Span, @@ -1155,7 +1162,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } - fn suggest_bare_struct_literal(&mut self, err: &mut Diagnostic) { + fn suggest_bare_struct_literal(&mut self, err: &mut DiagnosticBuilder<'_>) { if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal { err.multipart_suggestion( "you might have meant to write a `struct` literal", @@ -1170,7 +1177,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn suggest_changing_type_to_const_param( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, res: Option, source: PathSource<'_>, span: Span, @@ -1222,7 +1229,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn suggest_pattern_match_with_let( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: PathSource<'_>, span: Span, ) -> bool { @@ -1277,7 +1284,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } /// Given `where ::Baz: String`, suggest `where T: Bar`. - fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diagnostic) -> bool { + fn restrict_assoc_type_in_where_clause( + &mut self, + span: Span, + err: &mut DiagnosticBuilder<'_>, + ) -> bool { // Detect that we are actually in a `where` predicate. let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { @@ -1410,7 +1421,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { /// Returns `true` if able to provide context-dependent help. fn smart_resolve_context_dependent_help( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, span: Span, source: PathSource<'_>, path: &[Segment], @@ -1421,50 +1432,52 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let ns = source.namespace(); let is_expected = &|res| source.is_expected(res); - let path_sep = |this: &mut Self, err: &mut Diagnostic, expr: &Expr, kind: DefKind| { - const MESSAGE: &str = "use the path separator to refer to an item"; + let path_sep = + |this: &mut Self, err: &mut DiagnosticBuilder<'_>, expr: &Expr, kind: DefKind| { + const MESSAGE: &str = "use the path separator to refer to an item"; - let (lhs_span, rhs_span) = match &expr.kind { - ExprKind::Field(base, ident) => (base.span, ident.span), - ExprKind::MethodCall(box MethodCall { receiver, span, .. }) => { - (receiver.span, *span) - } - _ => return false, - }; + let (lhs_span, rhs_span) = match &expr.kind { + ExprKind::Field(base, ident) => (base.span, ident.span), + ExprKind::MethodCall(box MethodCall { receiver, span, .. }) => { + (receiver.span, *span) + } + _ => return false, + }; - if lhs_span.eq_ctxt(rhs_span) { - err.span_suggestion( - lhs_span.between(rhs_span), - MESSAGE, - "::", - Applicability::MaybeIncorrect, - ); - true - } else if kind == DefKind::Struct - && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span) - && let Ok(snippet) = this.r.tcx.sess.source_map().span_to_snippet(lhs_source_span) - { - // The LHS is a type that originates from a macro call. - // We have to add angle brackets around it. + if lhs_span.eq_ctxt(rhs_span) { + err.span_suggestion( + lhs_span.between(rhs_span), + MESSAGE, + "::", + Applicability::MaybeIncorrect, + ); + true + } else if kind == DefKind::Struct + && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span) + && let Ok(snippet) = + this.r.tcx.sess.source_map().span_to_snippet(lhs_source_span) + { + // The LHS is a type that originates from a macro call. + // We have to add angle brackets around it. - err.span_suggestion_verbose( - lhs_source_span.until(rhs_span), - MESSAGE, - format!("<{snippet}>::"), - Applicability::MaybeIncorrect, - ); - true - } else { - // Either we were unable to obtain the source span / the snippet or - // the LHS originates from a macro call and it is not a type and thus - // there is no way to replace `.` with `::` and still somehow suggest - // valid Rust code. + err.span_suggestion_verbose( + lhs_source_span.until(rhs_span), + MESSAGE, + format!("<{snippet}>::"), + Applicability::MaybeIncorrect, + ); + true + } else { + // Either we were unable to obtain the source span / the snippet or + // the LHS originates from a macro call and it is not a type and thus + // there is no way to replace `.` with `::` and still somehow suggest + // valid Rust code. - false - } - }; + false + } + }; - let find_span = |source: &PathSource<'_>, err: &mut Diagnostic| { + let find_span = |source: &PathSource<'_>, err: &mut DiagnosticBuilder<'_>| { match source { PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. })) | PathSource::TupleStruct(span, _) => { @@ -1820,7 +1833,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn suggest_alternative_construction_methods( &mut self, def_id: DefId, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, path_span: Span, call_span: Span, args: &[P], @@ -2250,7 +2263,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // try to give a suggestion for this pattern: `name = blah`, which is common in other languages // suggest `let name = blah` to introduce a new binding - fn let_binding_suggestion(&mut self, err: &mut Diagnostic, ident_span: Span) -> bool { + fn let_binding_suggestion( + &mut self, + err: &mut DiagnosticBuilder<'_>, + ident_span: Span, + ) -> bool { if let Some(Expr { kind: ExprKind::Assign(lhs, ..), .. }) = self.diagnostic_metadata.in_assignment && let ast::ExprKind::Path(None, ref path) = lhs.kind @@ -2351,7 +2368,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { /// Adds a suggestion for using an enum's variant when an enum is used instead. fn suggest_using_enum_variant( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, source: PathSource<'_>, def_id: DefId, span: Span, @@ -2727,9 +2744,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn suggest_introducing_lifetime( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, name: Option<&str>, - suggest: impl Fn(&mut Diagnostic, bool, Span, Cow<'static, str>, String) -> bool, + suggest: impl Fn(&mut DiagnosticBuilder<'_>, bool, Span, Cow<'static, str>, String) -> bool, ) { let mut suggest_note = true; for rib in self.lifetime_ribs.iter().rev() { @@ -2887,7 +2904,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { fn add_missing_lifetime_specifiers_label( &mut self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, lifetime_refs: Vec, function_param_lifetimes: Option<(Vec, Vec)>, ) { diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 701c5bf375f..b011ca4dd50 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -15,7 +15,8 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, DiagCtxt}; use rustc_errors::{ - fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticMessage, MultiSpan, StashKey, + fallback_fluent_bundle, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, MultiSpan, + StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -156,7 +157,11 @@ pub fn feature_warn_issue( } /// Adds the diagnostics for a feature to an existing error. -pub fn add_feature_diagnostics(err: &mut Diagnostic, sess: &Session, feature: Symbol) { +pub fn add_feature_diagnostics( + err: &mut DiagnosticBuilder<'_, G>, + sess: &Session, + feature: Symbol, +) { add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false); } @@ -165,8 +170,8 @@ pub fn add_feature_diagnostics(err: &mut Diagnostic, sess: &Session, feature: Sy /// This variant allows you to control whether it is a library or language feature. /// Almost always, you want to use this for a language feature. If so, prefer /// `add_feature_diagnostics`. -pub fn add_feature_diagnostics_for_issue( - err: &mut Diagnostic, +pub fn add_feature_diagnostics_for_issue( + err: &mut DiagnosticBuilder<'_, G>, sess: &Session, feature: Symbol, issue: GateIssue, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f663f02f872..3619d02438d 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -18,7 +18,7 @@ use crate::traits::{ Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext, }; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::Diagnostic; +use rustc_errors::{DiagnosticBuilder, EmissionGuarantee}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; @@ -58,7 +58,7 @@ pub struct OverlapResult<'tcx> { pub involves_placeholder: bool, } -pub fn add_placeholder_note(err: &mut Diagnostic) { +pub fn add_placeholder_note(err: &mut DiagnosticBuilder<'_, G>) { err.note( "this behavior recently changed as a result of a bug fix; \ see rust-lang/rust#56105 for details", diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 2d85f84f480..101460789ee 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -13,7 +13,7 @@ use hir::def::CtorOf; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, + codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan, Style, SuggestionStyle, }; use rustc_hir as hir; @@ -116,12 +116,12 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) - /// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but /// it can also be an `impl Trait` param that needs to be decomposed to a type /// param for cleaner code. -pub fn suggest_restriction<'tcx>( +pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( tcx: TyCtxt<'tcx>, item_id: LocalDefId, hir_generics: &hir::Generics<'tcx>, msg: &str, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, G>, fn_sig: Option<&hir::FnSig<'_>>, projection: Option<&ty::AliasTy<'_>>, trait_pred: ty::PolyTraitPredicate<'tcx>, @@ -240,7 +240,7 @@ pub fn suggest_restriction<'tcx>( impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_restricting_param_bound( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, associated_ty: Option<(&'static str, Ty<'tcx>)>, mut body_id: LocalDefId, @@ -450,7 +450,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_dereferences( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { let mut code = obligation.cause.code(); @@ -743,22 +743,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn get_closure_name( &self, def_id: DefId, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, msg: Cow<'static, str>, ) -> Option { - let get_name = |err: &mut Diagnostic, kind: &hir::PatKind<'_>| -> Option { - // Get the local name of this closure. This can be inaccurate because - // of the possibility of reassignment, but this should be good enough. - match &kind { - hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, ident, None) => { - Some(ident.name) - } - _ => { - err.note(msg); - None + let get_name = + |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind<'_>| -> Option { + // Get the local name of this closure. This can be inaccurate because + // of the possibility of reassignment, but this should be good enough. + match &kind { + hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, ident, None) => { + Some(ident.name) + } + _ => { + err.note(msg); + None + } } - } - }; + }; let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?); match self.tcx.parent_hir_node(hir_id) { @@ -778,7 +779,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_fn_call( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { // It doesn't make sense to make this suggestion outside of typeck... @@ -894,7 +895,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn check_for_binding_assigned_block_without_tail_expression( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let mut span = obligation.cause.span; @@ -971,7 +972,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_add_clone_to_arg( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); @@ -1156,7 +1157,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, poly_trait_pred: ty::PolyTraitPredicate<'tcx>, has_custom_message: bool, ) -> bool { @@ -1374,7 +1375,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Suggest borrowing the type fn suggest_borrowing_for_object_cast( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, self_ty: Ty<'tcx>, target_ty: Ty<'tcx>, @@ -1410,7 +1411,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_remove_reference( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { let mut span = obligation.cause.span; @@ -1529,7 +1530,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { false } - fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) { + fn suggest_remove_await( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'_>, + ) { let hir = self.tcx.hir(); if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id) @@ -1599,7 +1604,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let points_at_arg = matches!( @@ -1677,7 +1682,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_semicolon_removal( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, span: Span, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { @@ -1731,7 +1736,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// emitted. fn suggest_impl_trait( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { @@ -1913,7 +1918,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn note_conflicting_fn_args( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, cause: &ObligationCauseCode<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -2120,7 +2125,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_fully_qualified_path( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, item_def_id: DefId, span: Span, trait_ref: DefId, @@ -2185,9 +2190,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// /// Returns `true` if an async-await specific note was added to the diagnostic. #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))] - fn maybe_note_obligation_cause_for_async_await( + fn maybe_note_obligation_cause_for_async_await( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, G>, obligation: &PredicateObligation<'tcx>, ) -> bool { let hir = self.tcx.hir(); @@ -2421,9 +2426,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// Unconditionally adds the diagnostic note described in /// `maybe_note_obligation_cause_for_async_await`'s documentation comment. #[instrument(level = "debug", skip_all)] - fn note_obligation_cause_for_async_await( + fn note_obligation_cause_for_async_await( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, G>, interior_or_upvar_span: CoroutineInteriorOrUpvar, is_async: bool, outer_coroutine: Option, @@ -2656,10 +2661,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } - fn note_obligation_cause_code( + fn note_obligation_cause_code( &self, body_id: LocalDefId, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, G>, predicate: T, param_env: ty::ParamEnv<'tcx>, cause_code: &ObligationCauseCode<'tcx>, @@ -3507,7 +3512,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { )] fn suggest_await_before_try( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, @@ -3565,7 +3570,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_floating_point_literal( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::PolyTraitRef<'tcx>, ) { let rhs_span = match obligation.cause.code() { @@ -3589,7 +3594,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_derive( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else { @@ -3655,7 +3660,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_dereferencing_index( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { if let ObligationCauseCode::ImplDerivedObligation(_) = obligation.cause.code() @@ -3675,10 +3680,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - fn note_function_argument_obligation( + fn note_function_argument_obligation( &self, body_id: LocalDefId, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, G>, arg_hir_id: HirId, parent_code: &ObligationCauseCode<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -3860,11 +3865,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - fn suggest_option_method_if_applicable( + fn suggest_option_method_if_applicable( &self, failed_pred: ty::Predicate<'tcx>, param_env: ty::ParamEnv<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, G>, expr: &hir::Expr<'_>, ) { let tcx = self.tcx; @@ -3934,7 +3939,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - fn look_for_iterator_item_mistakes( + fn look_for_iterator_item_mistakes( &self, assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>], typeck_results: &TypeckResults<'tcx>, @@ -3942,7 +3947,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { param_env: ty::ParamEnv<'tcx>, path_segment: &hir::PathSegment<'_>, args: &[hir::Expr<'_>], - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, G>, ) { let tcx = self.tcx; // Special case for iterator chains, we look at potential failures of `Iterator::Item` @@ -4037,13 +4042,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - fn point_at_chain( + fn point_at_chain( &self, expr: &hir::Expr<'_>, typeck_results: &TypeckResults<'tcx>, type_diffs: Vec>, param_env: ty::ParamEnv<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, G>, ) { let mut primary_spans = vec![]; let mut span_labels = vec![]; @@ -4279,7 +4284,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// the array into a slice. fn suggest_convert_to_slice( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, candidate_impls: &[ImplCandidate<'tcx>], @@ -4351,7 +4356,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn explain_hrtb_projection( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, pred: ty::PolyTraitPredicate<'tcx>, param_env: ty::ParamEnv<'tcx>, cause: &ObligationCause<'tcx>, @@ -4417,7 +4422,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn suggest_desugaring_async_fn_in_trait( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_ref: ty::PolyTraitRef<'tcx>, ) { // Don't suggest if RTN is active -- we should prefer a where-clause bound instead. @@ -4508,7 +4513,7 @@ fn hint_missing_borrow<'tcx>( found: Ty<'tcx>, expected: Ty<'tcx>, found_node: Node<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) { if matches!(found_node, Node::TraitItem(..)) { return; @@ -4867,9 +4872,9 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( /// On `impl` evaluation cycles, look for `Self::AssocTy` restrictions in `where` clauses, explain /// they are not allowed and if possible suggest alternatives. -fn point_at_assoc_type_restriction( +fn point_at_assoc_type_restriction( tcx: TyCtxt<'_>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, G>, self_ty_str: &str, trait_name: &str, predicate: ty::Predicate<'_>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 67bd18d7404..4f674ac7583 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -21,8 +21,8 @@ use crate::traits::{ }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, MultiSpan, StashKey, StringPart, + codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, + MultiSpan, StashKey, StringPart, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; @@ -185,7 +185,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { predicate: &T, span: Span, suggest_increasing_limit: bool, - mutate: impl FnOnce(&mut Diagnostic), + mutate: impl FnOnce(&mut DiagnosticBuilder<'_>), ) -> ! where T: fmt::Display + TypeFoldable> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>, @@ -272,7 +272,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } - fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) { + fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { let suggested_limit = match self.tcx.recursion_limit() { Limit(0) => Limit(2), limit => limit * 2, @@ -1020,7 +1020,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, trait_ref: ty::TraitRef<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) -> bool { let span = obligation.cause.span; struct V<'v> { @@ -1810,7 +1810,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { impl_candidates: &[ImplCandidate<'tcx>], trait_ref: ty::PolyTraitRef<'tcx>, body_def_id: LocalDefId, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, other: bool, param_env: ty::ParamEnv<'tcx>, ) -> bool { @@ -1897,7 +1897,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } let other = if other { "other " } else { "" }; - let report = |candidates: Vec>, err: &mut Diagnostic| { + let report = |candidates: Vec>, err: &mut DiagnosticBuilder<'_>| { if candidates.is_empty() { return false; } @@ -2032,7 +2032,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { obligation: &PredicateObligation<'tcx>, trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, body_def_id: LocalDefId, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) { // This is *almost* equivalent to // `obligation.cause.code().peel_derives()`, but it gives us the @@ -2103,7 +2103,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// a probable version mismatch is added to `err` fn note_version_mismatch( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::PolyTraitRef<'tcx>, ) -> bool { let get_trait_impls = |trait_def_id| { @@ -2572,7 +2572,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn annotate_source_of_ambiguity( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ambiguities: &[ambiguity::Ambiguity], predicate: ty::Predicate<'tcx>, ) { @@ -2715,7 +2715,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }) } - fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>) { + fn note_obligation_cause( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ) { // First, attempt to add note to this error with an async-await-specific // message, and fall back to regular note otherwise. if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { @@ -2744,7 +2748,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { #[instrument(level = "debug", skip_all)] fn suggest_unsized_bound_if_applicable( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, ) { let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = @@ -2770,7 +2774,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } #[instrument(level = "debug", skip_all)] - fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>) { + fn maybe_suggest_unsized_generics( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + node: Node<'tcx>, + ) { let Some(generics) = node.generics() else { return; }; @@ -2822,7 +2831,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn maybe_indirection_for_unsized( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, item: &Item<'tcx>, param: &GenericParam<'tcx>, ) -> bool { @@ -3016,7 +3025,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn add_tuple_trait_message( &self, obligation_cause_code: &ObligationCauseCode<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, ) { match obligation_cause_code { ObligationCauseCode::RustCall => { @@ -3041,7 +3050,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { obligation: &PredicateObligation<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, trait_predicate: &ty::PolyTraitPredicate<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, span: Span, is_fn_trait: bool, suggested: bool, @@ -3122,7 +3131,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn add_help_message_for_fn_trait( &self, trait_ref: ty::PolyTraitRef<'tcx>, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_>, implemented_kind: ty::ClosureKind, params: ty::Binder<'tcx, Ty<'tcx>>, ) { @@ -3178,7 +3187,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn maybe_add_note_for_unsatisfied_const( &self, _trait_predicate: &ty::PolyTraitPredicate<'tcx>, - _err: &mut Diagnostic, + _err: &mut DiagnosticBuilder<'_>, _span: Span, ) -> UnsatisfiedConst { let unsatisfied_const = UnsatisfiedConst(false); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5bcf46a96ed..77fe927797f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -29,7 +29,7 @@ use crate::traits::ProjectionCacheKey; use crate::traits::Unimplemented; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::Diagnostic; +use rustc_errors::{DiagnosticBuilder, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::BoundRegionConversionTime; @@ -70,7 +70,10 @@ pub enum IntercrateAmbiguityCause<'tcx> { impl<'tcx> IntercrateAmbiguityCause<'tcx> { /// Emits notes when the overlap is caused by complex intercrate ambiguities. /// See #23980 for details. - pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) { + pub fn add_intercrate_ambiguity_hint( + &self, + err: &mut DiagnosticBuilder<'_, G>, + ) { err.note(self.intercrate_ambiguity_hint()); } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index e1a49ecf1b6..56bc2f2cf25 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -20,7 +20,7 @@ use crate::traits::{ self, coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, }; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{codes::*, DelayDm, Diagnostic}; +use rustc_errors::{codes::*, DelayDm, DiagnosticBuilder, EmissionGuarantee}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; @@ -395,11 +395,11 @@ fn report_conflicting_impls<'tcx>( // Work to be done after we've built the DiagnosticBuilder. We have to define it // now because the lint emit methods don't return back the DiagnosticBuilder // that's passed in. - fn decorate<'tcx>( + fn decorate<'tcx, G: EmissionGuarantee>( tcx: TyCtxt<'tcx>, overlap: &OverlapError<'tcx>, impl_span: Span, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'_, G>, ) { if (overlap.trait_ref, overlap.self_ty).references_error() { err.downgrade_to_delayed_bug(); diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index af172eb0713..f3dad966fd5 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,7 +1,7 @@ use super::NormalizeExt; use super::{ObligationCause, PredicateObligation, SelectionContext}; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::Diagnostic; +use rustc_errors::DiagnosticBuilder; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferOk; use rustc_middle::ty::GenericArgsRef; @@ -43,7 +43,7 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> { /// trait aliases. pub fn label_with_exp_info( &self, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_>, top_label: &'static str, use_desc: &str, ) { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fe02611b5d4..a172580ac3f 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -8,7 +8,7 @@ use rustc_data_structures::{ fx::{FxHashMap, FxHashSet}, intern::Interned, }; -use rustc_errors::{Applicability, Diagnostic, DiagnosticMessage}; +use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticMessage}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{DefKind, Namespace, PerNS}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; @@ -1173,21 +1173,22 @@ impl LinkCollector<'_, '_> { ) { // The resolved item did not match the disambiguator; give a better error than 'not found' let msg = format!("incompatible link kind for `{path_str}`"); - let callback = |diag: &mut Diagnostic, sp: Option, link_range| { - let note = format!( - "this link resolved to {} {}, which is not {} {}", - resolved.article(), - resolved.descr(), - specified.article(), - specified.descr(), - ); - if let Some(sp) = sp { - diag.span_label(sp, note); - } else { - diag.note(note); - } - suggest_disambiguator(resolved, diag, path_str, link_range, sp, diag_info); - }; + let callback = + |diag: &mut DiagnosticBuilder<'_, ()>, sp: Option, link_range| { + let note = format!( + "this link resolved to {} {}, which is not {} {}", + resolved.article(), + resolved.descr(), + specified.article(), + specified.descr(), + ); + if let Some(sp) = sp { + diag.span_label(sp, note); + } else { + diag.note(note); + } + suggest_disambiguator(resolved, diag, path_str, link_range, sp, diag_info); + }; report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, callback); } @@ -1676,7 +1677,7 @@ fn report_diagnostic( lint: &'static Lint, msg: impl Into + Display, DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>, - decorate: impl FnOnce(&mut Diagnostic, Option, MarkdownLinkRange), + decorate: impl FnOnce(&mut DiagnosticBuilder<'_, ()>, Option, MarkdownLinkRange), ) { let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) else { // If non-local, no need to check anything. @@ -2124,7 +2125,7 @@ fn ambiguity_error( /// disambiguator. fn suggest_disambiguator( res: Res, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_, ()>, path_str: &str, link_range: MarkdownLinkRange, sp: Option, diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index f99a51e2b88..1543ae80399 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -4,7 +4,7 @@ use clippy_utils::expr_or_init; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; -use rustc_errors::{Applicability, Diagnostic, SuggestionStyle}; +use rustc_errors::{Applicability, DiagnosticBuilder, SuggestionStyle}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -177,7 +177,7 @@ fn offer_suggestion( expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to_span: Span, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_, ()>, ) { let cast_to_snip = snippet(cx, cast_to_span, ".."); let suggestion = if cast_to_snip == "_" { diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index f1200c2edc1..9505741e68f 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -1,4 +1,4 @@ -use rustc_errors::Diagnostic; +use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; @@ -135,7 +135,7 @@ fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty RESULT_LARGE_ERR, hir_ty_span, "the `Err`-variant returned from this function is very large", - |diag: &mut Diagnostic| { + |diag: &mut DiagnosticBuilder<'_, ()>| { diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes")); diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`")); }, diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs index 5e354209cbf..61a322ea881 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{higher, SpanlessEq}; -use rustc_errors::Diagnostic; +use rustc_errors::DiagnosticBuilder; use rustc_hir::intravisit::{self as visit, Visitor}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { arm_visit.visit_expr(if_else); if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) { - let diag = |diag: &mut Diagnostic| { + let diag = |diag: &mut DiagnosticBuilder<'_, ()>| { diag.span_label( op_mutex.span, "this Mutex will remain locked for the entire `if let`-block...", diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 87f6f5e7959..746de50c0fa 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::collections::BTreeMap; -use rustc_errors::Diagnostic; +use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor}; use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind}; @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { fn suggestion( cx: &LateContext<'_>, - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_, ()>, generics_span: Span, generics_suggestion_span: Span, target: &ImplicitHasherType<'_>, diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index 0da309f9531..12bb80dfde2 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -9,7 +9,7 @@ use clippy_utils::{ peel_blocks_with_stmt, MaybePath, }; use itertools::Itertools; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir::def::Res; use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -163,7 +163,7 @@ fn emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggestion<'t }; let suggestion = format!("{assignment}{input}.clamp({min}, {max}){semicolon}"); let msg = "clamp-like pattern without using clamp function"; - let lint_builder = |d: &mut Diagnostic| { + let lint_builder = |d: &mut DiagnosticBuilder<'_, ()>| { d.span_suggestion(*span, "replace with clamp", suggestion, Applicability::MaybeIncorrect); if *is_float { d.note("clamp will panic if max < min, min.is_nan(), or max.is_nan()") diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index ee0fdb35313..a7e42fd2405 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -2,7 +2,7 @@ use crate::FxHashSet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{indent_of, snippet}; use clippy_utils::{get_attr, is_lint_allowed}; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LintContext}; @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>( } } -fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) { +fn set_diagnostic<'tcx>(diag: &mut DiagnosticBuilder<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) { if found.lint_suggestion == LintSuggestion::MoveAndClone { // If our suggestion is to move and clone, then we want to leave it to the user to // decide how to address this lint, since it may be that cloning is inappropriate. diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs index b2c5987e43d..617d6d998fc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_lint::LateContext; use rustc_span::{sym, Span}; use {rustc_ast as ast, rustc_hir as hir}; @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg SUSPICIOUS_COMMAND_ARG_SPACE, arg.span, "single argument that looks like it should be multiple arguments", - |diag: &mut Diagnostic| { + |diag: &mut DiagnosticBuilder<'_, ()>| { diag.multipart_suggestion_verbose( "consider splitting the argument", vec![(span, "args".to_string()), (arg.span, format!("[{arg1:?}, {arg2:?}]"))], diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index 0e4d39c9990..ab25dde7efe 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -9,7 +9,7 @@ use clippy_utils::{eq_expr_value, hash_expr, higher}; use rustc_ast::{LitKind, RangeLimits}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir::{BinOp, Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -67,7 +67,7 @@ declare_lint_pass!(MissingAssertsForIndexing => [MISSING_ASSERTS_FOR_INDEXING]); fn report_lint(cx: &LateContext<'_>, full_span: Span, msg: &str, indexes: &[Span], f: F) where - F: FnOnce(&mut Diagnostic), + F: FnOnce(&mut DiagnosticBuilder<'_, ()>), { span_lint_and_then(cx, MISSING_ASSERTS_FOR_INDEXING, full_span, msg, |diag| { f(diag); diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 384a402ce5b..6252f91b25f 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -6,7 +6,7 @@ use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; use rustc_ast::ast::Attribute; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir::intravisit::FnKind; use rustc_hir::{ BindingAnnotation, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node, PatKind, @@ -196,7 +196,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { && !moved_vars.contains(&canonical_id) { // Dereference suggestion - let sugg = |diag: &mut Diagnostic| { + let sugg = |diag: &mut DiagnosticBuilder<'_, ()>| { if let ty::Adt(def, ..) = ty.kind() { if let Some(span) = cx.tcx.hir().span_if_local(def.did()) { if type_allowed_to_implement_copy( diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 5199959c0f2..db94b60dc95 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -8,13 +8,13 @@ //! Thank you! //! ~The `INTERNAL_METADATA_COLLECTOR` lint -use rustc_errors::{Applicability, Diagnostic, MultiSpan}; +use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; use rustc_span::Span; use std::env; -fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) { +fn docs_link(diag: &mut DiagnosticBuilder<'_, ()>, lint: &'static Lint) { if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() { if let Some(lint) = lint.name_lower().strip_prefix("clippy::") { diag.help(format!( @@ -143,7 +143,7 @@ pub fn span_lint_and_then(cx: &C, lint: &'static Lint, sp: S, msg: &str where C: LintContext, S: Into, - F: FnOnce(&mut Diagnostic), + F: FnOnce(&mut DiagnosticBuilder<'_, ()>), { #[expect(clippy::disallowed_methods)] cx.span_lint(lint, sp, msg.to_string(), |diag| { @@ -165,7 +165,7 @@ pub fn span_lint_hir_and_then( hir_id: HirId, sp: impl Into, msg: &str, - f: impl FnOnce(&mut Diagnostic), + f: impl FnOnce(&mut DiagnosticBuilder<'_, ()>), ) { #[expect(clippy::disallowed_methods)] cx.tcx.node_span_lint(lint, hir_id, sp, msg.to_string(), |diag| { @@ -214,7 +214,7 @@ pub fn span_lint_and_sugg( /// appear once per /// replacement. In human-readable format though, it only appears once before /// the whole suggestion. -pub fn multispan_sugg(diag: &mut Diagnostic, help_msg: &str, sugg: I) +pub fn multispan_sugg(diag: &mut DiagnosticBuilder<'_, ()>, help_msg: &str, sugg: I) where I: IntoIterator, { @@ -227,7 +227,7 @@ where /// multiple spans. This is tracked in issue [rustfix#141](https://github.com/rust-lang/rustfix/issues/141). /// Suggestions with multiple spans will be silently ignored. pub fn multispan_sugg_with_applicability( - diag: &mut Diagnostic, + diag: &mut DiagnosticBuilder<'_, ()>, help_msg: &str, applicability: Applicability, sugg: I, -- cgit 1.4.1-3-g733a5 From 9c32a7d61b052d07c5fdbedb1a4678bcc848236e Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Mon, 19 Feb 2024 17:43:09 +0800 Subject: target: Revert default to the medium code model on LoongArch targets This reverts commit 35dad14dfb63d77cf4a2077f1e8e9cff5a02a92b. Fixes #121289 --- .../rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs | 3 +-- compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs | 2 +- .../src/spec/targets/loongarch64_unknown_none_softfloat.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs index f4350708986..234270c999b 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs @@ -1,4 +1,4 @@ -use crate::spec::{base, CodeModel, Target, TargetOptions}; +use crate::spec::{base, Target, TargetOptions}; pub fn target() -> Target { Target { @@ -7,7 +7,6 @@ pub fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(), arch: "loongarch64".into(), options: TargetOptions { - code_model: Some(CodeModel::Medium), cpu: "generic".into(), features: "+f,+d".into(), llvm_abiname: "lp64d".into(), diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs index f448017a2a5..3b1ea8e206f 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { max_atomic_width: Some(64), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - code_model: Some(CodeModel::Medium), + code_model: Some(CodeModel::Small), ..Default::default() }, } diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs index d636c9599a7..ab9300ef9c7 100644 --- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { max_atomic_width: Some(64), relocation_model: RelocModel::Static, panic_strategy: PanicStrategy::Abort, - code_model: Some(CodeModel::Medium), + code_model: Some(CodeModel::Small), ..Default::default() }, } -- cgit 1.4.1-3-g733a5 From 94ddbb615d290ece648076f7d34198249a191fff Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 19 Feb 2024 12:13:01 +0100 Subject: Remove MACOSX_DEPLOYMENT_TARGET env var when linking Mac Catalyst Mac Catalyst uses IPHONEOS_DEPLOYMENT_TARGET to specify the deployment target, so it makes no sense to remove that variable. --- compiler/rustc_target/src/spec/base/apple/mod.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index aee5d60626e..0724ba53f4e 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -131,7 +131,7 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions { abi: abi.into(), os: os.into(), cpu: arch.target_cpu().into(), - link_env_remove: link_env_remove(arch, os), + link_env_remove: link_env_remove(os), vendor: "apple".into(), linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No), // macOS has -dead_strip, which doesn't rely on function_sections @@ -270,7 +270,7 @@ pub fn macos_llvm_target(arch: Arch) -> String { format!("{}-apple-macosx{}.{}.0", arch.target_name(), major, minor) } -fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow]> { +fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow]> { // Apple platforms only officially support macOS as a host for any compilation. // // If building for macOS, we go ahead and remove any erroneous environment state @@ -298,15 +298,9 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow]> env_remove.push("TVOS_DEPLOYMENT_TARGET".into()); env_remove.into() } else { - // Otherwise if cross-compiling for a different OS/SDK, remove any part + // Otherwise if cross-compiling for a different OS/SDK (including Mac Catalyst), remove any part // of the linking environment that's wrong and reversed. - match arch { - Armv7k | Armv7s | Arm64 | Arm64e | Arm64_32 | I386 | I386_sim | I686 | X86_64 - | X86_64_sim | X86_64h | Arm64_sim => { - cvs!["MACOSX_DEPLOYMENT_TARGET"] - } - X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"], - } + cvs!["MACOSX_DEPLOYMENT_TARGET"] } } -- cgit 1.4.1-3-g733a5 From 92d4b313eb11a24292e1c91b07a2887b719265d4 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 19 Feb 2024 12:45:11 +0100 Subject: Make LLVM target contain correct deployment target info on Mac Catalyst --- compiler/rustc_target/src/spec/base/apple/mod.rs | 21 +++++++++++++++++---- .../src/spec/targets/aarch64_apple_ios_macabi.rs | 9 +++------ .../src/spec/targets/x86_64_apple_ios_macabi.rs | 9 +++------ 3 files changed, 23 insertions(+), 16 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 0724ba53f4e..1caa0eccc62 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -106,11 +106,9 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { } .into(); - let arch = arch.target_name(); - let mut args = TargetOptions::link_args( LinkerFlavor::Darwin(Cc::No, Lld::No), - &["-arch", arch, "-platform_version"], + &["-arch", arch.target_name(), "-platform_version"], ); add_link_args_iter( &mut args, @@ -118,7 +116,17 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { [platform_name, platform_version.clone(), platform_version].into_iter(), ); if abi != "macabi" { - add_link_args(&mut args, LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-arch", arch]); + add_link_args( + &mut args, + LinkerFlavor::Darwin(Cc::Yes, Lld::No), + &["-arch", arch.target_name()], + ); + } else { + add_link_args_iter( + &mut args, + LinkerFlavor::Darwin(Cc::Yes, Lld::No), + ["-target".into(), mac_catalyst_llvm_target(arch).into()].into_iter(), + ); } args @@ -326,6 +334,11 @@ pub fn ios_llvm_target(arch: Arch) -> String { format!("{}-apple-ios{}.{}.0", arch.target_name(), major, minor) } +pub fn mac_catalyst_llvm_target(arch: Arch) -> String { + let (major, minor) = mac_catalyst_deployment_target(); + format!("{}-apple-ios{}.{}.0-macabi", arch.target_name(), major, minor) +} + fn ios_lld_platform_version(arch: Arch) -> String { let (major, minor) = ios_deployment_target(arch); format!("{major}.{minor}") diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs index 78067a138a9..300e3014079 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs @@ -1,16 +1,13 @@ -use crate::spec::base::apple::{opts, Arch}; -use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions}; +use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch}; +use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { - let llvm_target = "arm64-apple-ios14.0-macabi"; - let arch = Arch::Arm64_macabi; let mut base = opts("ios", arch); - base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; Target { - llvm_target: llvm_target.into(), + llvm_target: mac_catalyst_llvm_target(arch).into(), pointer_width: 64, data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), arch: arch.target_arch(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs index ff21e489333..e59f41185de 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs @@ -1,16 +1,13 @@ -use crate::spec::base::apple::{opts, Arch}; -use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions}; +use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch}; +use crate::spec::{SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { - let llvm_target = "x86_64-apple-ios14.0-macabi"; - let arch = Arch::X86_64_macabi; let mut base = opts("ios", arch); - base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; Target { - llvm_target: llvm_target.into(), + llvm_target: mac_catalyst_llvm_target(arch).into(), pointer_width: 64, data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), -- cgit 1.4.1-3-g733a5 From 3cb4e34310e3548a540b5a3e72567ffb7883b38e Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 19 Feb 2024 13:10:07 +0100 Subject: Fix ld platform_version argument on Mac Catalyst --- compiler/rustc_target/src/spec/base/apple/mod.rs | 42 ++++++++---------------- 1 file changed, 13 insertions(+), 29 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 1caa0eccc62..7044e5f8ffc 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -97,14 +97,18 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { _ => os.into(), }; - let platform_version: StaticCow = match os { - "ios" => ios_lld_platform_version(arch), - "tvos" => tvos_lld_platform_version(), - "watchos" => watchos_lld_platform_version(), - "macos" => macos_lld_platform_version(arch), - _ => unreachable!(), - } - .into(); + let min_version: StaticCow = { + let (major, minor) = match (os, abi) { + ("ios", "macabi") => mac_catalyst_deployment_target(), + ("ios", _) => ios_deployment_target(arch), + ("tvos", _) => tvos_deployment_target(), + ("watchos", _) => watchos_deployment_target(), + ("macos", _) => macos_deployment_target(arch), + _ => unreachable!(), + }; + format!("{major}.{minor}").into() + }; + let sdk_version = min_version.clone(); let mut args = TargetOptions::link_args( LinkerFlavor::Darwin(Cc::No, Lld::No), @@ -113,7 +117,7 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { add_link_args_iter( &mut args, LinkerFlavor::Darwin(Cc::No, Lld::No), - [platform_name, platform_version.clone(), platform_version].into_iter(), + [platform_name, min_version, sdk_version].into_iter(), ); if abi != "macabi" { add_link_args( @@ -268,11 +272,6 @@ fn macos_deployment_target(arch: Arch) -> (u32, u32) { .unwrap_or_else(|| macos_default_deployment_target(arch)) } -fn macos_lld_platform_version(arch: Arch) -> String { - let (major, minor) = macos_deployment_target(arch); - format!("{major}.{minor}") -} - pub fn macos_llvm_target(arch: Arch) -> String { let (major, minor) = macos_deployment_target(arch); format!("{}-apple-macosx{}.{}.0", arch.target_name(), major, minor) @@ -339,11 +338,6 @@ pub fn mac_catalyst_llvm_target(arch: Arch) -> String { format!("{}-apple-ios{}.{}.0-macabi", arch.target_name(), major, minor) } -fn ios_lld_platform_version(arch: Arch) -> String { - let (major, minor) = ios_deployment_target(arch); - format!("{major}.{minor}") -} - pub fn ios_sim_llvm_target(arch: Arch) -> String { let (major, minor) = ios_deployment_target(arch); format!("{}-apple-ios{}.{}.0-simulator", arch.target_name(), major, minor) @@ -354,11 +348,6 @@ fn tvos_deployment_target() -> (u32, u32) { from_set_deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((10, 0)) } -fn tvos_lld_platform_version() -> String { - let (major, minor) = tvos_deployment_target(); - format!("{major}.{minor}") -} - pub fn tvos_llvm_target(arch: Arch) -> String { let (major, minor) = tvos_deployment_target(); format!("{}-apple-tvos{}.{}.0", arch.target_name(), major, minor) @@ -374,11 +363,6 @@ fn watchos_deployment_target() -> (u32, u32) { from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0)) } -fn watchos_lld_platform_version() -> String { - let (major, minor) = watchos_deployment_target(); - format!("{major}.{minor}") -} - pub fn watchos_sim_llvm_target(arch: Arch) -> String { let (major, minor) = watchos_deployment_target(); format!("{}-apple-watchos{}.{}.0-simulator", arch.target_name(), major, minor) -- cgit 1.4.1-3-g733a5 From cd530fccb3f4bc870d3e671d6944fa2883720b14 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 19 Feb 2024 13:09:47 +0100 Subject: Merge deployment target variable loading on iOS and Mac Catalyst --- compiler/rustc_target/src/spec/base/apple/mod.rs | 47 +++++++++++------------- 1 file changed, 21 insertions(+), 26 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 7044e5f8ffc..322d1c4e5f6 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -98,12 +98,11 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { }; let min_version: StaticCow = { - let (major, minor) = match (os, abi) { - ("ios", "macabi") => mac_catalyst_deployment_target(), - ("ios", _) => ios_deployment_target(arch), - ("tvos", _) => tvos_deployment_target(), - ("watchos", _) => watchos_deployment_target(), - ("macos", _) => macos_deployment_target(arch), + let (major, minor) = match os { + "ios" => ios_deployment_target(arch, abi), + "tvos" => tvos_deployment_target(), + "watchos" => watchos_deployment_target(), + "macos" => macos_deployment_target(arch), _ => unreachable!(), }; format!("{major}.{minor}").into() @@ -232,16 +231,13 @@ pub fn deployment_target(target: &Target) -> Option<(u32, u32)> { }; macos_deployment_target(arch) } - "ios" => match &*target.abi { - "macabi" => mac_catalyst_deployment_target(), - _ => { - let arch = match target.arch.as_ref() { - "arm64e" => Arm64e, - _ => Arm64, - }; - ios_deployment_target(arch) - } - }, + "ios" => { + let arch = match target.arch.as_ref() { + "arm64e" => Arm64e, + _ => Arm64, + }; + ios_deployment_target(arch, &target.abi) + } "watchos" => watchos_deployment_target(), "tvos" => tvos_deployment_target(), _ => return None, @@ -311,17 +307,16 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow]> { } } -fn ios_deployment_target(arch: Arch) -> (u32, u32) { +fn ios_deployment_target(arch: Arch, abi: &str) -> (u32, u32) { // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. - let (major, minor) = if arch == Arm64e { (14, 0) } else { (10, 0) }; + let (major, minor) = match (arch, abi) { + (Arm64e, _) => (14, 0), + (_, "macabi") => (14, 0), + _ => (10, 0), + }; from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((major, minor)) } -fn mac_catalyst_deployment_target() -> (u32, u32) { - // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. - from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((14, 0)) -} - pub fn ios_llvm_target(arch: Arch) -> String { // Modern iOS tooling extracts information about deployment target // from LC_BUILD_VERSION. This load command will only be emitted when @@ -329,17 +324,17 @@ pub fn ios_llvm_target(arch: Arch) -> String { // set high enough. Luckily one LC_BUILD_VERSION is enough, for Xcode // to pick it up (since std and core are still built with the fallback // of version 7.0 and hence emit the old LC_IPHONE_MIN_VERSION). - let (major, minor) = ios_deployment_target(arch); + let (major, minor) = ios_deployment_target(arch, ""); format!("{}-apple-ios{}.{}.0", arch.target_name(), major, minor) } pub fn mac_catalyst_llvm_target(arch: Arch) -> String { - let (major, minor) = mac_catalyst_deployment_target(); + let (major, minor) = ios_deployment_target(arch, "macabi"); format!("{}-apple-ios{}.{}.0-macabi", arch.target_name(), major, minor) } pub fn ios_sim_llvm_target(arch: Arch) -> String { - let (major, minor) = ios_deployment_target(arch); + let (major, minor) = ios_deployment_target(arch, "sim"); format!("{}-apple-ios{}.{}.0-simulator", arch.target_name(), major, minor) } -- cgit 1.4.1-3-g733a5 From a3cf493642e770783d2bd89deb8afe90af45525b Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 19 Feb 2024 13:30:53 +0100 Subject: Lower default Mac Catalyst deployment target to 13.1 Same default as Clang: https://github.com/llvm/llvm-project/blob/d022f32c73c57b59a9121eba909f5034e89c628e/clang/lib/Driver/ToolChains/Darwin.cpp#L2038 --- compiler/rustc_target/src/spec/base/apple/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'compiler') diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 322d1c4e5f6..dd75377ead2 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -311,7 +311,8 @@ fn ios_deployment_target(arch: Arch, abi: &str) -> (u32, u32) { // If you are looking for the default deployment target, prefer `rustc --print deployment-target`. let (major, minor) = match (arch, abi) { (Arm64e, _) => (14, 0), - (_, "macabi") => (14, 0), + // Mac Catalyst defaults to 13.1 in Clang. + (_, "macabi") => (13, 1), _ => (10, 0), }; from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((major, minor)) -- cgit 1.4.1-3-g733a5 From b4a424feb84f8b43fde0f76984da6b79efa0654f Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 19 Feb 2024 17:04:23 +0000 Subject: Drive-by `DUMMY_SP` -> `Span` and fmt changes Noticed these while doing something else. There's no practical change, but it's preferable to use `DUMMY_SP` as little as possible, particularly when we have perfectlly useful `Span`s available. --- compiler/rustc_borrowck/src/type_check/canonical.rs | 2 +- .../src/type_check/constraint_conversion.rs | 4 ++-- .../src/type_check/free_region_relations.rs | 16 ++++++++++------ compiler/rustc_borrowck/src/type_check/mod.rs | 6 +++--- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../rustc_infer/src/infer/canonical/query_response.rs | 2 +- .../rustc_trait_selection/src/traits/outlives_bounds.rs | 5 ++--- tests/ui/inference/issue-80409.no-compat.stderr | 12 +++++++++++- tests/ui/inference/issue-80409.rs | 1 + 9 files changed, 32 insertions(+), 18 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index fc600af1b76..e5ebf97cfc4 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -100,7 +100,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, ) { for (predicate, span) in instantiated_predicates { - debug!(?predicate); + debug!(?span, ?predicate); let category = ConstraintCategory::Predicate(span); let predicate = self.normalize_with_category(predicate, locations, category); self.prove_predicate(predicate, locations, category); diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index c97e3170166..de75a9857f8 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -8,7 +8,7 @@ use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Const use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_trait_selection::solve::deeply_normalize; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -183,7 +183,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // we don't actually use this for anything, but // the `TypeOutlives` code needs an origin. - let origin = infer::RelateParamBound(DUMMY_SP, t1, None); + let origin = infer::RelateParamBound(self.span, t1, None); TypeOutlives::new( &mut *self, diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 2e0caf44819..356f0024c07 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; -use rustc_span::{ErrorGuaranteed, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::solve::deeply_normalize; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; @@ -269,7 +269,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { debug!("build: input_or_output={:?}", ty); // We add implied bounds from both the unnormalized and normalized ty. // See issue #87748 - let constraints_unnorm = self.add_implied_bounds(ty); + let constraints_unnorm = self.add_implied_bounds(ty, span); if let Some(c) = constraints_unnorm { constraints.push(c) } @@ -299,7 +299,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // ``` // Both &Self::Bar and &() are WF if ty != norm_ty { - let constraints_norm = self.add_implied_bounds(norm_ty); + let constraints_norm = self.add_implied_bounds(norm_ty, span); if let Some(c) = constraints_norm { constraints.push(c) } @@ -323,7 +323,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // We currently add implied bounds from the normalized ty only. // This is more conservative and matches wfcheck behavior. - let c = self.add_implied_bounds(norm_ty); + let c = self.add_implied_bounds(norm_ty, span); constraints.extend(c); } } @@ -361,11 +361,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { /// the same time, compute and add any implied bounds that come /// from this local. #[instrument(level = "debug", skip(self))] - fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<&'tcx QueryRegionConstraints<'tcx>> { + fn add_implied_bounds( + &mut self, + ty: Ty<'tcx>, + span: Span, + ) -> Option<&'tcx QueryRegionConstraints<'tcx>> { let TypeOpOutput { output: bounds, constraints, .. } = self .param_env .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) - .fully_perform(self.infcx, DUMMY_SP) + .fully_perform(self.infcx, span) .map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty)) .ok()?; debug!(?bounds, ?constraints); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 64469727d0d..f96c2cbd8c0 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -37,7 +37,7 @@ use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; @@ -1014,7 +1014,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ) -> Self { let mut checker = Self { infcx, - last_span: DUMMY_SP, + last_span: body.span, body, user_type_annotations: &body.user_type_annotations, param_env, @@ -2766,7 +2766,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.param_env, self.known_type_outlives_obligations, locations, - DUMMY_SP, // irrelevant; will be overridden. + self.body.span, // irrelevant; will be overridden. ConstraintCategory::Boring, // same as above. self.borrowck_context.constraints, ) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index a5ef1490bce..cffb88a1365 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1630,7 +1630,7 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>( #[instrument(level = "debug", skip(tcx))] fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { let mut result = tcx.explicit_predicates_of(def_id); - debug!("predicates_defined_on: explicit_predicates_of({:?}) = {:?}", def_id, result,); + debug!("predicates_defined_on: explicit_predicates_of({:?}) = {:?}", def_id, result); let inferred_outlives = tcx.inferred_outlives_of(def_id); if !inferred_outlives.is_empty() { debug!( diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 56a45586c9d..6d1abc33ae7 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -405,7 +405,7 @@ impl<'tcx> InferCtxt<'tcx> { /// will instantiate fresh inference variables for each canonical /// variable instead. Therefore, the result of this method must be /// properly unified - #[instrument(level = "debug", skip(self, cause, param_env))] + #[instrument(level = "debug", skip(self, param_env))] fn query_response_instantiation_guess( &self, cause: &ObligationCause<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 6825dd4ac71..8b2e8b54aee 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -62,9 +62,10 @@ fn implied_outlives_bounds<'a, 'tcx>( }; let mut constraints = QueryRegionConstraints::default(); + let span = infcx.tcx.def_span(body_id); let Ok(InferOk { value: mut bounds, obligations }) = infcx .instantiate_nll_query_response_and_region_obligations( - &ObligationCause::dummy(), + &ObligationCause::dummy_with_span(span), param_env, &canonical_var_values, canonical_result, @@ -80,8 +81,6 @@ fn implied_outlives_bounds<'a, 'tcx>( bounds.retain(|bound| !bound.has_placeholders()); if !constraints.is_empty() { - let span = infcx.tcx.def_span(body_id); - debug!(?constraints); if !constraints.member_constraints.is_empty() { span_bug!(span, "{:#?}", constraints.member_constraints); diff --git a/tests/ui/inference/issue-80409.no-compat.stderr b/tests/ui/inference/issue-80409.no-compat.stderr index 7bb4786db3a..f9772b2d5a6 100644 --- a/tests/ui/inference/issue-80409.no-compat.stderr +++ b/tests/ui/inference/issue-80409.no-compat.stderr @@ -1,6 +1,16 @@ error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ImpliedOutlivesBounds { ty: &'?2 mut StateContext<'?3, usize> } } + --> $DIR/issue-80409.rs:49:30 | - = query stack during panic: +LL | builder.state().on_entry(|_| {}); + | ^^^ + | +note: + --> $DIR/issue-80409.rs:49:30 + | +LL | builder.state().on_entry(|_| {}); + | ^^^ + +query stack during panic: end of query stack error: aborting due to 1 previous error diff --git a/tests/ui/inference/issue-80409.rs b/tests/ui/inference/issue-80409.rs index e54da78614f..dfb84563e6d 100644 --- a/tests/ui/inference/issue-80409.rs +++ b/tests/ui/inference/issue-80409.rs @@ -8,6 +8,7 @@ //@[no-compat] check-fail //@[no-compat] known-bug: #80409 //@[no-compat] failure-status: 101 +//@[no-compat] normalize-stderr-test "delayed at.*" -> "" //@[no-compat] normalize-stderr-test "note: .*\n\n" -> "" //@[no-compat] normalize-stderr-test "thread 'rustc' panicked.*\n" -> "" //@[no-compat] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " -- cgit 1.4.1-3-g733a5 From 48b83e8a63c9108acd6e62228235e577f7c667d0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 21:25:55 +0100 Subject: Switch to Vec of MatchPairs Because I'm about to make MatchPair recursive, which I can't do with SmallVec, and I need to share code between the two. --- compiler/rustc_mir_build/src/build/matches/mod.rs | 6 ++---- compiler/rustc_mir_build/src/build/matches/util.rs | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 35f5a6bfac5..74be541d962 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -22,8 +22,6 @@ use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Pos, Span}; use rustc_target::abi::VariantIdx; -use smallvec::{smallvec, SmallVec}; - // helper functions, broken out by category: mod simplify; mod test; @@ -949,7 +947,7 @@ struct Candidate<'pat, 'tcx> { has_guard: bool, /// All of these must be satisfied... - match_pairs: SmallVec<[MatchPair<'pat, 'tcx>; 1]>, + match_pairs: Vec>, /// ...these bindings established... bindings: Vec>, @@ -979,7 +977,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { Candidate { span: pattern.span, has_guard, - match_pairs: smallvec![MatchPair::new(place, pattern, cx)], + match_pairs: vec![MatchPair::new(place, pattern, cx)], bindings: Vec::new(), ascriptions: Vec::new(), subcandidates: Vec::new(), diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index c34105174ef..5eb853989d0 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -6,7 +6,6 @@ use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty; use rustc_middle::ty::TypeVisitableExt; -use smallvec::SmallVec; impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn field_match_pairs<'pat>( @@ -26,7 +25,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn prefix_slice_suffix<'pat>( &mut self, - match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, + match_pairs: &mut Vec>, place: &PlaceBuilder<'tcx>, prefix: &'pat [Box>], opt_slice: &'pat Option>>, -- cgit 1.4.1-3-g733a5 From bafad5a737a2afac7926cc0ead6c9f76baf089cb Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 22:06:28 +0100 Subject: Move `Or` test outside of `simplify_candidate` --- compiler/rustc_mir_build/src/build/matches/mod.rs | 18 +++++++++- .../rustc_mir_build/src/build/matches/simplify.rs | 39 +++++----------------- 2 files changed, 26 insertions(+), 31 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 74be541d962..b35a0c3c671 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1168,7 +1168,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // be a switch or pattern comparison. let mut split_or_candidate = false; for candidate in &mut *candidates { - split_or_candidate |= self.simplify_candidate(candidate); + self.simplify_candidate(candidate); + if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = + &*candidate.match_pairs + { + // Split a candidate in which the only match-pair is an or-pattern into multiple + // candidates. This is so that + // + // match x { + // 0 | 1 => { ... }, + // 2 | 3 => { ... }, + // } + // + // only generates a single switch. + candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats); + candidate.match_pairs.pop(); + split_or_candidate = true; + } } ensure_sufficient_stack(|| { diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index dba8e8b6499..a74b664441a 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -23,23 +23,8 @@ use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Simplify a candidate so that all match pairs require a test. - /// - /// This method will also split a candidate, in which the only - /// match-pair is an or-pattern, into multiple candidates. - /// This is so that - /// - /// match x { - /// 0 | 1 => { ... }, - /// 2 | 3 => { ... }, - /// } - /// - /// only generates a single switch. If this happens this method returns - /// `true`. #[instrument(skip(self, candidate), level = "debug")] - pub(super) fn simplify_candidate<'pat>( - &mut self, - candidate: &mut Candidate<'pat, 'tcx>, - ) -> bool { + pub(super) fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) { debug!("{candidate:#?}"); // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the // bindings in `pat` before `x`. E.g. (#69971): @@ -97,30 +82,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Store computed bindings back in `candidate`. mem::swap(&mut candidate.bindings, &mut accumulated_bindings); - let did_expand_or = - if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = - &*candidate.match_pairs - { - candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats); - candidate.match_pairs.clear(); - true - } else { - false - }; - // Move or-patterns to the end, because they can result in us // creating additional candidates, so we want to test them as // late as possible. candidate.match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); debug!(simplified = ?candidate, "simplify_candidate"); - - did_expand_or } /// Given `candidate` that has a single or-pattern for its match-pairs, /// creates a fresh candidate for each of its input subpatterns passed via /// `pats`. - fn create_or_subcandidates<'pat>( + pub(super) fn create_or_subcandidates<'pat>( &mut self, candidate: &Candidate<'pat, 'tcx>, place: &PlaceBuilder<'tcx>, @@ -130,6 +102,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|box pat| { let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard, self); self.simplify_candidate(&mut candidate); + + if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = + &*candidate.match_pairs + { + candidate.subcandidates = self.create_or_subcandidates(&candidate, place, pats); + candidate.match_pairs.pop(); + } candidate }) .collect() -- cgit 1.4.1-3-g733a5 From e86c82296f26454d7451d64586062b59c9b62d22 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 21:38:24 +0100 Subject: Make `simplify_candidate` more general Because we will soon need to apply it to match pairs that aren't directly in a candidate. --- compiler/rustc_mir_build/src/build/matches/mod.rs | 9 +- .../rustc_mir_build/src/build/matches/simplify.rs | 95 +++++++++++----------- 2 files changed, 56 insertions(+), 48 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index b35a0c3c671..bb307089f1c 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1168,7 +1168,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // be a switch or pattern comparison. let mut split_or_candidate = false; for candidate in &mut *candidates { - self.simplify_candidate(candidate); + self.simplify_match_pairs( + &mut candidate.match_pairs, + &mut candidate.bindings, + &mut candidate.ascriptions, + ); if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = &*candidate.match_pairs { @@ -1181,7 +1185,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // } // // only generates a single switch. - candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats); + candidate.subcandidates = + self.create_or_subcandidates(place, pats, candidate.has_guard); candidate.match_pairs.pop(); split_or_candidate = true; } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a74b664441a..040d38c109b 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -6,7 +6,7 @@ //! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]` //! - `place @ x` can be simplified to `[]` by binding `x` to `place` //! -//! The `simplify_candidate` routine just repeatedly applies these +//! The `simplify_match_pairs` routine just repeatedly applies these //! sort of simplifications until there is nothing left to //! simplify. Match pairs cannot be simplified if they require some //! sort of test: for example, testing which variant an enum is, or @@ -22,10 +22,15 @@ use rustc_middle::ty; use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { - /// Simplify a candidate so that all match pairs require a test. - #[instrument(skip(self, candidate), level = "debug")] - pub(super) fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) { - debug!("{candidate:#?}"); + /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and + /// ascriptions in the provided `Vec`s. + #[instrument(skip(self), level = "debug")] + pub(super) fn simplify_match_pairs<'pat>( + &mut self, + match_pairs: &mut Vec>, + candidate_bindings: &mut Vec>, + candidate_ascriptions: &mut Vec>, + ) { // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the // bindings in `pat` before `x`. E.g. (#69971): // @@ -53,25 +58,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // bindings in iter 2: [6, 7] // // final bindings: [6, 7, 4, 5, 1, 2, 3] - let mut accumulated_bindings = mem::take(&mut candidate.bindings); + let mut accumulated_bindings = mem::take(candidate_bindings); // Repeatedly simplify match pairs until fixed point is reached loop { let mut changed = false; - for match_pair in mem::take(&mut candidate.match_pairs) { - match self.simplify_match_pair(match_pair, candidate) { + for match_pair in mem::take(match_pairs) { + match self.simplify_match_pair( + match_pair, + candidate_bindings, + candidate_ascriptions, + match_pairs, + ) { Ok(()) => { changed = true; } Err(match_pair) => { - candidate.match_pairs.push(match_pair); + match_pairs.push(match_pair); } } } // This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings - candidate.bindings.extend_from_slice(&accumulated_bindings); - mem::swap(&mut candidate.bindings, &mut accumulated_bindings); - candidate.bindings.clear(); + candidate_bindings.extend_from_slice(&accumulated_bindings); + mem::swap(candidate_bindings, &mut accumulated_bindings); + candidate_bindings.clear(); if !changed { // If we were not able to simplify anymore, done. @@ -79,14 +89,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - // Store computed bindings back in `candidate`. - mem::swap(&mut candidate.bindings, &mut accumulated_bindings); + // Store computed bindings back in `candidate_bindings`. + mem::swap(candidate_bindings, &mut accumulated_bindings); // Move or-patterns to the end, because they can result in us // creating additional candidates, so we want to test them as // late as possible. - candidate.match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); - debug!(simplified = ?candidate, "simplify_candidate"); + match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); + debug!(simplified = ?match_pairs, "simplify_match_pairs"); } /// Given `candidate` that has a single or-pattern for its match-pairs, @@ -94,19 +104,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// `pats`. pub(super) fn create_or_subcandidates<'pat>( &mut self, - candidate: &Candidate<'pat, 'tcx>, place: &PlaceBuilder<'tcx>, pats: &'pat [Box>], + has_guard: bool, ) -> Vec> { pats.iter() .map(|box pat| { - let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard, self); - self.simplify_candidate(&mut candidate); + let mut candidate = Candidate::new(place.clone(), pat, has_guard, self); + self.simplify_match_pairs( + &mut candidate.match_pairs, + &mut candidate.bindings, + &mut candidate.ascriptions, + ); if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = &*candidate.match_pairs { - candidate.subcandidates = self.create_or_subcandidates(&candidate, place, pats); + candidate.subcandidates = + self.create_or_subcandidates(place, pats, candidate.has_guard); candidate.match_pairs.pop(); } candidate @@ -122,7 +137,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn simplify_match_pair<'pat>( &mut self, match_pair: MatchPair<'pat, 'tcx>, - candidate: &mut Candidate<'pat, 'tcx>, + bindings: &mut Vec>, + ascriptions: &mut Vec>, + match_pairs: &mut Vec>, ) -> Result<(), MatchPair<'pat, 'tcx>> { match match_pair.pattern.kind { PatKind::AscribeUserType { @@ -131,14 +148,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { // Apply the type ascription to the value at `match_pair.place` if let Some(source) = match_pair.place.try_to_place(self) { - candidate.ascriptions.push(Ascription { + ascriptions.push(Ascription { annotation: annotation.clone(), source, variance, }); } - candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); + match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); Ok(()) } @@ -158,7 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { is_primary: _, } => { if let Some(source) = match_pair.place.try_to_place(self) { - candidate.bindings.push(Binding { + bindings.push(Binding { span: match_pair.pattern.span, source, var_id: var, @@ -168,7 +185,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(subpattern) = subpattern.as_ref() { // this is the `x @ P` case; have to keep matching against `P` now - candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); + match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); } Ok(()) @@ -211,13 +228,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span, user_ty: Box::new(user_ty), }; - candidate.ascriptions.push(Ascription { + ascriptions.push(Ascription { annotation, source, variance: ty::Contravariant, }); } - candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); + match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); Ok(()) } @@ -233,13 +250,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Slice { ref prefix, ref slice, ref suffix } => { if prefix.is_empty() && slice.is_some() && suffix.is_empty() { // irrefutable - self.prefix_slice_suffix( - &mut candidate.match_pairs, - &match_pair.place, - prefix, - slice, - suffix, - ); + self.prefix_slice_suffix(match_pairs, &match_pair.place, prefix, slice, suffix); Ok(()) } else { Err(match_pair) @@ -260,9 +271,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { || !adt_def.is_variant_list_non_exhaustive()); if irrefutable { let place_builder = match_pair.place.downcast(adt_def, variant_index); - candidate - .match_pairs - .extend(self.field_match_pairs(place_builder, subpatterns)); + match_pairs.extend(self.field_match_pairs(place_builder, subpatterns)); Ok(()) } else { Err(match_pair) @@ -270,25 +279,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::Array { ref prefix, ref slice, ref suffix } => { - self.prefix_slice_suffix( - &mut candidate.match_pairs, - &match_pair.place, - prefix, - slice, - suffix, - ); + self.prefix_slice_suffix(match_pairs, &match_pair.place, prefix, slice, suffix); Ok(()) } PatKind::Leaf { ref subpatterns } => { // tuple struct, match subpats (if any) - candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns)); + match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns)); Ok(()) } PatKind::Deref { ref subpattern } => { let place_builder = match_pair.place.deref(); - candidate.match_pairs.push(MatchPair::new(place_builder, subpattern, self)); + match_pairs.push(MatchPair::new(place_builder, subpattern, self)); Ok(()) } -- cgit 1.4.1-3-g733a5 From 308b4824aabf92e1301b67137059e35b0b388768 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 10 Feb 2024 20:46:08 +0100 Subject: Don't repeatedly simplify already-simplified match pairs --- compiler/rustc_mir_build/src/build/matches/simplify.rs | 18 +++++++----------- ...ential_or.match_tuple.SimplifyCfg-initial.after.mir | 8 ++++---- 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 040d38c109b..8ff07c590bb 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -59,22 +59,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // final bindings: [6, 7, 4, 5, 1, 2, 3] let mut accumulated_bindings = mem::take(candidate_bindings); - // Repeatedly simplify match pairs until fixed point is reached + let mut simplified_match_pairs = Vec::new(); + // Repeatedly simplify match pairs until we're left with only unsimplifiable ones. loop { - let mut changed = false; for match_pair in mem::take(match_pairs) { - match self.simplify_match_pair( + if let Err(match_pair) = self.simplify_match_pair( match_pair, candidate_bindings, candidate_ascriptions, match_pairs, ) { - Ok(()) => { - changed = true; - } - Err(match_pair) => { - match_pairs.push(match_pair); - } + simplified_match_pairs.push(match_pair); } } @@ -83,14 +78,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mem::swap(candidate_bindings, &mut accumulated_bindings); candidate_bindings.clear(); - if !changed { - // If we were not able to simplify anymore, done. + if match_pairs.is_empty() { break; } } // Store computed bindings back in `candidate_bindings`. mem::swap(candidate_bindings, &mut accumulated_bindings); + // Store simplified match pairs back in `match_pairs`. + mem::swap(match_pairs, &mut simplified_match_pairs); // Move or-patterns to the end, because they can result in us // creating additional candidates, so we want to test them as diff --git a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir index 596dcef85fd..ea5cd55b560 100644 --- a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir @@ -19,7 +19,8 @@ fn match_tuple(_1: (u32, bool, Option, u32)) -> u32 { bb0: { PlaceMention(_1); - switchInt((_1.0: u32)) -> [1: bb2, 4: bb2, otherwise: bb1]; + _2 = discriminant((_1.2: std::option::Option)); + switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; } bb1: { @@ -28,12 +29,11 @@ fn match_tuple(_1: (u32, bool, Option, u32)) -> u32 { } bb2: { - _2 = discriminant((_1.2: std::option::Option)); - switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb1]; + switchInt((((_1.2: std::option::Option) as Some).0: i32)) -> [1: bb3, 8: bb3, otherwise: bb1]; } bb3: { - switchInt((((_1.2: std::option::Option) as Some).0: i32)) -> [1: bb4, 8: bb4, otherwise: bb1]; + switchInt((_1.0: u32)) -> [1: bb4, 4: bb4, otherwise: bb1]; } bb4: { -- cgit 1.4.1-3-g733a5 From d936ab63d44f8d0f093e3a09709881673b1a7ecd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 08:33:02 +0100 Subject: Eagerly simplify match pairs --- compiler/rustc_mir_build/src/build/matches/mod.rs | 35 ++++--- .../rustc_mir_build/src/build/matches/simplify.rs | 20 ++-- compiler/rustc_mir_build/src/build/matches/test.rs | 106 +++++---------------- compiler/rustc_mir_build/src/build/matches/util.rs | 2 +- 4 files changed, 61 insertions(+), 102 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index bb307089f1c..309fd3bf09e 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -947,12 +947,16 @@ struct Candidate<'pat, 'tcx> { has_guard: bool, /// All of these must be satisfied... + // Invariant: all the `MatchPair`s are recursively simplified. + // Invariant: or-patterns must be sorted at the end. match_pairs: Vec>, /// ...these bindings established... + // Invariant: not mutated outside `Candidate::new()`. bindings: Vec>, /// ...and these types asserted... + // Invariant: not mutated outside `Candidate::new()`. ascriptions: Vec>, /// ...and if this is non-empty, one of these subcandidates also has to match... @@ -972,9 +976,9 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, has_guard: bool, - cx: &Builder<'_, 'tcx>, + cx: &mut Builder<'_, 'tcx>, ) -> Self { - Candidate { + let mut candidate = Candidate { span: pattern.span, has_guard, match_pairs: vec![MatchPair::new(place, pattern, cx)], @@ -984,7 +988,15 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { otherwise_block: None, pre_binding_block: None, next_candidate_pre_binding_block: None, - } + }; + + cx.simplify_match_pairs( + &mut candidate.match_pairs, + &mut candidate.bindings, + &mut candidate.ascriptions, + ); + + candidate } /// Visit the leaf candidates (those with no subcandidates) contained in @@ -1040,13 +1052,18 @@ struct Ascription<'tcx> { variance: ty::Variance, } -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) struct MatchPair<'pat, 'tcx> { - // this place... + // This place... place: PlaceBuilder<'tcx>, // ... must match this pattern. + // Invariant: after creation and simplification in `Candidate::new()`, all match pairs must be + // simplified, i.e. require a test. pattern: &'pat Pat<'tcx>, + + /// Precomputed sub-match pairs of `pattern`. + subpairs: Vec, } /// See [`Test`] for more. @@ -1163,16 +1180,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidates: &mut [&mut Candidate<'pat, 'tcx>], fake_borrows: &mut Option>>, ) { - // Start by simplifying candidates. Once this process is complete, all - // the match pairs which remain require some form of test, whether it - // be a switch or pattern comparison. let mut split_or_candidate = false; for candidate in &mut *candidates { - self.simplify_match_pairs( - &mut candidate.match_pairs, - &mut candidate.bindings, - &mut candidate.ascriptions, - ); if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = &*candidate.match_pairs { diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 8ff07c590bb..441e55fda89 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -107,12 +107,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pats.iter() .map(|box pat| { let mut candidate = Candidate::new(place.clone(), pat, has_guard, self); - self.simplify_match_pairs( - &mut candidate.match_pairs, - &mut candidate.bindings, - &mut candidate.ascriptions, - ); - if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = &*candidate.match_pairs { @@ -132,11 +126,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// candidate. fn simplify_match_pair<'pat>( &mut self, - match_pair: MatchPair<'pat, 'tcx>, + mut match_pair: MatchPair<'pat, 'tcx>, bindings: &mut Vec>, ascriptions: &mut Vec>, match_pairs: &mut Vec>, ) -> Result<(), MatchPair<'pat, 'tcx>> { + assert!(match_pair.subpairs.is_empty(), "mustn't simplify a match pair twice"); match match_pair.pattern.kind { PatKind::AscribeUserType { ref subpattern, @@ -249,6 +244,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.prefix_slice_suffix(match_pairs, &match_pair.place, prefix, slice, suffix); Ok(()) } else { + self.prefix_slice_suffix( + &mut match_pair.subpairs, + &match_pair.place, + prefix, + slice, + suffix, + ); + self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions); Err(match_pair) } } @@ -270,6 +273,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pairs.extend(self.field_match_pairs(place_builder, subpatterns)); Ok(()) } else { + let downcast_place = match_pair.place.clone().downcast(adt_def, variant_index); // `(x as Variant)` + match_pair.subpairs = self.field_match_pairs(downcast_place, subpatterns); + self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions); Err(match_pair) } } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 990be30b2d6..d5ae2fcdfa0 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -589,22 +589,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // away.) let (match_pair_index, match_pair) = candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?; + let mut fully_matched = false; - match (&test.kind, &match_pair.pattern.kind) { + let ret = match (&test.kind, &match_pair.pattern.kind) { // If we are performing a variant switch, then this // informs variant patterns, but nothing else. ( &TestKind::Switch { adt_def: tested_adt_def, .. }, - &PatKind::Variant { adt_def, variant_index, ref subpatterns, .. }, + &PatKind::Variant { adt_def, variant_index, .. }, ) => { assert_eq!(adt_def, tested_adt_def); - self.candidate_after_variant_switch( - match_pair_index, - adt_def, - variant_index, - subpatterns, - candidate, - ); + fully_matched = true; Some(variant_index.as_usize()) } @@ -618,8 +613,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Constant { value }) if is_switch_ty(match_pair.pattern.ty) => { + fully_matched = true; let index = options.get_index_of(value).unwrap(); - self.candidate_without_match_pair(match_pair_index, candidate); Some(index) } @@ -645,13 +640,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (Ordering::Equal, &None) => { // on true, min_len = len = $actual_length, // on false, len != $actual_length - self.candidate_after_slice_test( - match_pair_index, - candidate, - prefix, - slice, - suffix, - ); + fully_matched = true; Some(0) } (Ordering::Less, _) => { @@ -683,13 +672,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (Ordering::Equal, &Some(_)) => { // $actual_len >= test_len = pat_len, // so we can match. - self.candidate_after_slice_test( - match_pair_index, - candidate, - prefix, - slice, - suffix, - ); + fully_matched = true; Some(0) } (Ordering::Less, _) | (Ordering::Equal, &None) => { @@ -713,13 +696,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (TestKind::Range(test), PatKind::Range(pat)) => { if test == pat { - self.candidate_without_match_pair(match_pair_index, candidate); - return Some(0); + fully_matched = true; + Some(0) + } else { + // If the testing range does not overlap with pattern range, + // the pattern can be matched only if this test fails. + if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None } } - - // If the testing range does not overlap with pattern range, - // the pattern can be matched only if this test fails. - if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None } } (TestKind::Range(range), &PatKind::Constant { value }) => { @@ -751,64 +734,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // FIXME(#29623) we can be more clever here let pattern_test = self.test(match_pair); if pattern_test.kind == test.kind { - self.candidate_without_match_pair(match_pair_index, candidate); + fully_matched = true; Some(0) } else { None } } - } - } - - fn candidate_without_match_pair( - &mut self, - match_pair_index: usize, - candidate: &mut Candidate<'_, 'tcx>, - ) { - candidate.match_pairs.remove(match_pair_index); - } + }; - fn candidate_after_slice_test<'pat>( - &mut self, - match_pair_index: usize, - candidate: &mut Candidate<'pat, 'tcx>, - prefix: &'pat [Box>], - opt_slice: &'pat Option>>, - suffix: &'pat [Box>], - ) { - let removed_place = candidate.match_pairs.remove(match_pair_index).place; - self.prefix_slice_suffix( - &mut candidate.match_pairs, - &removed_place, - prefix, - opt_slice, - suffix, - ); - } + if fully_matched { + // Replace the match pair by its sub-pairs. + let match_pair = candidate.match_pairs.remove(match_pair_index); + candidate.match_pairs.extend(match_pair.subpairs); + // Move or-patterns to the end. + candidate + .match_pairs + .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); + } - fn candidate_after_variant_switch<'pat>( - &mut self, - match_pair_index: usize, - adt_def: ty::AdtDef<'tcx>, - variant_index: VariantIdx, - subpatterns: &'pat [FieldPat<'tcx>], - candidate: &mut Candidate<'pat, 'tcx>, - ) { - let match_pair = candidate.match_pairs.remove(match_pair_index); - - // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, - // we want to create a set of derived match-patterns like - // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. - let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)` - let consequent_match_pairs = subpatterns.iter().map(|subpattern| { - // e.g., `(x as Variant).0` - let place = downcast_place - .clone_project(PlaceElem::Field(subpattern.field, subpattern.pattern.ty)); - // e.g., `(x as Variant).0 @ P1` - MatchPair::new(place, &subpattern.pattern, self) - }); - - candidate.match_pairs.extend(consequent_match_pairs); + ret } fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! { diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 5eb853989d0..a426f2593fa 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -116,6 +116,6 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { if may_need_cast { place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); } - MatchPair { place, pattern } + MatchPair { place, pattern, subpairs: Vec::new() } } } -- cgit 1.4.1-3-g733a5 From 15072766afa5cc1947e116f026e8f4bef79fde91 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 10 Feb 2024 23:59:03 +0100 Subject: Compute subpairs when creating match pair --- .../rustc_mir_build/src/build/matches/simplify.rs | 101 +++++---------------- compiler/rustc_mir_build/src/build/matches/util.rs | 49 +++++++++- 2 files changed, 72 insertions(+), 78 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 441e55fda89..7322e578f25 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -131,11 +131,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascriptions: &mut Vec>, match_pairs: &mut Vec>, ) -> Result<(), MatchPair<'pat, 'tcx>> { - assert!(match_pair.subpairs.is_empty(), "mustn't simplify a match pair twice"); match match_pair.pattern.kind { + PatKind::Leaf { .. } + | PatKind::Deref { .. } + | PatKind::Array { .. } + | PatKind::Never + | PatKind::Wild + | PatKind::Error(_) => {} + PatKind::AscribeUserType { - ref subpattern, ascription: thir::Ascription { ref annotation, variance }, + .. } => { // Apply the type ascription to the value at `match_pair.place` if let Some(source) = match_pair.place.try_to_place(self) { @@ -145,15 +151,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { variance, }); } - - match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); - - Ok(()) - } - - PatKind::Wild | PatKind::Error(_) => { - // nothing left to do - Ok(()) } PatKind::Binding { @@ -162,7 +159,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mode, var, ty: _, - ref subpattern, + subpattern: _, is_primary: _, } => { if let Some(source) = match_pair.place.try_to_place(self) { @@ -173,24 +170,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { binding_mode: mode, }); } - - if let Some(subpattern) = subpattern.as_ref() { - // this is the `x @ P` case; have to keep matching against `P` now - match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); - } - - Ok(()) - } - - PatKind::Never => { - // A never pattern acts like a load from the place. - // FIXME(never_patterns): load from the place - Ok(()) - } - - PatKind::Constant { .. } => { - // FIXME normalize patterns when possible - Err(match_pair) } PatKind::InlineConstant { subpattern: ref pattern, def } => { @@ -225,38 +204,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { variance: ty::Contravariant, }); } - match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); + } - Ok(()) + PatKind::Constant { .. } => { + // FIXME normalize patterns when possible + return Err(match_pair); } PatKind::Range(ref range) => { - if let Some(true) = range.is_full_range(self.tcx) { - // Irrefutable pattern match. - return Ok(()); + if range.is_full_range(self.tcx) != Some(true) { + return Err(match_pair); } - Err(match_pair) } PatKind::Slice { ref prefix, ref slice, ref suffix } => { - if prefix.is_empty() && slice.is_some() && suffix.is_empty() { - // irrefutable - self.prefix_slice_suffix(match_pairs, &match_pair.place, prefix, slice, suffix); - Ok(()) - } else { - self.prefix_slice_suffix( - &mut match_pair.subpairs, - &match_pair.place, - prefix, - slice, - suffix, - ); + if !(prefix.is_empty() && slice.is_some() && suffix.is_empty()) { self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions); - Err(match_pair) + return Err(match_pair); } } - PatKind::Variant { adt_def, args, variant_index, ref subpatterns } => { + PatKind::Variant { adt_def, args, variant_index, subpatterns: _ } => { let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { i == variant_index || { (self.tcx.features().exhaustive_patterns @@ -268,36 +236,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } }) && (adt_def.did().is_local() || !adt_def.is_variant_list_non_exhaustive()); - if irrefutable { - let place_builder = match_pair.place.downcast(adt_def, variant_index); - match_pairs.extend(self.field_match_pairs(place_builder, subpatterns)); - Ok(()) - } else { - let downcast_place = match_pair.place.clone().downcast(adt_def, variant_index); // `(x as Variant)` - match_pair.subpairs = self.field_match_pairs(downcast_place, subpatterns); + if !irrefutable { self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions); - Err(match_pair) + return Err(match_pair); } } - PatKind::Array { ref prefix, ref slice, ref suffix } => { - self.prefix_slice_suffix(match_pairs, &match_pair.place, prefix, slice, suffix); - Ok(()) - } - - PatKind::Leaf { ref subpatterns } => { - // tuple struct, match subpats (if any) - match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns)); - Ok(()) - } - - PatKind::Deref { ref subpattern } => { - let place_builder = match_pair.place.deref(); - match_pairs.push(MatchPair::new(place_builder, subpattern, self)); - Ok(()) - } - - PatKind::Or { .. } => Err(match_pair), + PatKind::Or { .. } => return Err(match_pair), } + + // Simplifiable pattern; we replace it with its subpairs. + match_pairs.append(&mut match_pair.subpairs); + Ok(()) } } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index a426f2593fa..e42d764147c 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -96,7 +96,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { pub(in crate::build) fn new( mut place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, - cx: &Builder<'_, 'tcx>, + cx: &mut Builder<'_, 'tcx>, ) -> MatchPair<'pat, 'tcx> { // Force the place type to the pattern's type. // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? @@ -116,6 +116,51 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { if may_need_cast { place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); } - MatchPair { place, pattern, subpairs: Vec::new() } + + let mut subpairs = Vec::new(); + match pattern.kind { + PatKind::Constant { .. } + | PatKind::Range(_) + | PatKind::Or { .. } + | PatKind::Never + | PatKind::Wild + | PatKind::Error(_) => {} + + PatKind::AscribeUserType { ref subpattern, .. } => { + subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); + } + + PatKind::Binding { ref subpattern, .. } => { + if let Some(subpattern) = subpattern.as_ref() { + // this is the `x @ P` case; have to keep matching against `P` now + subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); + } + } + + PatKind::InlineConstant { subpattern: ref pattern, .. } => { + subpairs.push(MatchPair::new(place.clone(), pattern, cx)); + } + + PatKind::Slice { ref prefix, ref slice, ref suffix } + | PatKind::Array { ref prefix, ref slice, ref suffix } => { + cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix); + } + + PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { + let downcast_place = place.clone().downcast(adt_def, variant_index); // `(x as Variant)` + subpairs = cx.field_match_pairs(downcast_place, subpatterns); + } + + PatKind::Leaf { ref subpatterns } => { + subpairs = cx.field_match_pairs(place.clone(), subpatterns); + } + + PatKind::Deref { ref subpattern } => { + let place_builder = place.clone().deref(); + subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + } + } + + MatchPair { place, pattern, subpairs } } } -- cgit 1.4.1-3-g733a5 From 0ca1d220d279fd04aaf829ade6f9f111878dd9f4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 19 Feb 2024 21:31:15 +0100 Subject: Don't default `fully_matched` to false to avoid mistakes --- compiler/rustc_mir_build/src/build/matches/test.rs | 33 +++++++++++++++------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index d5ae2fcdfa0..ae9ebe7170b 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -589,8 +589,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // away.) let (match_pair_index, match_pair) = candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?; - let mut fully_matched = false; + let fully_matched; let ret = match (&test.kind, &match_pair.pattern.kind) { // If we are performing a variant switch, then this // informs variant patterns, but nothing else. @@ -602,8 +602,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fully_matched = true; Some(variant_index.as_usize()) } - - (&TestKind::Switch { .. }, _) => None, + (&TestKind::Switch { .. }, _) => { + fully_matched = false; + None + } // If we are performing a switch over integers, then this informs integer // equality, but nothing else. @@ -617,8 +619,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let index = options.get_index_of(value).unwrap(); Some(index) } - (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Range(range)) => { + fully_matched = false; let not_contained = self.values_not_contained_in_range(&*range, options).unwrap_or(false); @@ -628,8 +630,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { options.len() }) } - - (&TestKind::SwitchInt { .. }, _) => None, + (&TestKind::SwitchInt { .. }, _) => { + fully_matched = false; + None + } ( &TestKind::Len { len: test_len, op: BinOp::Eq }, @@ -647,21 +651,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // test_len < pat_len. If $actual_len = test_len, // then $actual_len < pat_len and we don't have // enough elements. + fully_matched = false; Some(1) } (Ordering::Equal | Ordering::Greater, &Some(_)) => { // This can match both if $actual_len = test_len >= pat_len, // and if $actual_len > test_len. We can't advance. + fully_matched = false; None } (Ordering::Greater, &None) => { // test_len != pat_len, so if $actual_len = test_len, then // $actual_len != pat_len. + fully_matched = false; Some(1) } } } - ( &TestKind::Len { len: test_len, op: BinOp::Ge }, PatKind::Slice { prefix, slice, suffix }, @@ -679,16 +685,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // test_len <= pat_len. If $actual_len < test_len, // then it is also < pat_len, so the test passing is // necessary (but insufficient). + fully_matched = false; Some(0) } (Ordering::Greater, &None) => { // test_len > pat_len. If $actual_len >= test_len > pat_len, // then we know we won't have a match. + fully_matched = false; Some(1) } (Ordering::Greater, &Some(_)) => { // test_len < pat_len, and is therefore less // strict. This can still go both ways. + fully_matched = false; None } } @@ -699,13 +708,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fully_matched = true; Some(0) } else { + fully_matched = false; // If the testing range does not overlap with pattern range, // the pattern can be matched only if this test fails. if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None } } } - (TestKind::Range(range), &PatKind::Constant { value }) => { + fully_matched = false; if !range.contains(value, self.tcx, self.param_env)? { // `value` is not contained in the testing range, // so `value` can be matched only if this test fails. @@ -714,8 +724,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None } } - - (&TestKind::Range { .. }, _) => None, + (&TestKind::Range { .. }, _) => { + fully_matched = false; + None + } (&TestKind::Eq { .. } | &TestKind::Len { .. }, _) => { // The call to `self.test(&match_pair)` below is not actually used to generate any @@ -737,6 +749,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fully_matched = true; Some(0) } else { + fully_matched = false; None } } -- cgit 1.4.1-3-g733a5 From 328c77683eda8356352dc619734dc5c49b2e2b84 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 19 Feb 2024 21:34:55 +0100 Subject: Update comments --- compiler/rustc_mir_build/src/build/matches/simplify.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 7322e578f25..83922dce327 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -95,9 +95,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!(simplified = ?match_pairs, "simplify_match_pairs"); } - /// Given `candidate` that has a single or-pattern for its match-pairs, - /// creates a fresh candidate for each of its input subpatterns passed via - /// `pats`. + /// Create a new candidate for each pattern in `pats`, and recursively simplify tje + /// single-or-pattern case. pub(super) fn create_or_subcandidates<'pat>( &mut self, place: &PlaceBuilder<'tcx>, @@ -119,11 +118,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .collect() } - /// Tries to simplify `match_pair`, returning `Ok(())` if - /// successful. If successful, new match pairs and bindings will - /// have been pushed into the candidate. If no simplification is - /// possible, `Err` is returned and no changes are made to - /// candidate. + /// Tries to simplify `match_pair`, returning `Ok(())` if successful. If successful, new match + /// pairs and bindings will have been pushed into the respective `Vec`s. If no simplification is + /// possible, `Err` is returned. fn simplify_match_pair<'pat>( &mut self, mut match_pair: MatchPair<'pat, 'tcx>, -- cgit 1.4.1-3-g733a5 From 086463b227ea12c244243609cce5c795dc3ec40a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 19 Feb 2024 17:39:25 -0300 Subject: Remove suspicious auto trait lint --- .../rustc_hir_analysis/src/coherence/orphan.rs | 164 +-------------------- compiler/rustc_lint/src/lib.rs | 5 + compiler/rustc_lint_defs/src/builtin.rs | 35 ----- .../clippy/tests/ui/non_send_fields_in_send_ty.rs | 1 - .../tests/ui/non_send_fields_in_send_ty.stderr | 52 +++---- .../crates/ide-db/src/generated/lints.rs | 5 - tests/ui/auto-traits/issue-117789.rs | 2 - tests/ui/auto-traits/issue-117789.stderr | 4 +- tests/ui/auto-traits/issue-83857-ub.rs | 1 - tests/ui/auto-traits/issue-83857-ub.stderr | 12 +- tests/ui/auto-traits/suspicious-impls-lint.rs | 50 ------- tests/ui/auto-traits/suspicious-impls-lint.stderr | 82 ----------- .../auto-traits/suspicious-negative-impls-lint.rs | 21 --- .../suspicious-negative-impls-lint.stderr | 52 ------- .../coherence-conflicting-negative-trait-impl.rs | 2 - ...oherence-conflicting-negative-trait-impl.stderr | 18 +-- tests/ui/coherence/coherence-orphan.rs | 12 +- tests/ui/coherence/coherence-orphan.stderr | 25 +--- .../coherence/coherence-overlap-negative-impls.rs | 13 +- tests/ui/issues/issue-106755.rs | 2 - tests/ui/issues/issue-106755.stderr | 18 +-- ...eck-default-trait-impl-cross-crate-coherence.rs | 13 +- ...default-trait-impl-cross-crate-coherence.stderr | 16 +- 23 files changed, 78 insertions(+), 527 deletions(-) delete mode 100644 tests/ui/auto-traits/suspicious-impls-lint.rs delete mode 100644 tests/ui/auto-traits/suspicious-impls-lint.stderr delete mode 100644 tests/ui/auto-traits/suspicious-negative-impls-lint.rs delete mode 100644 tests/ui/auto-traits/suspicious-negative-impls-lint.stderr (limited to 'compiler') diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 45641be52d2..faf676ddc09 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -1,20 +1,12 @@ //! Orphan checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{DelayDm, ErrorGuaranteed}; +use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_middle::ty::util::CheckRegions; -use rustc_middle::ty::GenericArgs; -use rustc_middle::ty::{ - self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, - TypeVisitor, -}; -use rustc_session::lint; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_trait_selection::traits; -use std::ops::ControlFlow; use crate::errors; @@ -26,12 +18,7 @@ pub(crate) fn orphan_check_impl( let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(); trait_ref.error_reported()?; - let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id); - if tcx.trait_is_auto(trait_ref.def_id) { - lint_auto_trait_impl(tcx, trait_ref, impl_def_id); - } - - ret + do_orphan_check_impl(tcx, trait_ref, impl_def_id) } fn do_orphan_check_impl<'tcx>( @@ -445,146 +432,3 @@ fn emit_orphan_check_error<'tcx>( } }) } - -/// Lint impls of auto traits if they are likely to have -/// unsound or surprising effects on auto impls. -fn lint_auto_trait_impl<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - impl_def_id: LocalDefId, -) { - if trait_ref.args.len() != 1 { - tcx.dcx().span_delayed_bug( - tcx.def_span(impl_def_id), - "auto traits cannot have generic parameters", - ); - return; - } - let self_ty = trait_ref.self_ty(); - let (self_type_did, args) = match self_ty.kind() { - ty::Adt(def, args) => (def.did(), args), - _ => { - // FIXME: should also lint for stuff like `&i32` but - // considering that auto traits are unstable, that - // isn't too important for now as this only affects - // crates using `nightly`, and std. - return; - } - }; - - // Impls which completely cover a given root type are fine as they - // disable auto impls entirely. So only lint if the args - // are not a permutation of the identity args. - let Err(arg) = tcx.uses_unique_generic_params(args, CheckRegions::No) else { - // ok - return; - }; - - // Ideally: - // - // - compute the requirements for the auto impl candidate - // - check whether these are implied by the non covering impls - // - if not, emit the lint - // - // What we do here is a bit simpler: - // - // - badly check if an auto impl candidate definitely does not apply - // for the given simplified type - // - if so, do not lint - if fast_reject_auto_impl(tcx, trait_ref.def_id, self_ty) { - // ok - return; - } - - tcx.node_span_lint( - lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS, - tcx.local_def_id_to_hir_id(impl_def_id), - tcx.def_span(impl_def_id), - DelayDm(|| { - format!( - "cross-crate traits with a default impl, like `{}`, \ - should not be specialized", - tcx.def_path_str(trait_ref.def_id), - ) - }), - |lint| { - let item_span = tcx.def_span(self_type_did); - let self_descr = tcx.def_descr(self_type_did); - match arg { - ty::util::NotUniqueParam::DuplicateParam(arg) => { - lint.note(format!("`{arg}` is mentioned multiple times")); - } - ty::util::NotUniqueParam::NotParam(arg) => { - lint.note(format!("`{arg}` is not a generic parameter")); - } - } - lint.span_note( - item_span, - format!( - "try using the same sequence of generic parameters as the {self_descr} definition", - ), - ); - }, - ); -} - -fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>) -> bool { - struct DisableAutoTraitVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - self_ty_root: Ty<'tcx>, - seen: FxHashSet, - } - - impl<'tcx> TypeVisitor> for DisableAutoTraitVisitor<'tcx> { - type BreakTy = (); - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - let tcx = self.tcx; - if ty != self.self_ty_root { - for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, ty) { - match tcx.impl_polarity(impl_def_id) { - ImplPolarity::Negative => return ControlFlow::Break(()), - ImplPolarity::Reservation => {} - // FIXME(@lcnr): That's probably not good enough, idk - // - // We might just want to take the rustdoc code and somehow avoid - // explicit impls for `Self`. - ImplPolarity::Positive => return ControlFlow::Continue(()), - } - } - } - - match ty.kind() { - ty::Adt(def, args) if def.is_phantom_data() => args.visit_with(self), - ty::Adt(def, args) => { - // @lcnr: This is the only place where cycles can happen. We avoid this - // by only visiting each `DefId` once. - // - // This will be is incorrect in subtle cases, but I don't care :) - if self.seen.insert(def.did()) { - for ty in def.all_fields().map(|field| field.ty(tcx, args)) { - ty.visit_with(self)?; - } - } - - ControlFlow::Continue(()) - } - _ => ty.super_visit_with(self), - } - } - } - - let self_ty_root = match self_ty.kind() { - ty::Adt(def, _) => Ty::new_adt(tcx, *def, GenericArgs::identity_for_item(tcx, def.did())), - _ => unimplemented!("unexpected self ty {:?}", self_ty), - }; - - self_ty_root - .visit_with(&mut DisableAutoTraitVisitor { - tcx, - self_ty_root, - trait_def_id, - seen: FxHashSet::default(), - }) - .is_break() -} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index e50f4ca338b..d6009324402 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -524,6 +524,11 @@ fn register_builtins(store: &mut LintStore) { "no longer needed, see RFC #3535 \ for more information", ); + store.register_removed( + "suspicious_auto_trait_impls", + "no longer needed, see #93367 \ + for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8ba5942898c..84a050a242a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -90,7 +90,6 @@ declare_lint_pass! { SOFT_UNSTABLE, STABLE_FEATURES, STATIC_MUT_REFS, - SUSPICIOUS_AUTO_TRAIT_IMPLS, TEST_UNSTABLE_LINT, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, TRIVIAL_CASTS, @@ -4032,40 +4031,6 @@ declare_lint! { "duplicated attribute" } -declare_lint! { - /// The `suspicious_auto_trait_impls` lint checks for potentially incorrect - /// implementations of auto traits. - /// - /// ### Example - /// - /// ```rust - /// struct Foo(T); - /// - /// unsafe impl Send for Foo<*const T> {} - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// A type can implement auto traits, e.g. `Send`, `Sync` and `Unpin`, - /// in two different ways: either by writing an explicit impl or if - /// all fields of the type implement that auto trait. - /// - /// The compiler disables the automatic implementation if an explicit one - /// exists for given type constructor. The exact rules governing this - /// were previously unsound, quite subtle, and have been recently modified. - /// This change caused the automatic implementation to be disabled in more - /// cases, potentially breaking some code. - pub SUSPICIOUS_AUTO_TRAIT_IMPLS, - Warn, - "the rules governing auto traits have recently changed resulting in potential breakage", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange, - reference: "issue #93367 ", - }; -} - declare_lint! { /// The `deprecated_where_clause_location` lint detects when a where clause in front of the equals /// in an associated type. diff --git a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs index c6855a09696..046ea70b08f 100644 --- a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs @@ -1,5 +1,4 @@ #![warn(clippy::non_send_fields_in_send_ty)] -#![allow(suspicious_auto_trait_impls)] #![feature(extern_types)] use std::cell::UnsafeCell; diff --git a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr index 1ea76196af9..99fd4ea60b6 100644 --- a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr +++ b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.stderr @@ -1,11 +1,11 @@ error: some fields in `RingBuffer` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:17:1 + --> $DIR/non_send_fields_in_send_ty.rs:16:1 | LL | unsafe impl Send for RingBuffer {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `data` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:12:5 + --> $DIR/non_send_fields_in_send_ty.rs:11:5 | LL | data: Vec>, | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,155 +14,155 @@ LL | data: Vec>, = help: to override `-D warnings` add `#[allow(clippy::non_send_fields_in_send_ty)]` error: some fields in `MvccRwLock` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:26:1 + --> $DIR/non_send_fields_in_send_ty.rs:25:1 | LL | unsafe impl Send for MvccRwLock {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `lock` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:23:5 + --> $DIR/non_send_fields_in_send_ty.rs:22:5 | LL | lock: Mutex>, | ^^^^^^^^^^^^^^^^^^^ = help: add bounds on type parameter `T` that satisfy `Mutex>: Send` error: some fields in `ArcGuard` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:35:1 + --> $DIR/non_send_fields_in_send_ty.rs:34:1 | LL | unsafe impl Send for ArcGuard {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `head` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:32:5 + --> $DIR/non_send_fields_in_send_ty.rs:31:5 | LL | head: Arc, | ^^^^^^^^^^^^^ = help: add bounds on type parameter `RC` that satisfy `Arc: Send` error: some fields in `DeviceHandle` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:52:1 + --> $DIR/non_send_fields_in_send_ty.rs:51:1 | LL | unsafe impl Send for DeviceHandle {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `context` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:48:5 + --> $DIR/non_send_fields_in_send_ty.rs:47:5 | LL | context: T, | ^^^^^^^^^^ = help: add `T: Send` bound in `Send` impl error: some fields in `NoGeneric` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:60:1 + --> $DIR/non_send_fields_in_send_ty.rs:59:1 | LL | unsafe impl Send for NoGeneric {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `rc_is_not_send` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:57:5 + --> $DIR/non_send_fields_in_send_ty.rs:56:5 | LL | rc_is_not_send: Rc, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use a thread-safe type that implements `Send` error: some fields in `MultiField` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:69:1 + --> $DIR/non_send_fields_in_send_ty.rs:68:1 | LL | unsafe impl Send for MultiField {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `field1` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:64:5 + --> $DIR/non_send_fields_in_send_ty.rs:63:5 | LL | field1: T, | ^^^^^^^^^ = help: add `T: Send` bound in `Send` impl note: it is not safe to send field `field2` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:65:5 + --> $DIR/non_send_fields_in_send_ty.rs:64:5 | LL | field2: T, | ^^^^^^^^^ = help: add `T: Send` bound in `Send` impl note: it is not safe to send field `field3` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:66:5 + --> $DIR/non_send_fields_in_send_ty.rs:65:5 | LL | field3: T, | ^^^^^^^^^ = help: add `T: Send` bound in `Send` impl error: some fields in `MyOption` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:77:1 + --> $DIR/non_send_fields_in_send_ty.rs:76:1 | LL | unsafe impl Send for MyOption {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `0` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:73:12 + --> $DIR/non_send_fields_in_send_ty.rs:72:12 | LL | MySome(T), | ^ = help: add `T: Send` bound in `Send` impl error: some fields in `MultiParam` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:90:1 + --> $DIR/non_send_fields_in_send_ty.rs:89:1 | LL | unsafe impl Send for MultiParam {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `vec` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:87:5 + --> $DIR/non_send_fields_in_send_ty.rs:86:5 | LL | vec: Vec<(A, B)>, | ^^^^^^^^^^^^^^^^ = help: add bounds on type parameters `A, B` that satisfy `Vec<(A, B)>: Send` error: some fields in `HeuristicTest` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:109:1 + --> $DIR/non_send_fields_in_send_ty.rs:108:1 | LL | unsafe impl Send for HeuristicTest {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `field4` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:104:5 + --> $DIR/non_send_fields_in_send_ty.rs:103:5 | LL | field4: (*const NonSend, Rc), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use a thread-safe type that implements `Send` error: some fields in `AttrTest3` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:129:1 + --> $DIR/non_send_fields_in_send_ty.rs:128:1 | LL | unsafe impl Send for AttrTest3 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `0` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:124:11 + --> $DIR/non_send_fields_in_send_ty.rs:123:11 | LL | Enum2(T), | ^ = help: add `T: Send` bound in `Send` impl error: some fields in `Complex` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:138:1 + --> $DIR/non_send_fields_in_send_ty.rs:137:1 | LL | unsafe impl

Send for Complex {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `field1` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:134:5 + --> $DIR/non_send_fields_in_send_ty.rs:133:5 | LL | field1: A, | ^^^^^^^^^ = help: add `P: Send` bound in `Send` impl error: some fields in `Complex>` are not safe to be sent to another thread - --> $DIR/non_send_fields_in_send_ty.rs:142:1 + --> $DIR/non_send_fields_in_send_ty.rs:141:1 | LL | unsafe impl Send for Complex> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `field2` to another thread - --> $DIR/non_send_fields_in_send_ty.rs:135:5 + --> $DIR/non_send_fields_in_send_ty.rs:134:5 | LL | field2: B, | ^^^^^^^^^ diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 2fc07933200..3329909e9da 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -502,10 +502,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "stable_features", description: r##"stable features found in `#[feature]` directive"##, }, - Lint { - label: "suspicious_auto_trait_impls", - description: r##"the rules governing auto traits have recently changed resulting in potential breakage"##, - }, Lint { label: "suspicious_double_ref_op", description: r##"suspicious call of trait method on `&&T`"##, @@ -778,7 +774,6 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ "repr_transparent_external_private_fields", "semicolon_in_expressions_from_macros", "soft_unstable", - "suspicious_auto_trait_impls", "uninhabited_static", "unstable_name_collisions", "unstable_syntax_pre_expansion", diff --git a/tests/ui/auto-traits/issue-117789.rs b/tests/ui/auto-traits/issue-117789.rs index 0c30931a1b5..63f796771db 100644 --- a/tests/ui/auto-traits/issue-117789.rs +++ b/tests/ui/auto-traits/issue-117789.rs @@ -1,5 +1,3 @@ -#![deny(suspicious_auto_trait_impls)] - auto trait Trait

{} //~ ERROR auto traits cannot have generic parameters //~^ ERROR auto traits are experimental and possibly buggy impl

Trait

for () {} diff --git a/tests/ui/auto-traits/issue-117789.stderr b/tests/ui/auto-traits/issue-117789.stderr index 1f8880b1ef4..99efb213417 100644 --- a/tests/ui/auto-traits/issue-117789.stderr +++ b/tests/ui/auto-traits/issue-117789.stderr @@ -1,5 +1,5 @@ error[E0567]: auto traits cannot have generic parameters - --> $DIR/issue-117789.rs:3:17 + --> $DIR/issue-117789.rs:1:17 | LL | auto trait Trait

{} | -----^^^ help: remove the parameters @@ -7,7 +7,7 @@ LL | auto trait Trait

{} | auto trait cannot have generic parameters error[E0658]: auto traits are experimental and possibly buggy - --> $DIR/issue-117789.rs:3:1 + --> $DIR/issue-117789.rs:1:1 | LL | auto trait Trait

{} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/auto-traits/issue-83857-ub.rs b/tests/ui/auto-traits/issue-83857-ub.rs index f9b47d2b0c6..20abfdd851a 100644 --- a/tests/ui/auto-traits/issue-83857-ub.rs +++ b/tests/ui/auto-traits/issue-83857-ub.rs @@ -1,4 +1,3 @@ -#![allow(suspicious_auto_trait_impls)] // Tests that we don't incorrectly allow overlap between a builtin auto trait // impl and a user written one. See #83857 for more details diff --git a/tests/ui/auto-traits/issue-83857-ub.stderr b/tests/ui/auto-traits/issue-83857-ub.stderr index 6372bdfe762..20bfe7e36ca 100644 --- a/tests/ui/auto-traits/issue-83857-ub.stderr +++ b/tests/ui/auto-traits/issue-83857-ub.stderr @@ -1,12 +1,12 @@ error[E0277]: `Foo` cannot be sent between threads safely - --> $DIR/issue-83857-ub.rs:22:38 + --> $DIR/issue-83857-ub.rs:21:38 | LL | fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i32) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `Foo`, which is required by `Foo: WithAssoc` note: required for `Foo` to implement `WithAssoc` - --> $DIR/issue-83857-ub.rs:15:15 + --> $DIR/issue-83857-ub.rs:14:15 | LL | impl WithAssoc for T { | ---- ^^^^^^^^^ ^ @@ -18,7 +18,7 @@ LL | fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i | +++++++++++++++++++++ error[E0277]: `Foo` cannot be sent between threads safely - --> $DIR/issue-83857-ub.rs:22:80 + --> $DIR/issue-83857-ub.rs:21:80 | LL | fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i32) { | ________________________________________________________________________________^ @@ -31,7 +31,7 @@ LL | | } | = help: the trait `Send` is not implemented for `Foo`, which is required by `Foo: WithAssoc` note: required for `Foo` to implement `WithAssoc` - --> $DIR/issue-83857-ub.rs:15:15 + --> $DIR/issue-83857-ub.rs:14:15 | LL | impl WithAssoc for T { | ---- ^^^^^^^^^ ^ @@ -43,7 +43,7 @@ LL | fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i | +++++++++++++++++++++ error[E0277]: `Foo` cannot be sent between threads safely - --> $DIR/issue-83857-ub.rs:25:11 + --> $DIR/issue-83857-ub.rs:24:11 | LL | f(foo(v)); | --- ^ `Foo` cannot be sent between threads safely @@ -52,7 +52,7 @@ LL | f(foo(v)); | = help: the trait `Send` is not implemented for `Foo` note: required by a bound in `foo` - --> $DIR/issue-83857-ub.rs:29:11 + --> $DIR/issue-83857-ub.rs:28:11 | LL | fn foo(x: T) -> ::Output { | ^^^^ required by this bound in `foo` diff --git a/tests/ui/auto-traits/suspicious-impls-lint.rs b/tests/ui/auto-traits/suspicious-impls-lint.rs deleted file mode 100644 index 7712e84f4a2..00000000000 --- a/tests/ui/auto-traits/suspicious-impls-lint.rs +++ /dev/null @@ -1,50 +0,0 @@ -#![deny(suspicious_auto_trait_impls)] - -use std::marker::PhantomData; - -struct MayImplementSendOk(T); -unsafe impl Send for MayImplementSendOk {} // ok - -struct MayImplementSendErr(T); -unsafe impl Send for MayImplementSendErr<&T> {} -//~^ ERROR -//~| WARNING this will change its meaning - -struct ContainsNonSendDirect(*const T); -unsafe impl Send for ContainsNonSendDirect<&T> {} // ok - -struct ContainsPtr(*const T); -struct ContainsIndirectNonSend(ContainsPtr); -unsafe impl Send for ContainsIndirectNonSend<&T> {} // ok - -struct ContainsVec(Vec); -unsafe impl Send for ContainsVec {} -//~^ ERROR -//~| WARNING this will change its meaning - -struct TwoParams(T, U); -unsafe impl Send for TwoParams {} // ok - -struct TwoParamsFlipped(T, U); -unsafe impl Send for TwoParamsFlipped {} // ok - -struct TwoParamsSame(T, U); -unsafe impl Send for TwoParamsSame {} -//~^ ERROR -//~| WARNING this will change its meaning - -pub struct WithPhantomDataNonSend(PhantomData<*const T>, U); -unsafe impl Send for WithPhantomDataNonSend {} // ok - -pub struct WithPhantomDataSend(PhantomData, U); -unsafe impl Send for WithPhantomDataSend<*const T, i8> {} -//~^ ERROR -//~| WARNING this will change its meaning - -pub struct WithLifetime<'a, T>(&'a (), T); -unsafe impl Send for WithLifetime<'static, T> {} // ok -unsafe impl Sync for WithLifetime<'static, Vec> {} -//~^ ERROR -//~| WARNING this will change its meaning - -fn main() {} diff --git a/tests/ui/auto-traits/suspicious-impls-lint.stderr b/tests/ui/auto-traits/suspicious-impls-lint.stderr deleted file mode 100644 index 9cd4e79f851..00000000000 --- a/tests/ui/auto-traits/suspicious-impls-lint.stderr +++ /dev/null @@ -1,82 +0,0 @@ -error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:9:1 - | -LL | unsafe impl Send for MayImplementSendErr<&T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `&T` is not a generic parameter -note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:8:1 - | -LL | struct MayImplementSendErr(T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: the lint level is defined here - --> $DIR/suspicious-impls-lint.rs:1:9 - | -LL | #![deny(suspicious_auto_trait_impls)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:21:1 - | -LL | unsafe impl Send for ContainsVec {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `i32` is not a generic parameter -note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:20:1 - | -LL | struct ContainsVec(Vec); - | ^^^^^^^^^^^^^^^^^^^^^ - -error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:32:1 - | -LL | unsafe impl Send for TwoParamsSame {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `T` is mentioned multiple times -note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:31:1 - | -LL | struct TwoParamsSame(T, U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:40:1 - | -LL | unsafe impl Send for WithPhantomDataSend<*const T, i8> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `*const T` is not a generic parameter -note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:39:1 - | -LL | pub struct WithPhantomDataSend(PhantomData, U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: cross-crate traits with a default impl, like `Sync`, should not be specialized - --> $DIR/suspicious-impls-lint.rs:46:1 - | -LL | unsafe impl Sync for WithLifetime<'static, Vec> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `Vec` is not a generic parameter -note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-impls-lint.rs:44:1 - | -LL | pub struct WithLifetime<'a, T>(&'a (), T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 5 previous errors - diff --git a/tests/ui/auto-traits/suspicious-negative-impls-lint.rs b/tests/ui/auto-traits/suspicious-negative-impls-lint.rs deleted file mode 100644 index 34842e5944b..00000000000 --- a/tests/ui/auto-traits/suspicious-negative-impls-lint.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![feature(negative_impls)] -#![deny(suspicious_auto_trait_impls)] - -use std::marker::PhantomData; - -struct ContainsVec(Vec); -impl !Send for ContainsVec {} -//~^ ERROR -//~| WARNING this will change its meaning - -pub struct WithPhantomDataSend(PhantomData, U); -impl !Send for WithPhantomDataSend<*const T, u8> {} -//~^ ERROR -//~| WARNING this will change its meaning - -pub struct WithLifetime<'a, T>(&'a (), T); -impl !Sync for WithLifetime<'static, Option> {} -//~^ ERROR -//~| WARNING this will change its meaning - -fn main() {} diff --git a/tests/ui/auto-traits/suspicious-negative-impls-lint.stderr b/tests/ui/auto-traits/suspicious-negative-impls-lint.stderr deleted file mode 100644 index ee03ea12557..00000000000 --- a/tests/ui/auto-traits/suspicious-negative-impls-lint.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-negative-impls-lint.rs:7:1 - | -LL | impl !Send for ContainsVec {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `u32` is not a generic parameter -note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-negative-impls-lint.rs:6:1 - | -LL | struct ContainsVec(Vec); - | ^^^^^^^^^^^^^^^^^^^^^ -note: the lint level is defined here - --> $DIR/suspicious-negative-impls-lint.rs:2:9 - | -LL | #![deny(suspicious_auto_trait_impls)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/suspicious-negative-impls-lint.rs:12:1 - | -LL | impl !Send for WithPhantomDataSend<*const T, u8> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `*const T` is not a generic parameter -note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-negative-impls-lint.rs:11:1 - | -LL | pub struct WithPhantomDataSend(PhantomData, U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: cross-crate traits with a default impl, like `Sync`, should not be specialized - --> $DIR/suspicious-negative-impls-lint.rs:17:1 - | -LL | impl !Sync for WithLifetime<'static, Option> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `Option` is not a generic parameter -note: try using the same sequence of generic parameters as the struct definition - --> $DIR/suspicious-negative-impls-lint.rs:16:1 - | -LL | pub struct WithLifetime<'a, T>(&'a (), T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs index 76a57936e69..24b87892753 100644 --- a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs +++ b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs @@ -13,7 +13,5 @@ impl !Send for TestType {} //~ ERROR found both positive and nega unsafe impl Send for TestType {} //~ ERROR conflicting implementations impl !Send for TestType {} -//~^ WARNING -//~| WARNING this will change its meaning fn main() {} diff --git a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr index 020199da991..2463f38a922 100644 --- a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr +++ b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr @@ -16,23 +16,7 @@ LL | unsafe impl Send for TestType {} LL | unsafe impl Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` -warning: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/coherence-conflicting-negative-trait-impl.rs:15:1 - | -LL | impl !Send for TestType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `i32` is not a generic parameter -note: try using the same sequence of generic parameters as the struct definition - --> $DIR/coherence-conflicting-negative-trait-impl.rs:7:1 - | -LL | struct TestType(::std::marker::PhantomData); - | ^^^^^^^^^^^^^^^^^^ - = note: `#[warn(suspicious_auto_trait_impls)]` on by default - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0119, E0751. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/coherence-orphan.rs b/tests/ui/coherence/coherence-orphan.rs index c06705133c8..9c96958f21a 100644 --- a/tests/ui/coherence/coherence-orphan.rs +++ b/tests/ui/coherence/coherence-orphan.rs @@ -7,18 +7,16 @@ use lib::TheTrait; struct TheType; -impl TheTrait for isize { } +impl TheTrait for isize {} //~^ ERROR E0117 //~| ERROR not all trait items implemented -impl TheTrait for isize { } +impl TheTrait for isize {} //~^ ERROR not all trait items implemented -impl TheTrait for TheType { } +impl TheTrait for TheType {} //~^ ERROR not all trait items implemented -impl !Send for Vec { } //~ ERROR E0117 -//~^ WARNING -//~| WARNING this will change its meaning +impl !Send for Vec {} //~ ERROR E0117 -fn main() { } +fn main() {} diff --git a/tests/ui/coherence/coherence-orphan.stderr b/tests/ui/coherence/coherence-orphan.stderr index 78fad837647..b1bb75bfe51 100644 --- a/tests/ui/coherence/coherence-orphan.stderr +++ b/tests/ui/coherence/coherence-orphan.stderr @@ -1,7 +1,7 @@ error[E0117]: only traits defined in the current crate can be implemented for primitive types --> $DIR/coherence-orphan.rs:10:1 | -LL | impl TheTrait for isize { } +LL | impl TheTrait for isize {} | ^^^^^---------------^^^^^----- | | | | | | | `isize` is not defined in the current crate @@ -13,7 +13,7 @@ LL | impl TheTrait for isize { } error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate --> $DIR/coherence-orphan.rs:20:1 | -LL | impl !Send for Vec { } +LL | impl !Send for Vec {} | ^^^^^^^^^^^^^^^---------- | | | | | `Vec` is not defined in the current crate @@ -21,23 +21,10 @@ LL | impl !Send for Vec { } | = note: define and implement a trait or new type instead -warning: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/coherence-orphan.rs:20:1 - | -LL | impl !Send for Vec { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `isize` is not a generic parameter -note: try using the same sequence of generic parameters as the struct definition - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - = note: `#[warn(suspicious_auto_trait_impls)]` on by default - error[E0046]: not all trait items implemented, missing: `the_fn` --> $DIR/coherence-orphan.rs:10:1 | -LL | impl TheTrait for isize { } +LL | impl TheTrait for isize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `the_fn` in implementation | = help: implement the missing item: `fn the_fn(&self) { todo!() }` @@ -45,7 +32,7 @@ LL | impl TheTrait for isize { } error[E0046]: not all trait items implemented, missing: `the_fn` --> $DIR/coherence-orphan.rs:14:1 | -LL | impl TheTrait for isize { } +LL | impl TheTrait for isize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `the_fn` in implementation | = help: implement the missing item: `fn the_fn(&self) { todo!() }` @@ -53,12 +40,12 @@ LL | impl TheTrait for isize { } error[E0046]: not all trait items implemented, missing: `the_fn` --> $DIR/coherence-orphan.rs:17:1 | -LL | impl TheTrait for TheType { } +LL | impl TheTrait for TheType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `the_fn` in implementation | = help: implement the missing item: `fn the_fn(&self) { todo!() }` -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 5 previous errors Some errors have detailed explanations: E0046, E0117. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/coherence/coherence-overlap-negative-impls.rs b/tests/ui/coherence/coherence-overlap-negative-impls.rs index 9a85d8c5a63..ffcd56817e5 100644 --- a/tests/ui/coherence/coherence-overlap-negative-impls.rs +++ b/tests/ui/coherence/coherence-overlap-negative-impls.rs @@ -15,16 +15,20 @@ struct Test; trait Fold {} -impl Fold for Cons // 0 +impl Fold for Cons +// 0 where T: Fold, -{} +{ +} -impl Fold for Cons // 1 +impl Fold for Cons +// 1 where T: Fold, private::Is: private::NotNil, -{} +{ +} impl Fold for Test {} // 2 @@ -34,7 +38,6 @@ mod private { pub struct Is(T); pub auto trait NotNil {} - #[allow(suspicious_auto_trait_impls)] impl !NotNil for Is {} } diff --git a/tests/ui/issues/issue-106755.rs b/tests/ui/issues/issue-106755.rs index 40cb83fcabc..689b1d885ae 100644 --- a/tests/ui/issues/issue-106755.rs +++ b/tests/ui/issues/issue-106755.rs @@ -15,7 +15,5 @@ impl !Send for TestType {} //~ ERROR found both positive and nega unsafe impl Send for TestType {} //~ ERROR conflicting implementations impl !Send for TestType {} -//~^ WARNING -//~| WARNING this will change its meaning fn main() {} diff --git a/tests/ui/issues/issue-106755.stderr b/tests/ui/issues/issue-106755.stderr index 6b3a8427e77..54397034062 100644 --- a/tests/ui/issues/issue-106755.stderr +++ b/tests/ui/issues/issue-106755.stderr @@ -16,23 +16,7 @@ LL | unsafe impl Send for TestType {} LL | unsafe impl Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>` -warning: cross-crate traits with a default impl, like `Send`, should not be specialized - --> $DIR/issue-106755.rs:17:1 - | -LL | impl !Send for TestType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this will change its meaning in a future release! - = note: for more information, see issue #93367 - = note: `i32` is not a generic parameter -note: try using the same sequence of generic parameters as the struct definition - --> $DIR/issue-106755.rs:9:1 - | -LL | struct TestType(::std::marker::PhantomData); - | ^^^^^^^^^^^^^^^^^^ - = note: `#[warn(suspicious_auto_trait_impls)]` on by default - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0119, E0751. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.rs b/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.rs index 3e15e28b8fd..ce0b60b6411 100644 --- a/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.rs +++ b/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.rs @@ -1,5 +1,4 @@ //@ aux-build:tdticc_coherence_lib.rs -#![allow(suspicious_auto_trait_impls)] // Test that we do not consider associated types to be sendable without // some applicable trait bound (and we don't ICE). @@ -11,15 +10,15 @@ extern crate tdticc_coherence_lib as lib; use lib::DefaultedTrait; struct A; -impl DefaultedTrait for (A,) { } //~ ERROR E0117 +impl DefaultedTrait for (A,) {} //~ ERROR E0117 struct B; -impl !DefaultedTrait for (B,) { } //~ ERROR E0117 +impl !DefaultedTrait for (B,) {} //~ ERROR E0117 struct C; struct D(T); -impl DefaultedTrait for Box { } //~ ERROR E0321 -impl DefaultedTrait for lib::Something { } //~ ERROR E0117 -impl DefaultedTrait for D { } // OK +impl DefaultedTrait for Box {} //~ ERROR E0321 +impl DefaultedTrait for lib::Something {} //~ ERROR E0117 +impl DefaultedTrait for D {} // OK -fn main() { } +fn main() {} diff --git a/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr b/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr index fc3778b7967..32e6e88fc48 100644 --- a/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr +++ b/tests/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr @@ -1,7 +1,7 @@ error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:14:1 + --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:13:1 | -LL | impl DefaultedTrait for (A,) { } +LL | impl DefaultedTrait for (A,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^---- | | | | | this is not defined in the current crate because tuples are always foreign @@ -10,9 +10,9 @@ LL | impl DefaultedTrait for (A,) { } = note: define and implement a trait or new type instead error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:17:1 + --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:16:1 | -LL | impl !DefaultedTrait for (B,) { } +LL | impl !DefaultedTrait for (B,) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^---- | | | | | this is not defined in the current crate because tuples are always foreign @@ -21,15 +21,15 @@ LL | impl !DefaultedTrait for (B,) { } = note: define and implement a trait or new type instead error[E0321]: cross-crate traits with a default impl, like `DefaultedTrait`, can only be implemented for a struct/enum type defined in the current crate - --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:21:1 + --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:20:1 | -LL | impl DefaultedTrait for Box { } +LL | impl DefaultedTrait for Box {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait for type in another crate error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate - --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:22:1 + --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:21:1 | -LL | impl DefaultedTrait for lib::Something { } +LL | impl DefaultedTrait for lib::Something {} | ^^^^^^^^^^^^^^^^^^^^^^^^----------------- | | | | | `Something` is not defined in the current crate -- cgit 1.4.1-3-g733a5 From 4803f173be0af812f8754c4d4e33c92436c8c4e6 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 16 Feb 2024 23:12:20 -0300 Subject: Inline do_orphan_check_impl --- .../rustc_hir_analysis/src/coherence/orphan.rs | 26 ++++++++-------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index faf676ddc09..07bbaa1926e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -18,25 +18,17 @@ pub(crate) fn orphan_check_impl( let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(); trait_ref.error_reported()?; - do_orphan_check_impl(tcx, trait_ref, impl_def_id) -} - -fn do_orphan_check_impl<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - def_id: LocalDefId, -) -> Result<(), ErrorGuaranteed> { let trait_def_id = trait_ref.def_id; - match traits::orphan_check(tcx, def_id.to_def_id()) { + match traits::orphan_check(tcx, impl_def_id.to_def_id()) { Ok(()) => {} Err(err) => { - let item = tcx.hir().expect_item(def_id); + let item = tcx.hir().expect_item(impl_def_id); let hir::ItemKind::Impl(impl_) = item.kind else { - bug!("{:?} is not an impl: {:?}", def_id, item); + bug!("{:?} is not an impl: {:?}", impl_def_id, item); }; let tr = impl_.of_trait.as_ref().unwrap(); - let sp = tcx.def_span(def_id); + let sp = tcx.def_span(impl_def_id); emit_orphan_check_error( tcx, @@ -180,7 +172,7 @@ fn do_orphan_check_impl<'tcx>( // impl AutoTrait for T {} // impl AutoTrait for T {} ty::Param(..) => ( - if self_ty.is_sized(tcx, tcx.param_env(def_id)) { + if self_ty.is_sized(tcx, tcx.param_env(impl_def_id)) { LocalImpl::Allow } else { LocalImpl::Disallow { problematic_kind: "generic type" } @@ -237,7 +229,7 @@ fn do_orphan_check_impl<'tcx>( | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => { - let sp = tcx.def_span(def_id); + let sp = tcx.def_span(impl_def_id); span_bug!(sp, "weird self type for autotrait impl") } @@ -249,7 +241,7 @@ fn do_orphan_check_impl<'tcx>( LocalImpl::Allow => {} LocalImpl::Disallow { problematic_kind } => { return Err(tcx.dcx().emit_err(errors::TraitsWithDefaultImpl { - span: tcx.def_span(def_id), + span: tcx.def_span(impl_def_id), traits: tcx.def_path_str(trait_def_id), problematic_kind, self_ty, @@ -261,13 +253,13 @@ fn do_orphan_check_impl<'tcx>( NonlocalImpl::Allow => {} NonlocalImpl::DisallowBecauseNonlocal => { return Err(tcx.dcx().emit_err(errors::CrossCrateTraitsDefined { - span: tcx.def_span(def_id), + span: tcx.def_span(impl_def_id), traits: tcx.def_path_str(trait_def_id), })); } NonlocalImpl::DisallowOther => { return Err(tcx.dcx().emit_err(errors::CrossCrateTraits { - span: tcx.def_span(def_id), + span: tcx.def_span(impl_def_id), traits: tcx.def_path_str(trait_def_id), self_ty, })); -- cgit 1.4.1-3-g733a5 From 90626979170da2d6c5ec1622b3d7a9512df9eb71 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 14 Feb 2024 12:28:07 +0000 Subject: Always evaluate free constants and statics, even if previous errors occurred --- .../src/transform/check_consts/check.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 11 +++ compiler/rustc_lint/src/builtin.rs | 26 ------- compiler/rustc_lint/src/lib.rs | 2 - .../tests/ui-toml/suppress_lint_in_const/test.rs | 5 -- .../ui-toml/suppress_lint_in_const/test.stderr | 33 ++------ .../clippy/tests/ui/indexing_slicing_index.rs | 2 - .../clippy/tests/ui/indexing_slicing_index.stderr | 47 ++++-------- tests/mir-opt/dataflow-const-prop/enum.rs | 2 +- ...ssue-24949-assoc-const-static-recursion-impl.rs | 4 +- ...-24949-assoc-const-static-recursion-impl.stderr | 16 ++-- ...soc-const-static-recursion-trait-default.stderr | 14 ++-- ...sue-24949-assoc-const-static-recursion-trait.rs | 4 +- ...24949-assoc-const-static-recursion-trait.stderr | 16 ++-- tests/ui/check-static-values-constraints.stderr | 22 +++--- tests/ui/const-generics/issues/issue-100313.rs | 1 - tests/ui/const-generics/issues/issue-100313.stderr | 13 +--- tests/ui/consts/const-array-oob.rs | 3 +- tests/ui/consts/const-array-oob.stderr | 10 ++- .../const-eval/const-eval-query-stack.stderr | 3 +- tests/ui/consts/const-eval/const_fn_ptr.stderr | 10 +-- tests/ui/consts/const-eval/generic-slice.stderr | 28 +++---- .../consts/const-eval/validate_uninhabited_zsts.rs | 2 - .../const-eval/validate_uninhabited_zsts.stderr | 32 +------- tests/ui/consts/const-mut-refs/issue-76510.rs | 1 - tests/ui/consts/const-mut-refs/issue-76510.stderr | 12 +-- tests/ui/consts/const_cmp_type_id.stderr | 12 ++- tests/ui/consts/const_let_assign3.stderr | 16 ++-- .../const_refs_to_static_fail_invalid.stderr | 24 +++--- tests/ui/consts/fn_trait_refs.stderr | 36 ++++----- tests/ui/consts/issue-16538.stderr | 18 ++--- tests/ui/consts/issue-66693.rs | 4 +- tests/ui/consts/issue-66693.stderr | 19 ++++- .../const_refers_to_static_cross_crate.stderr | 36 ++++----- .../ui/consts/miri_unleashed/mutable_references.rs | 15 ++-- .../miri_unleashed/mutable_references.stderr | 48 +++++++++--- tests/ui/consts/promote-not.stderr | 40 +++++----- tests/ui/consts/promoted_const_call2.stderr | 12 +-- .../ui/consts/qualif-indirect-mutation-fail.stderr | 51 +++++++++++-- .../ui/consts/recursive-zst-static.default.stderr | 12 +-- .../ui/consts/recursive-zst-static.unleash.stderr | 12 +-- tests/ui/drop/repeat-drop-2.stderr | 18 ++--- tests/ui/error-codes/E0017.rs | 4 + tests/ui/error-codes/E0017.stderr | 33 +++++--- tests/ui/error-codes/E0388.rs | 6 +- tests/ui/error-codes/E0388.stderr | 6 +- tests/ui/error-codes/E0396.stderr | 32 ++++---- tests/ui/extern/issue-28324.rs | 1 + tests/ui/extern/issue-28324.stderr | 11 ++- .../trivially-unsatisfied-bounds-0.rs | 2 +- .../trivially-unsatisfied-bounds-0.stderr | 13 +++- tests/ui/issues/issue-17252.rs | 1 + tests/ui/issues/issue-17252.stderr | 21 +++-- .../issue-23302-3.stderr | 10 +-- tests/ui/issues/issue-76191.rs | 1 + tests/ui/issues/issue-76191.stderr | 17 ++++- tests/ui/liveness/liveness-consts.stderr | 12 +-- .../call-const-trait-method-pass.stderr | 18 ++--- .../const-closures.stderr | 22 +++--- .../const-drop-fail.precise.stderr | 55 ++++++++++++- .../const-drop.precise.stderr | 89 ++++++++++++++++++++-- .../const-drop.stock.stderr | 16 ++-- tests/ui/static/static-drop-scope.stderr | 32 ++++---- tests/ui/statics/issue-14227.rs | 1 + tests/ui/statics/issue-14227.stderr | 11 ++- tests/ui/statics/uninhabited-static.rs | 2 - tests/ui/statics/uninhabited-static.stderr | 31 +------- tests/ui/treat-err-as-bug/err.stderr | 2 +- .../ui/typeck/typeck_type_placeholder_item.stderr | 12 +-- 69 files changed, 643 insertions(+), 512 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index a3c4734f0a3..26ef083219f 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -249,7 +249,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { let secondary_errors = mem::take(&mut self.secondary_errors); if self.error_emitted.is_none() { for error in secondary_errors { - error.emit(); + self.error_emitted = Some(error.emit()); } } else { assert!(self.tcx.dcx().has_errors().is_some()); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index e53f922ad10..7cb103626da 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -198,6 +198,17 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { collect::test_opaque_hidden_types(tcx)?; } + // Make sure we evaluate all static and (non-associated) const items, even if unused. + // If any of these fail to evaluate, we do not want this crate to pass compilation. + tcx.hir().par_body_owners(|item_def_id| { + let def_kind = tcx.def_kind(item_def_id); + match def_kind { + DefKind::Static(_) => tcx.ensure().eval_static_initializer(item_def_id), + DefKind::Const => tcx.ensure().const_eval_poly(item_def_id.into()), + _ => (), + } + }); + // Freeze definitions as we don't add new ones at this point. This improves performance by // allowing lock-free access to them. tcx.untracked().definitions.freeze(); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index faa35f51cd4..f9149f54e92 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1542,32 +1542,6 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { } } -declare_lint_pass!( - /// Lint constants that are erroneous. - /// Without this lint, we might not get any diagnostic if the constant is - /// unused within this crate, even though downstream crates can't use it - /// without producing an error. - UnusedBrokenConst => [] -); - -impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst { - fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { - match it.kind { - hir::ItemKind::Const(_, _, body_id) => { - let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); - // trigger the query once for all constants since that will already report the errors - // FIXME(generic_const_items): Does this work properly with generic const items? - cx.tcx.ensure().const_eval_poly(def_id); - } - hir::ItemKind::Static(_, _, body_id) => { - let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); - cx.tcx.ensure().eval_static_initializer(def_id); - } - _ => {} - } - } -} - declare_lint! { /// The `trivial_bounds` lint detects trait bounds that don't depend on /// any type parameters. diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index e50f4ca338b..bc5038a5b14 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -213,8 +213,6 @@ late_lint_methods!( ExplicitOutlivesRequirements: ExplicitOutlivesRequirements, InvalidValue: InvalidValue, DerefNullPtr: DerefNullPtr, - // May Depend on constants elsewhere - UnusedBrokenConst: UnusedBrokenConst, UnstableFeatures: UnstableFeatures, UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller, ArrayIntoIter: ArrayIntoIter::default(), diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs index 3edb3a10b76..4ae75544c60 100644 --- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs +++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs @@ -13,8 +13,6 @@ const ARR: [i32; 2] = [1, 2]; const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true. -const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts. -//~^ ERROR: failed const fn idx() -> usize { 1 @@ -35,9 +33,6 @@ fn main() { x[const { idx() }]; // Ok, should not produce stderr. x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays. const { &ARR[idx()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true. - const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true. - // - //~^^ ERROR: failed let y = &x; y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021 diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr index 84e7eff4557..d5ce891b680 100644 --- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr +++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr @@ -1,17 +1,5 @@ -error[E0080]: evaluation of `main::{constant#3}` failed - --> $DIR/test.rs:38:14 - | -LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true. - | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 - -note: erroneous constant encountered - --> $DIR/test.rs:38:5 - | -LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true. - | ^^^^^^^^^^^^^^^^^^^^^^ - error: indexing may panic - --> $DIR/test.rs:29:5 + --> $DIR/test.rs:27:5 | LL | x[index]; | ^^^^^^^^ @@ -21,7 +9,7 @@ LL | x[index]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: indexing may panic - --> $DIR/test.rs:47:5 + --> $DIR/test.rs:42:5 | LL | v[0]; | ^^^^ @@ -29,7 +17,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/test.rs:48:5 + --> $DIR/test.rs:43:5 | LL | v[10]; | ^^^^^ @@ -37,7 +25,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/test.rs:49:5 + --> $DIR/test.rs:44:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -45,7 +33,7 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/test.rs:55:5 + --> $DIR/test.rs:50:5 | LL | v[N]; | ^^^^ @@ -53,19 +41,12 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/test.rs:56:5 + --> $DIR/test.rs:51:5 | LL | v[M]; | ^^^^ | = help: consider using `.get(n)` or `.get_mut(n)` instead -error[E0080]: evaluation of constant value failed - --> $DIR/test.rs:16:24 - | -LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts. - | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 - -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0080`. diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs index 1ac0bb11014..2ababad7fc7 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs @@ -13,8 +13,6 @@ const ARR: [i32; 2] = [1, 2]; const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. //~^ ERROR: indexing may panic -const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts. -//~^ ERROR: indexing may panic const fn idx() -> usize { 1 diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index 6d64fa1e6cf..2996e31a1aa 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -9,29 +9,20 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = note: `-D clippy::indexing-slicing` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` -error: indexing may panic - --> $DIR/indexing_slicing_index.rs:16:24 - | -LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts. - | ^^^^^^^^^^^ - | - = help: consider using `.get(n)` or `.get_mut(n)` instead - = note: the suggestion might not be applicable in constant blocks - error[E0080]: evaluation of `main::{constant#3}` failed - --> $DIR/indexing_slicing_index.rs:48:14 + --> $DIR/indexing_slicing_index.rs:46:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 note: erroneous constant encountered - --> $DIR/indexing_slicing_index.rs:48:5 + --> $DIR/indexing_slicing_index.rs:46:5 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^^^^^^^^^^^^ error: indexing may panic - --> $DIR/indexing_slicing_index.rs:29:5 + --> $DIR/indexing_slicing_index.rs:27:5 | LL | x[index]; | ^^^^^^^^ @@ -39,7 +30,7 @@ LL | x[index]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> $DIR/indexing_slicing_index.rs:32:5 + --> $DIR/indexing_slicing_index.rs:30:5 | LL | x[4]; | ^^^^ @@ -48,13 +39,13 @@ LL | x[4]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: index is out of bounds - --> $DIR/indexing_slicing_index.rs:34:5 + --> $DIR/indexing_slicing_index.rs:32:5 | LL | x[1 << 3]; | ^^^^^^^^^ error: indexing may panic - --> $DIR/indexing_slicing_index.rs:45:14 + --> $DIR/indexing_slicing_index.rs:43:14 | LL | const { &ARR[idx()] }; | ^^^^^^^^^^ @@ -63,7 +54,7 @@ LL | const { &ARR[idx()] }; = note: the suggestion might not be applicable in constant blocks error: indexing may panic - --> $DIR/indexing_slicing_index.rs:48:14 + --> $DIR/indexing_slicing_index.rs:46:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ @@ -72,13 +63,13 @@ LL | const { &ARR[idx4()] }; = note: the suggestion might not be applicable in constant blocks error: index is out of bounds - --> $DIR/indexing_slicing_index.rs:55:5 + --> $DIR/indexing_slicing_index.rs:53:5 | LL | y[4]; | ^^^^ error: indexing may panic - --> $DIR/indexing_slicing_index.rs:58:5 + --> $DIR/indexing_slicing_index.rs:56:5 | LL | v[0]; | ^^^^ @@ -86,7 +77,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/indexing_slicing_index.rs:60:5 + --> $DIR/indexing_slicing_index.rs:58:5 | LL | v[10]; | ^^^^^ @@ -94,7 +85,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/indexing_slicing_index.rs:62:5 + --> $DIR/indexing_slicing_index.rs:60:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -102,13 +93,13 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> $DIR/indexing_slicing_index.rs:70:5 + --> $DIR/indexing_slicing_index.rs:68:5 | LL | x[N]; | ^^^^ error: indexing may panic - --> $DIR/indexing_slicing_index.rs:73:5 + --> $DIR/indexing_slicing_index.rs:71:5 | LL | v[N]; | ^^^^ @@ -116,7 +107,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/indexing_slicing_index.rs:75:5 + --> $DIR/indexing_slicing_index.rs:73:5 | LL | v[M]; | ^^^^ @@ -124,17 +115,11 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> $DIR/indexing_slicing_index.rs:79:13 + --> $DIR/indexing_slicing_index.rs:77:13 | LL | let _ = x[4]; | ^^^^ -error[E0080]: evaluation of constant value failed - --> $DIR/indexing_slicing_index.rs:16:24 - | -LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts. - | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 - -error: aborting due to 17 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/mir-opt/dataflow-const-prop/enum.rs b/tests/mir-opt/dataflow-const-prop/enum.rs index 78410e49d2a..34792cb9f01 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.rs +++ b/tests/mir-opt/dataflow-const-prop/enum.rs @@ -62,7 +62,7 @@ fn statics() { static RC: &E = &E::V2(4); - // CHECK: [[t:_.*]] = const {alloc2: &&E}; + // CHECK: [[t:_.*]] = const {alloc5: &&E}; // CHECK: [[e2]] = (*[[t]]); let e2 = RC; diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.rs b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.rs index 0315938a7ed..be8162c86b9 100644 --- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.rs +++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.rs @@ -4,12 +4,12 @@ trait Foo { const BAR: u32; } -const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; +const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; //~ ERROR E0391 struct GlobalImplRef; impl GlobalImplRef { - const BAR: u32 = IMPL_REF_BAR; //~ ERROR E0391 + const BAR: u32 = IMPL_REF_BAR; } fn main() {} diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr index 88b17be601c..bf37f537a49 100644 --- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr +++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr @@ -1,14 +1,9 @@ -error[E0391]: cycle detected when elaborating drops for `::BAR` - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:22 - | -LL | const BAR: u32 = IMPL_REF_BAR; - | ^^^^^^^^^^^^ - | -note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`... +error[E0391]: cycle detected when simplifying constant for the type system `IMPL_REF_BAR` --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^ + | note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:27 | @@ -29,7 +24,12 @@ note: ...which requires caching mir of `::BAR`, completing the cycle +note: ...which requires elaborating drops for `::BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:22 + | +LL | const BAR: u32 = IMPL_REF_BAR; + | ^^^^^^^^^^^^ + = note: ...which again requires simplifying constant for the type system `IMPL_REF_BAR`, completing the cycle = note: cycle used when running analysis passes on this crate = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr index fd1b4f2f964..d0ada37b99e 100644 --- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr +++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr @@ -1,9 +1,14 @@ -error[E0391]: cycle detected when elaborating drops for `FooDefault::BAR` +error[E0391]: cycle detected when caching mir of `FooDefault::BAR` for CTFE + --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 + | +LL | const BAR: u32 = DEFAULT_REF_BAR; + | ^^^^^^^^^^^^^^ + | +note: ...which requires elaborating drops for `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:22 | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^ - | note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | @@ -24,13 +29,12 @@ note: ...which requires const-evaluating + checking `FooDefault::BAR`... | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^ -note: ...which requires caching mir of `FooDefault::BAR` for CTFE... + = note: ...which again requires caching mir of `FooDefault::BAR` for CTFE, completing the cycle +note: cycle used when const-evaluating + checking `FooDefault::BAR` --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^ - = note: ...which again requires elaborating drops for `FooDefault::BAR`, completing the cycle - = note: cycle used when running analysis passes on this crate = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.rs b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.rs index 68b653ff3c5..62af8534340 100644 --- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.rs +++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.rs @@ -4,12 +4,12 @@ trait Foo { const BAR: u32; } -const TRAIT_REF_BAR: u32 = ::BAR; +const TRAIT_REF_BAR: u32 = ::BAR; //~ ERROR E0391 struct GlobalTraitRef; impl Foo for GlobalTraitRef { - const BAR: u32 = TRAIT_REF_BAR; //~ ERROR E0391 + const BAR: u32 = TRAIT_REF_BAR; } fn main() {} diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr index 303400f928e..317af7975aa 100644 --- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr +++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr @@ -1,14 +1,9 @@ -error[E0391]: cycle detected when elaborating drops for `::BAR` - --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:22 - | -LL | const BAR: u32 = TRAIT_REF_BAR; - | ^^^^^^^^^^^^^ - | -note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`... +error[E0391]: cycle detected when simplifying constant for the type system `TRAIT_REF_BAR` --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^ + | note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:28 | @@ -29,7 +24,12 @@ note: ...which requires caching mir of `::BAR`, completing the cycle +note: ...which requires elaborating drops for `::BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:22 + | +LL | const BAR: u32 = TRAIT_REF_BAR; + | ^^^^^^^^^^^^^ + = note: ...which again requires simplifying constant for the type system `TRAIT_REF_BAR`, completing the cycle = note: cycle used when running analysis passes on this crate = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information diff --git a/tests/ui/check-static-values-constraints.stderr b/tests/ui/check-static-values-constraints.stderr index 064eb4b8a5c..e7532de5647 100644 --- a/tests/ui/check-static-values-constraints.stderr +++ b/tests/ui/check-static-values-constraints.stderr @@ -129,17 +129,6 @@ LL | static STATIC19: Vec = vec![3]; = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0507]: cannot move out of static item `x` - --> $DIR/check-static-values-constraints.rs:119:9 - | -LL | x - | ^ move occurs because `x` has type `Vec`, which does not implement the `Copy` trait - | -help: consider borrowing here - | -LL | &x - | + - error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:117:32 | @@ -158,6 +147,17 @@ LL | static x: Vec = vec![3]; = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0507]: cannot move out of static item `x` + --> $DIR/check-static-values-constraints.rs:119:9 + | +LL | x + | ^ move occurs because `x` has type `Vec`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | &x + | + + error: aborting due to 17 previous errors Some errors have detailed explanations: E0010, E0015, E0493, E0507. diff --git a/tests/ui/const-generics/issues/issue-100313.rs b/tests/ui/const-generics/issues/issue-100313.rs index 9af9b5ca458..4e9d3626aa8 100644 --- a/tests/ui/const-generics/issues/issue-100313.rs +++ b/tests/ui/const-generics/issues/issue-100313.rs @@ -9,7 +9,6 @@ impl T { unsafe { *(B as *const bool as *mut bool) = false; //~^ ERROR evaluation of constant value failed [E0080] - //~| ERROR assigning to `&T` is undefined behavior } } } diff --git a/tests/ui/const-generics/issues/issue-100313.stderr b/tests/ui/const-generics/issues/issue-100313.stderr index 5832dbe1777..a422764fe2c 100644 --- a/tests/ui/const-generics/issues/issue-100313.stderr +++ b/tests/ui/const-generics/issues/issue-100313.stderr @@ -1,12 +1,3 @@ -error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell` - --> $DIR/issue-100313.rs:10:13 - | -LL | *(B as *const bool as *mut bool) = false; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: for more information, visit - = note: `#[deny(invalid_reference_casting)]` on by default - error[E0080]: evaluation of constant value failed --> $DIR/issue-100313.rs:10:13 | @@ -19,11 +10,11 @@ note: inside `T::<&true>::set_false` LL | *(B as *const bool as *mut bool) = false; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: inside `_` - --> $DIR/issue-100313.rs:19:5 + --> $DIR/issue-100313.rs:18:5 | LL | x.set_false(); | ^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-array-oob.rs b/tests/ui/consts/const-array-oob.rs index c747ab50c16..cf3db077e36 100644 --- a/tests/ui/consts/const-array-oob.rs +++ b/tests/ui/consts/const-array-oob.rs @@ -1,5 +1,6 @@ const FOO: [usize; 3] = [1, 2, 3]; -const BAR: usize = FOO[5]; // no error, because the error below occurs before regular const eval +const BAR: usize = FOO[5]; +//~^ ERROR: evaluation of constant value failed const BLUB: [u32; FOO[4]] = [5, 6]; //~^ ERROR evaluation of constant value failed [E0080] diff --git a/tests/ui/consts/const-array-oob.stderr b/tests/ui/consts/const-array-oob.stderr index d481d772894..be31f183b9a 100644 --- a/tests/ui/consts/const-array-oob.stderr +++ b/tests/ui/consts/const-array-oob.stderr @@ -1,9 +1,15 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const-array-oob.rs:4:19 + --> $DIR/const-array-oob.rs:5:19 | LL | const BLUB: [u32; FOO[4]] = [5, 6]; | ^^^^^^ index out of bounds: the length is 3 but the index is 4 -error: aborting due to 1 previous error +error[E0080]: evaluation of constant value failed + --> $DIR/const-array-oob.rs:2:20 + | +LL | const BAR: usize = FOO[5]; + | ^^^^^^ index out of bounds: the length is 3 but the index is 5 + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.stderr b/tests/ui/consts/const-eval/const-eval-query-stack.stderr index 2fcb3d41dd9..96fd9ed5f04 100644 --- a/tests/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/tests/ui/consts/const-eval/const-eval-query-stack.stderr @@ -7,6 +7,5 @@ LL | const X: i32 = 1 / 0; query stack during panic: #0 [eval_to_allocation_raw] const-evaluating + checking `X` #1 [eval_to_const_value_raw] simplifying constant for the type system `X` -#2 [lint_mod] linting top-level module -#3 [analysis] running analysis passes on this crate +#2 [analysis] running analysis passes on this crate end of query stack diff --git a/tests/ui/consts/const-eval/const_fn_ptr.stderr b/tests/ui/consts/const-eval/const_fn_ptr.stderr index ca1585f8837..682a5a23afc 100644 --- a/tests/ui/consts/const-eval/const_fn_ptr.stderr +++ b/tests/ui/consts/const-eval/const_fn_ptr.stderr @@ -1,10 +1,5 @@ warning: skipping const checks | -help: skipping check that does not even have a feature gate - --> $DIR/const_fn_ptr.rs:11:5 - | -LL | X(x) - | ^^^^ help: skipping check that does not even have a feature gate --> $DIR/const_fn_ptr.rs:15:5 | @@ -15,6 +10,11 @@ help: skipping check that does not even have a feature gate | LL | x(y) | ^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_fn_ptr.rs:11:5 + | +LL | X(x) + | ^^^^ warning: 1 warning emitted diff --git a/tests/ui/consts/const-eval/generic-slice.stderr b/tests/ui/consts/const-eval/generic-slice.stderr index ff1dc29ccfd..8559f6d1a44 100644 --- a/tests/ui/consts/const-eval/generic-slice.stderr +++ b/tests/ui/consts/const-eval/generic-slice.stderr @@ -1,3 +1,17 @@ +error[E0597]: `x` does not live long enough + --> $DIR/generic-slice.rs:27:5 + | +LL | let x: &[_] = &[]; + | - binding `x` declared here +LL | &x + | ^^ + | | + | borrowed value does not live long enough + | using this value as a static requires that `x` is borrowed for `'static` +LL | +LL | }; + | - `x` dropped here while still borrowed + error[E0597]: `x` does not live long enough --> $DIR/generic-slice.rs:15:9 | @@ -15,20 +29,6 @@ LL | LL | }; | - `x` dropped here while still borrowed -error[E0597]: `x` does not live long enough - --> $DIR/generic-slice.rs:27:5 - | -LL | let x: &[_] = &[]; - | - binding `x` declared here -LL | &x - | ^^ - | | - | borrowed value does not live long enough - | using this value as a static requires that `x` is borrowed for `'static` -LL | -LL | }; - | - `x` dropped here while still borrowed - error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs b/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs index 5fc0674c576..261dea6182d 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs @@ -1,7 +1,6 @@ const fn foo() -> ! { unsafe { std::mem::transmute(()) } //~^ ERROR evaluation of constant value failed - //~| WARN the type `!` does not permit zero-initialization [invalid_value] } // Type defined in a submodule, so that it is not "visibly" @@ -18,7 +17,6 @@ const FOO: [empty::Empty; 3] = [foo(); 3]; const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; //~^ ERROR evaluation of constant value failed -//~| WARN the type `empty::Empty` does not permit zero-initialization fn main() { FOO; diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr index 4c50ab5319e..d9f1780f7b9 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.stderr @@ -1,12 +1,3 @@ -warning: the type `!` does not permit zero-initialization - --> $DIR/validate_uninhabited_zsts.rs:2:14 - | -LL | unsafe { std::mem::transmute(()) } - | ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed - | - = note: the `!` type has no valid value - = note: `#[warn(invalid_value)]` on by default - error[E0080]: evaluation of constant value failed --> $DIR/validate_uninhabited_zsts.rs:2:14 | @@ -19,34 +10,17 @@ note: inside `foo` LL | unsafe { std::mem::transmute(()) } | ^^^^^^^^^^^^^^^^^^^^^^^ note: inside `FOO` - --> $DIR/validate_uninhabited_zsts.rs:17:33 + --> $DIR/validate_uninhabited_zsts.rs:16:33 | LL | const FOO: [empty::Empty; 3] = [foo(); 3]; | ^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/validate_uninhabited_zsts.rs:19:42 + --> $DIR/validate_uninhabited_zsts.rs:18:42 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered a value of uninhabited type `Void` -warning: the type `empty::Empty` does not permit zero-initialization - --> $DIR/validate_uninhabited_zsts.rs:19:42 - | -LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed - | -note: in this struct field - --> $DIR/validate_uninhabited_zsts.rs:14:22 - | -LL | pub struct Empty(Void); - | ^^^^ -note: enums with no inhabited variants have no valid value - --> $DIR/validate_uninhabited_zsts.rs:11:5 - | -LL | enum Void {} - | ^^^^^^^^^ - -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-mut-refs/issue-76510.rs b/tests/ui/consts/const-mut-refs/issue-76510.rs index b6a73abb09c..685e3a129c2 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.rs +++ b/tests/ui/consts/const-mut-refs/issue-76510.rs @@ -3,7 +3,6 @@ use std::mem::{transmute, ManuallyDrop}; const S: &'static mut str = &mut " hello "; //~^ ERROR: mutable references are not allowed in the final value of constants //~| ERROR: mutation through a reference is not allowed in constants -//~| ERROR: cannot borrow data in a `&` reference as mutable const fn trigger() -> [(); unsafe { let s = transmute::<(*const u8, usize), &ManuallyDrop>((S.as_ptr(), 3)); diff --git a/tests/ui/consts/const-mut-refs/issue-76510.stderr b/tests/ui/consts/const-mut-refs/issue-76510.stderr index 8a1b19baff7..ab4487026cf 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.stderr +++ b/tests/ui/consts/const-mut-refs/issue-76510.stderr @@ -14,13 +14,7 @@ LL | const S: &'static mut str = &mut " hello "; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/issue-76510.rs:3:29 - | -LL | const S: &'static mut str = &mut " hello "; - | ^^^^^^^^^^^^^^ cannot borrow as mutable - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0596, E0658, E0764. -For more information about an error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index 84be0b67307..98f5b3a5e90 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -4,6 +4,12 @@ error[E0131]: `main` function is not allowed to have generic parameters LL | const fn main() { | ^ `main` cannot have generic parameters +error[E0080]: evaluation of constant value failed + --> $DIR/const_cmp_type_id.rs:10:22 + | +LL | const _A: bool = TypeId::of::() < TypeId::of::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling non-const function `::lt` + error[E0308]: mismatched types --> $DIR/const_cmp_type_id.rs:8:13 | @@ -22,7 +28,7 @@ LL | assert!(TypeId::of::<()>() != TypeId::of::()); = note: expected constant `host` found constant `true` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0131, E0308. -For more information about an error, try `rustc --explain E0131`. +Some errors have detailed explanations: E0080, E0131, E0308. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const_let_assign3.stderr b/tests/ui/consts/const_let_assign3.stderr index 40c11acee5c..ae890131715 100644 --- a/tests/ui/consts/const_let_assign3.stderr +++ b/tests/ui/consts/const_let_assign3.stderr @@ -1,18 +1,18 @@ -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/const_let_assign3.rs:6:18 +error[E0658]: mutable references are not allowed in constants + --> $DIR/const_let_assign3.rs:14:5 | -LL | const fn foo(&mut self, x: u32) { - | ^^^^^^^^^ +LL | s.foo(3); + | ^ | = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: mutable references are not allowed in constants - --> $DIR/const_let_assign3.rs:14:5 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/const_let_assign3.rs:6:18 | -LL | s.foo(3); - | ^ +LL | const fn foo(&mut self, x: u32) { + | ^^^^^^^^^ | = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr index 4ff15f0c28b..d5bb4847746 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr @@ -9,12 +9,6 @@ LL | const C: &bool = unsafe { std::mem::transmute(&S) }; HEX_DUMP } -error: could not evaluate constant pattern - --> $DIR/const_refs_to_static_fail_invalid.rs:15:9 - | -LL | C => {} - | ^ - error[E0080]: it is undefined behavior to use this value --> $DIR/const_refs_to_static_fail_invalid.rs:25:5 | @@ -26,12 +20,6 @@ LL | const C: &i8 = unsafe { &S }; HEX_DUMP } -error: could not evaluate constant pattern - --> $DIR/const_refs_to_static_fail_invalid.rs:31:9 - | -LL | C => {} - | ^ - error[E0080]: it is undefined behavior to use this value --> $DIR/const_refs_to_static_fail_invalid.rs:39:5 | @@ -43,6 +31,18 @@ LL | const C: &i32 = unsafe { &S_MUT }; HEX_DUMP } +error: could not evaluate constant pattern + --> $DIR/const_refs_to_static_fail_invalid.rs:15:9 + | +LL | C => {} + | ^ + +error: could not evaluate constant pattern + --> $DIR/const_refs_to_static_fail_invalid.rs:31:9 + | +LL | C => {} + | ^ + error: could not evaluate constant pattern --> $DIR/const_refs_to_static_fail_invalid.rs:46:9 | diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index afe89461f03..527579d99ea 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -74,6 +74,24 @@ LL | T: ~const FnMut<()> + ~const Destruct, | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0015]: cannot call non-const operator in constants + --> $DIR/fn_trait_refs.rs:72:17 + | +LL | assert!(test_one == (1, 1, 1)); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable + +error[E0015]: cannot call non-const operator in constants + --> $DIR/fn_trait_refs.rs:75:17 + | +LL | assert!(test_two == (2, 2)); + | ^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable + error[E0015]: cannot call non-const closure in constant functions --> $DIR/fn_trait_refs.rs:17:5 | @@ -149,24 +167,6 @@ LL | const fn test_fn_mut(mut f: T) -> (T::Output, T::Output) LL | } | - value is dropped here -error[E0015]: cannot call non-const operator in constants - --> $DIR/fn_trait_refs.rs:72:17 - | -LL | assert!(test_one == (1, 1, 1)); - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - = help: add `#![feature(effects)]` to the crate attributes to enable - -error[E0015]: cannot call non-const operator in constants - --> $DIR/fn_trait_refs.rs:75:17 - | -LL | assert!(test_two == (2, 2)); - | ^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - = help: add `#![feature(effects)]` to the crate attributes to enable - error: aborting due to 20 previous errors Some errors have detailed explanations: E0015, E0493, E0635. diff --git a/tests/ui/consts/issue-16538.stderr b/tests/ui/consts/issue-16538.stderr index 834ffa8d3a0..3981b4ada49 100644 --- a/tests/ui/consts/issue-16538.stderr +++ b/tests/ui/consts/issue-16538.stderr @@ -1,3 +1,12 @@ +error[E0015]: cannot call non-const fn `Y::foo` in statics + --> $DIR/issue-16538.rs:11:23 + | +LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell + error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block --> $DIR/issue-16538.rs:11:22 | @@ -14,15 +23,6 @@ LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); | = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior -error[E0015]: cannot call non-const fn `Y::foo` in statics - --> $DIR/issue-16538.rs:11:23 - | -LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell - error: aborting due to 3 previous errors Some errors have detailed explanations: E0015, E0133. diff --git a/tests/ui/consts/issue-66693.rs b/tests/ui/consts/issue-66693.rs index df45d01ec02..416bd8ec72a 100644 --- a/tests/ui/consts/issue-66693.rs +++ b/tests/ui/consts/issue-66693.rs @@ -12,9 +12,11 @@ const fn _foo() { //~^ ERROR: argument to `panic!()` in a const context must have type `&str` } -// ensure that conforming panics don't cause an error +// ensure that conforming panics don't cause an error beyond the failure to const eval const _: () = panic!(); +//~^ ERROR: evaluation of constant value failed static _BAR: () = panic!("panic in static"); +//~^ ERROR could not evaluate static initializer const fn _bar() { panic!("panic in const fn"); diff --git a/tests/ui/consts/issue-66693.stderr b/tests/ui/consts/issue-66693.stderr index f4898fd9732..a435ace4773 100644 --- a/tests/ui/consts/issue-66693.stderr +++ b/tests/ui/consts/issue-66693.stderr @@ -14,6 +14,22 @@ LL | static _FOO: () = panic!(true); | = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0080]: evaluation of constant value failed + --> $DIR/issue-66693.rs:16:15 + | +LL | const _: () = panic!(); + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-66693.rs:16:15 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: could not evaluate static initializer + --> $DIR/issue-66693.rs:18:19 + | +LL | static _BAR: () = panic!("panic in static"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'panic in static', $DIR/issue-66693.rs:18:19 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + error: argument to `panic!()` in a const context must have type `&str` --> $DIR/issue-66693.rs:11:5 | @@ -22,5 +38,6 @@ LL | panic!(&1); | = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr index 7b22fa4399f..7a7b7bc57da 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr @@ -9,12 +9,6 @@ LL | const SLICE_MUT: &[u8; 1] = { HEX_DUMP } -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:40:9 - | -LL | SLICE_MUT => true, - | ^^^^^^^^^ - error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:17:1 | @@ -26,12 +20,6 @@ LL | const U8_MUT: &u8 = { HEX_DUMP } -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:48:9 - | -LL | U8_MUT => true, - | ^^^^^^ - error[E0080]: it is undefined behavior to use this value --> $DIR/const_refers_to_static_cross_crate.rs:23:1 | @@ -43,18 +31,30 @@ LL | const U8_MUT2: &u8 = { HEX_DUMP } -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:58:9 - | -LL | U8_MUT2 => true, - | ^^^^^^^ - error[E0080]: evaluation of constant value failed --> $DIR/const_refers_to_static_cross_crate.rs:29:15 | LL | match static_cross_crate::OPT_ZERO { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses mutable global memory +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:40:9 + | +LL | SLICE_MUT => true, + | ^^^^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:48:9 + | +LL | U8_MUT => true, + | ^^^^^^ + +error: could not evaluate constant pattern + --> $DIR/const_refers_to_static_cross_crate.rs:58:9 + | +LL | U8_MUT2 => true, + | ^^^^^^^ + error: could not evaluate constant pattern --> $DIR/const_refers_to_static_cross_crate.rs:65:9 | diff --git a/tests/ui/consts/miri_unleashed/mutable_references.rs b/tests/ui/consts/miri_unleashed/mutable_references.rs index a361c504b5e..ce7df4b1620 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.rs +++ b/tests/ui/consts/miri_unleashed/mutable_references.rs @@ -4,29 +4,26 @@ use std::cell::UnsafeCell; // a test demonstrating what things we could allow with a smarter const qualification -// this is fine because is not possible to mutate through an immutable reference. static FOO: &&mut u32 = &&mut 42; +//~^ ERROR encountered mutable pointer in final value of static -// this is fine because accessing an immutable static `BAR` is equivalent to accessing `*&BAR` -// which puts the mutable reference behind an immutable one. static BAR: &mut () = &mut (); +//~^ ERROR encountered mutable pointer in final value of static struct Foo(T); -// this is fine for the same reason as `BAR`. static BOO: &mut Foo<()> = &mut Foo(()); +//~^ ERROR encountered mutable pointer in final value of static -// interior mutability is fine struct Meh { x: &'static UnsafeCell, } unsafe impl Sync for Meh {} -static MEH: Meh = Meh { - x: &UnsafeCell::new(42), -}; +static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; +//~^ ERROR encountered mutable pointer in final value of static -// this is fine for the same reason as `BAR`. static OH_YES: &mut i32 = &mut 42; +//~^ ERROR encountered mutable pointer in final value of static fn main() { unsafe { diff --git a/tests/ui/consts/miri_unleashed/mutable_references.stderr b/tests/ui/consts/miri_unleashed/mutable_references.stderr index 39298842a33..532d7408e68 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references.stderr @@ -1,5 +1,35 @@ +error: encountered mutable pointer in final value of static + --> $DIR/mutable_references.rs:7:1 + | +LL | static FOO: &&mut u32 = &&mut 42; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/mutable_references.rs:10:1 + | +LL | static BAR: &mut () = &mut (); + | ^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/mutable_references.rs:15:1 + | +LL | static BOO: &mut Foo<()> = &mut Foo(()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/mutable_references.rs:22:1 + | +LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^ + +error: encountered mutable pointer in final value of static + --> $DIR/mutable_references.rs:25:1 + | +LL | static OH_YES: &mut i32 = &mut 42; + | ^^^^^^^^^^^^^^^^^^^^^^^ + error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item - --> $DIR/mutable_references.rs:35:5 + --> $DIR/mutable_references.rs:32:5 | LL | *OH_YES = 99; | ^^^^^^^^^^^^ cannot assign @@ -7,31 +37,31 @@ LL | *OH_YES = 99; warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:8:26 + --> $DIR/mutable_references.rs:7:26 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:12:23 + --> $DIR/mutable_references.rs:10:23 | LL | static BAR: &mut () = &mut (); | ^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:17:28 + --> $DIR/mutable_references.rs:15:28 | LL | static BOO: &mut Foo<()> = &mut Foo(()); | ^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:25:8 + --> $DIR/mutable_references.rs:22:28 | -LL | x: &UnsafeCell::new(42), - | ^^^^^^^^^^^^^^^^^^^^ +LL | static MEH: Meh = Meh { x: &UnsafeCell::new(42) }; + | ^^^^^^^^^^^^^^^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/mutable_references.rs:29:27 + --> $DIR/mutable_references.rs:25:27 | LL | static OH_YES: &mut i32 = &mut 42; | ^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/consts/promote-not.stderr b/tests/ui/consts/promote-not.stderr index b93358e8dcc..524d6981721 100644 --- a/tests/ui/consts/promote-not.stderr +++ b/tests/ui/consts/promote-not.stderr @@ -18,26 +18,6 @@ LL | x LL | }; | - temporary value is freed at the end of this statement -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:20:32 - | -LL | let _x: &'static () = &foo(); - | ----------- ^^^^^ creates a temporary value which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - -error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:28:29 - | -LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use - | | - | type annotation requires that borrow lasts for `'static` -LL | } - | - temporary value is freed at the end of this statement - error[E0716]: temporary value dropped while borrowed --> $DIR/promote-not.rs:33:29 | @@ -58,6 +38,26 @@ LL | let _val: &'static _ = &(Cell::new(1), 2).1; LL | }; | - temporary value is freed at the end of this statement +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:20:32 + | +LL | let _x: &'static () = &foo(); + | ----------- ^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:28:29 + | +LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + error[E0716]: temporary value dropped while borrowed --> $DIR/promote-not.rs:46:29 | diff --git a/tests/ui/consts/promoted_const_call2.stderr b/tests/ui/consts/promoted_const_call2.stderr index 13d864ed3db..177f7aed17d 100644 --- a/tests/ui/consts/promoted_const_call2.stderr +++ b/tests/ui/consts/promoted_const_call2.stderr @@ -18,6 +18,12 @@ LL | let _: &'static _ = &id(&String::new()); | | creates a temporary value which is freed while still in use | type annotation requires that borrow lasts for `'static` +error[E0493]: destructor of `String` cannot be evaluated at compile-time + --> $DIR/promoted_const_call2.rs:4:30 + | +LL | let _: &'static _ = &id(&String::new()); + | ^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants + error[E0716]: temporary value dropped while borrowed --> $DIR/promoted_const_call2.rs:11:26 | @@ -38,12 +44,6 @@ LL | let _: &'static _ = &id(&String::new()); | | creates a temporary value which is freed while still in use | type annotation requires that borrow lasts for `'static` -error[E0493]: destructor of `String` cannot be evaluated at compile-time - --> $DIR/promoted_const_call2.rs:4:30 - | -LL | let _: &'static _ = &id(&String::new()); - | ^^^^^^^^^^^^^ the destructor for this type cannot be evaluated in constants - error: aborting due to 5 previous errors Some errors have detailed explanations: E0493, E0716. diff --git a/tests/ui/consts/qualif-indirect-mutation-fail.stderr b/tests/ui/consts/qualif-indirect-mutation-fail.stderr index 6379c00e4b4..458dc2071c4 100644 --- a/tests/ui/consts/qualif-indirect-mutation-fail.stderr +++ b/tests/ui/consts/qualif-indirect-mutation-fail.stderr @@ -1,21 +1,55 @@ -error[E0493]: destructor of `(u32, Option)` cannot be evaluated at compile-time - --> $DIR/qualif-indirect-mutation-fail.rs:9:9 - | -LL | let mut a: (u32, Option) = (0, None); - | ^^^^^ the destructor for this type cannot be evaluated in constant functions - error[E0493]: destructor of `Option` cannot be evaluated at compile-time --> $DIR/qualif-indirect-mutation-fail.rs:15:9 | LL | let mut x = None; | ^^^^^ the destructor for this type cannot be evaluated in constants +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = note: calling non-const function ` as Drop>::drop` + | +note: inside `std::ptr::drop_in_place::> - shim(Some(Vec))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `std::ptr::drop_in_place:: - shim(Some(String))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `std::ptr::drop_in_place::> - shim(Some(Option))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `A1` + --> $DIR/qualif-indirect-mutation-fail.rs:21:1 + | +LL | }; + | ^ + error[E0493]: destructor of `Option` cannot be evaluated at compile-time --> $DIR/qualif-indirect-mutation-fail.rs:31:9 | LL | let _z = x; | ^^ the destructor for this type cannot be evaluated in constants +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = note: calling non-const function ` as Drop>::drop` + | +note: inside `std::ptr::drop_in_place::> - shim(Some(Vec))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `std::ptr::drop_in_place:: - shim(Some(String))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `std::ptr::drop_in_place::> - shim(Some(Option))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `A2` + --> $DIR/qualif-indirect-mutation-fail.rs:32:1 + | +LL | }; + | ^ + +error[E0493]: destructor of `(u32, Option)` cannot be evaluated at compile-time + --> $DIR/qualif-indirect-mutation-fail.rs:9:9 + | +LL | let mut a: (u32, Option) = (0, None); + | ^^^^^ the destructor for this type cannot be evaluated in constant functions + error[E0493]: destructor of `Option` cannot be evaluated at compile-time --> $DIR/qualif-indirect-mutation-fail.rs:36:9 | @@ -52,6 +86,7 @@ error[E0493]: destructor of `Option` cannot be evaluated at compile-time LL | let x: Option = None; | ^ the destructor for this type cannot be evaluated in constant functions -error: aborting due to 9 previous errors +error: aborting due to 11 previous errors -For more information about this error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0080, E0493. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/recursive-zst-static.default.stderr b/tests/ui/consts/recursive-zst-static.default.stderr index 7679c50c74b..dedca16db8d 100644 --- a/tests/ui/consts/recursive-zst-static.default.stderr +++ b/tests/ui/consts/recursive-zst-static.default.stderr @@ -16,17 +16,7 @@ note: ...which requires evaluating initializer of static `B`... LL | static B: () = A; | ^ = note: ...which again requires evaluating initializer of static `A`, completing the cycle -note: cycle used when linting top-level module - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | / static FOO: () = FOO; -LL | | -LL | | -LL | | static A: () = B; -... | -LL | | FOO -LL | | } - | |_^ + = note: cycle used when running analysis passes on this crate = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 2 previous errors diff --git a/tests/ui/consts/recursive-zst-static.unleash.stderr b/tests/ui/consts/recursive-zst-static.unleash.stderr index 7679c50c74b..dedca16db8d 100644 --- a/tests/ui/consts/recursive-zst-static.unleash.stderr +++ b/tests/ui/consts/recursive-zst-static.unleash.stderr @@ -16,17 +16,7 @@ note: ...which requires evaluating initializer of static `B`... LL | static B: () = A; | ^ = note: ...which again requires evaluating initializer of static `A`, completing the cycle -note: cycle used when linting top-level module - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | / static FOO: () = FOO; -LL | | -LL | | -LL | | static A: () = B; -... | -LL | | FOO -LL | | } - | |_^ + = note: cycle used when running analysis passes on this crate = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 2 previous errors diff --git a/tests/ui/drop/repeat-drop-2.stderr b/tests/ui/drop/repeat-drop-2.stderr index f030228f71a..009a2057212 100644 --- a/tests/ui/drop/repeat-drop-2.stderr +++ b/tests/ui/drop/repeat-drop-2.stderr @@ -1,3 +1,12 @@ +error[E0493]: destructor of `String` cannot be evaluated at compile-time + --> $DIR/repeat-drop-2.rs:7:25 + | +LL | const _: [String; 0] = [String::new(); 0]; + | -^^^^^^^^^^^^^---- + | || + | |the destructor for this type cannot be evaluated in constants + | value is dropped here + error[E0382]: use of moved value: `foo` --> $DIR/repeat-drop-2.rs:4:17 | @@ -13,15 +22,6 @@ help: consider cloning the value if the performance cost is acceptable LL | let _bar = foo.clone(); | ++++++++ -error[E0493]: destructor of `String` cannot be evaluated at compile-time - --> $DIR/repeat-drop-2.rs:7:25 - | -LL | const _: [String; 0] = [String::new(); 0]; - | -^^^^^^^^^^^^^---- - | || - | |the destructor for this type cannot be evaluated in constants - | value is dropped here - error[E0381]: used binding `x` isn't initialized --> $DIR/repeat-drop-2.rs:12:14 | diff --git a/tests/ui/error-codes/E0017.rs b/tests/ui/error-codes/E0017.rs index 144340b3512..c29015c8f33 100644 --- a/tests/ui/error-codes/E0017.rs +++ b/tests/ui/error-codes/E0017.rs @@ -1,5 +1,8 @@ #![feature(const_mut_refs)] +//@ normalize-stderr-test "\(size: ., align: .\)" -> "" +//@ normalize-stderr-test " +│ ╾─+╼" -> "" + static X: i32 = 1; const C: i32 = 2; static mut M: i32 = 3; @@ -14,5 +17,6 @@ static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are no static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs] +//~| ERROR undefined behavior fn main() {} diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr index 982ce52764e..b5e9bacb122 100644 --- a/tests/ui/error-codes/E0017.stderr +++ b/tests/ui/error-codes/E0017.stderr @@ -1,5 +1,5 @@ warning: creating a mutable reference to mutable static is discouraged - --> $DIR/E0017.rs:15:52 + --> $DIR/E0017.rs:18:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; | ^^^^^^ mutable reference to mutable static @@ -14,7 +14,7 @@ LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { addr_of_mut!(M) }; | ~~~~~~~~~~~~~~~ warning: taking a mutable reference to a `const` item - --> $DIR/E0017.rs:7:30 + --> $DIR/E0017.rs:10:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ @@ -22,26 +22,26 @@ LL | const CR: &'static mut i32 = &mut C; = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/E0017.rs:4:1 + --> $DIR/E0017.rs:7:1 | LL | const C: i32 = 2; | ^^^^^^^^^^^^ = note: `#[warn(const_item_mutation)]` on by default error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/E0017.rs:7:30 + --> $DIR/E0017.rs:10:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:10:39 + --> $DIR/E0017.rs:13:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable warning: taking a mutable reference to a `const` item - --> $DIR/E0017.rs:12:38 + --> $DIR/E0017.rs:15:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ @@ -49,18 +49,29 @@ LL | static CONST_REF: &'static mut i32 = &mut C; = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/E0017.rs:4:1 + --> $DIR/E0017.rs:7:1 | LL | const C: i32 = 2; | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0017.rs:12:38 + --> $DIR/E0017.rs:15:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ -error: aborting due to 3 previous errors; 3 warnings emitted +error[E0080]: it is undefined behavior to use this value + --> $DIR/E0017.rs:18:1 + | +LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const` or `static` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant { + ╾ALLOC0╼ + } + +error: aborting due to 4 previous errors; 3 warnings emitted -Some errors have detailed explanations: E0596, E0764. -For more information about an error, try `rustc --explain E0596`. +Some errors have detailed explanations: E0080, E0596, E0764. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/error-codes/E0388.rs b/tests/ui/error-codes/E0388.rs index bd371328e6b..bbc5f2710bf 100644 --- a/tests/ui/error-codes/E0388.rs +++ b/tests/ui/error-codes/E0388.rs @@ -2,10 +2,12 @@ static X: i32 = 1; const C: i32 = 2; const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed - //~| WARN taking a mutable + +//~| WARN taking a mutable static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed - //~| WARN taking a mutable + +//~| WARN taking a mutable fn main() {} diff --git a/tests/ui/error-codes/E0388.stderr b/tests/ui/error-codes/E0388.stderr index 3e89e3f804b..cb7047072bd 100644 --- a/tests/ui/error-codes/E0388.stderr +++ b/tests/ui/error-codes/E0388.stderr @@ -20,7 +20,7 @@ LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ error[E0658]: mutable references are not allowed in statics - --> $DIR/E0388.rs:6:39 + --> $DIR/E0388.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ @@ -30,7 +30,7 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: taking a mutable reference to a `const` item - --> $DIR/E0388.rs:8:38 + --> $DIR/E0388.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ @@ -44,7 +44,7 @@ LL | const C: i32 = 2; | ^^^^^^^^^^^^ error[E0764]: mutable references are not allowed in the final value of statics - --> $DIR/E0388.rs:8:38 + --> $DIR/E0388.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ diff --git a/tests/ui/error-codes/E0396.stderr b/tests/ui/error-codes/E0396.stderr index ac1e7d65ce8..8bc14139d63 100644 --- a/tests/ui/error-codes/E0396.stderr +++ b/tests/ui/error-codes/E0396.stderr @@ -8,42 +8,42 @@ LL | const VALUE: u8 = unsafe { *REG_ADDR }; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/E0396.rs:10:11 +error[E0658]: dereferencing raw mutable pointers in constants is unstable + --> $DIR/E0396.rs:14:36 | -LL | match *INFALLIBLE {} - | ^^^^^^^^^^^ +LL | const BAD: () = unsafe { match *INFALLIBLE {} }; + | ^^^^^^^^^^^ | = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: dereferencing raw mutable pointers in constant functions is unstable - --> $DIR/E0396.rs:10:11 +error[E0658]: dereferencing raw mutable pointers in constants is unstable + --> $DIR/E0396.rs:14:36 | -LL | match *INFALLIBLE {} - | ^^^^^^^^^^^ +LL | const BAD: () = unsafe { match *INFALLIBLE {} }; + | ^^^^^^^^^^^ | = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0658]: dereferencing raw mutable pointers in constants is unstable - --> $DIR/E0396.rs:14:36 +error[E0658]: dereferencing raw mutable pointers in constant functions is unstable + --> $DIR/E0396.rs:10:11 | -LL | const BAD: () = unsafe { match *INFALLIBLE {} }; - | ^^^^^^^^^^^ +LL | match *INFALLIBLE {} + | ^^^^^^^^^^^ | = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: dereferencing raw mutable pointers in constants is unstable - --> $DIR/E0396.rs:14:36 +error[E0658]: dereferencing raw mutable pointers in constant functions is unstable + --> $DIR/E0396.rs:10:11 | -LL | const BAD: () = unsafe { match *INFALLIBLE {} }; - | ^^^^^^^^^^^ +LL | match *INFALLIBLE {} + | ^^^^^^^^^^^ | = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable diff --git a/tests/ui/extern/issue-28324.rs b/tests/ui/extern/issue-28324.rs index f74726e8166..a5e240fa283 100644 --- a/tests/ui/extern/issue-28324.rs +++ b/tests/ui/extern/issue-28324.rs @@ -4,5 +4,6 @@ extern "C" { pub static BAZ: u32 = *&error_message_count; //~^ ERROR use of extern static is unsafe and requires +//~| ERROR could not evaluate static initializer fn main() {} diff --git a/tests/ui/extern/issue-28324.stderr b/tests/ui/extern/issue-28324.stderr index 94ff2131993..1fccb34fdf3 100644 --- a/tests/ui/extern/issue-28324.stderr +++ b/tests/ui/extern/issue-28324.stderr @@ -1,3 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/issue-28324.rs:5:23 + | +LL | pub static BAZ: u32 = *&error_message_count; + | ^^^^^^^^^^^^^^^^^^^^^ cannot access extern static (DefId(0:4 ~ issue_28324[8ec4]::{extern#0}::error_message_count)) + error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-28324.rs:5:25 | @@ -6,6 +12,7 @@ LL | pub static BAZ: u32 = *&error_message_count; | = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0133`. +Some errors have detailed explanations: E0080, E0133. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs index dd00b327d2d..93f01c9577c 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.rs @@ -3,7 +3,7 @@ // Ensure that we check if trivial bounds on const items hold or not. -const UNUSABLE: () = () +const UNUSABLE: () = () //~ ERROR evaluation of constant value failed where String: Copy; diff --git a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr index 942e5dbd88e..407682fee56 100644 --- a/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr +++ b/tests/ui/generic-const-items/trivially-unsatisfied-bounds-0.stderr @@ -1,3 +1,11 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/trivially-unsatisfied-bounds-0.rs:6:1 + | +LL | / const UNUSABLE: () = () +LL | | where +LL | | String: Copy; + | |_________________^ entering unreachable code + error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/trivially-unsatisfied-bounds-0.rs:11:13 | @@ -13,6 +21,7 @@ LL | where LL | String: Copy; | ^^^^ required by this bound in `UNUSABLE` -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0080, E0277. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/issues/issue-17252.rs b/tests/ui/issues/issue-17252.rs index 7141e4874c0..5941e10f8b0 100644 --- a/tests/ui/issues/issue-17252.rs +++ b/tests/ui/issues/issue-17252.rs @@ -4,6 +4,7 @@ fn main() { let _x: [u8; FOO]; // caused stack overflow prior to fix let _y: usize = 1 + { const BAR: usize = BAR; + //~^ ERROR: cycle let _z: [u8; BAR]; // caused stack overflow prior to fix 1 }; diff --git a/tests/ui/issues/issue-17252.stderr b/tests/ui/issues/issue-17252.stderr index d8984860457..56bc32b19ab 100644 --- a/tests/ui/issues/issue-17252.stderr +++ b/tests/ui/issues/issue-17252.stderr @@ -10,13 +10,24 @@ note: ...which requires const-evaluating + checking `FOO`... LL | const FOO: usize = FOO; | ^^^ = note: ...which again requires simplifying constant for the type system `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `main::{constant#0}` - --> $DIR/issue-17252.rs:4:18 + = note: cycle used when running analysis passes on this crate + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0391]: cycle detected when simplifying constant for the type system `main::BAR` + --> $DIR/issue-17252.rs:6:9 + | +LL | const BAR: usize = BAR; + | ^^^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `main::BAR`... + --> $DIR/issue-17252.rs:6:28 | -LL | let _x: [u8; FOO]; // caused stack overflow prior to fix - | ^^^ +LL | const BAR: usize = BAR; + | ^^^ + = note: ...which again requires simplifying constant for the type system `main::BAR`, completing the cycle + = note: cycle used when running analysis passes on this crate = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr index e23957c6de7..8a152f58966 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr +++ b/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr @@ -20,15 +20,7 @@ note: ...which requires const-evaluating + checking `B`... LL | const B: i32 = A; | ^ = note: ...which again requires simplifying constant for the type system `A`, completing the cycle -note: cycle used when linting top-level module - --> $DIR/issue-23302-3.rs:1:1 - | -LL | / const A: i32 = B; -LL | | -LL | | const B: i32 = A; -LL | | -LL | | fn main() { } - | |_____________^ + = note: cycle used when running analysis passes on this crate = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-76191.rs b/tests/ui/issues/issue-76191.rs index d9790d2b56e..277624c005a 100644 --- a/tests/ui/issues/issue-76191.rs +++ b/tests/ui/issues/issue-76191.rs @@ -6,6 +6,7 @@ use std::ops::RangeInclusive; const RANGE: RangeInclusive = 0..=255; const RANGE2: RangeInclusive = panic!(); +//~^ ERROR evaluation of constant value failed fn main() { let n: i32 = 1; diff --git a/tests/ui/issues/issue-76191.stderr b/tests/ui/issues/issue-76191.stderr index 32d9105b259..3702bfb7769 100644 --- a/tests/ui/issues/issue-76191.stderr +++ b/tests/ui/issues/issue-76191.stderr @@ -1,5 +1,13 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-76191.rs:8:37 + | +LL | const RANGE2: RangeInclusive = panic!(); + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-76191.rs:8:37 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0308]: mismatched types - --> $DIR/issue-76191.rs:13:9 + --> $DIR/issue-76191.rs:14:9 | LL | const RANGE: RangeInclusive = 0..=255; | -------------------------------- constant defined here @@ -20,7 +28,7 @@ LL | 0..=255 => {} | ~~~~~~~ error[E0308]: mismatched types - --> $DIR/issue-76191.rs:15:9 + --> $DIR/issue-76191.rs:16:9 | LL | const RANGE2: RangeInclusive = panic!(); | --------------------------------- constant defined here @@ -38,6 +46,7 @@ LL | RANGE2 => {} found struct `RangeInclusive` = note: constants only support matching by type, if you meant to match against a range of values, consider using a range pattern like `min ..= max` in the match block -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0080, E0308. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/liveness/liveness-consts.stderr b/tests/ui/liveness/liveness-consts.stderr index 016debdd396..34ce3947337 100644 --- a/tests/ui/liveness/liveness-consts.stderr +++ b/tests/ui/liveness/liveness-consts.stderr @@ -23,12 +23,6 @@ warning: unused variable: `z` LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] { | ^ help: if this is intentional, prefix it with an underscore: `_z` -warning: unused variable: `z` - --> $DIR/liveness-consts.rs:60:13 - | -LL | let z = 42; - | ^ help: if this is intentional, prefix it with an underscore: `_z` - warning: variable `a` is assigned to, but never used --> $DIR/liveness-consts.rs:7:13 | @@ -46,6 +40,12 @@ LL | b += 1; = help: maybe it is overwritten before being read? = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]` +warning: unused variable: `z` + --> $DIR/liveness-consts.rs:60:13 + | +LL | let z = 42; + | ^ help: if this is intentional, prefix it with an underscore: `_z` + warning: value assigned to `t` is never read --> $DIR/liveness-consts.rs:42:9 | diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr index e72d259e8a5..f802841d2e4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-const-trait-method-pass.stderr @@ -1,12 +1,3 @@ -error[E0015]: cannot call non-const fn `::plus` in constant functions - --> $DIR/call-const-trait-method-pass.rs:36:7 - | -LL | a.plus(b) - | ^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = help: add `#![feature(effects)]` to the crate attributes to enable - error[E0015]: cannot call non-const operator in constants --> $DIR/call-const-trait-method-pass.rs:39:22 | @@ -21,6 +12,15 @@ LL | impl const std::ops::Add for Int { = note: calls in constants are limited to constant functions, tuple structs and tuple variants = help: add `#![feature(effects)]` to the crate attributes to enable +error[E0015]: cannot call non-const fn `::plus` in constant functions + --> $DIR/call-const-trait-method-pass.rs:36:7 + | +LL | a.plus(b) + | ^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = help: add `#![feature(effects)]` to the crate attributes to enable + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr index b66b27ad2bd..a225125ef53 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr @@ -23,23 +23,23 @@ LL | const fn answer u8>(f: &F) -> u8 { | ^^^^^^^^^^ error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closures.rs:12:5 + --> $DIR/const-closures.rs:24:5 | -LL | f() * 7 +LL | f() + f() | ^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = help: add `#![feature(effects)]` to the crate attributes to enable help: consider further restricting this bound | -LL | F: ~const FnOnce() -> u8 + ~const std::ops::Fn<()>, - | +++++++++++++++++++++++++ +LL | const fn answer u8 + ~const std::ops::Fn<()>>(f: &F) -> u8 { + | +++++++++++++++++++++++++ error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closures.rs:24:5 + --> $DIR/const-closures.rs:24:11 | LL | f() + f() - | ^^^ + | ^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = help: add `#![feature(effects)]` to the crate attributes to enable @@ -49,17 +49,17 @@ LL | const fn answer u8 + ~const std::ops::Fn<()>>(f: &F) -> u | +++++++++++++++++++++++++ error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closures.rs:24:11 + --> $DIR/const-closures.rs:12:5 | -LL | f() + f() - | ^^^ +LL | f() * 7 + | ^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = help: add `#![feature(effects)]` to the crate attributes to enable help: consider further restricting this bound | -LL | const fn answer u8 + ~const std::ops::Fn<()>>(f: &F) -> u8 { - | +++++++++++++++++++++++++ +LL | F: ~const FnOnce() -> u8 + ~const std::ops::Fn<()>, + | +++++++++++++++++++++++++ error: aborting due to 7 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr index 8997e7ade6c..9afa2072dde 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr @@ -4,6 +4,57 @@ error[E0493]: destructor of `T` cannot be evaluated at compile-time LL | const fn check(_: T) {} | ^ the destructor for this type cannot be evaluated in constant functions -error: aborting due to 1 previous error +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = note: calling non-const function `::drop` + | +note: inside `std::ptr::drop_in_place:: - shim(Some(NonTrivialDrop))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `check::` + --> $DIR/const-drop-fail.rs:24:43 + | +LL | const fn check(_: T) {} + | ^ +note: inside `_` + --> $DIR/const-drop-fail.rs:28:23 + | +LL | const _: () = check($exp); + | ^^^^^^^^^^^ +... +LL | / check_all! { +LL | | NonTrivialDrop, +LL | | ConstImplWithDropGlue(NonTrivialDrop), +LL | | } + | |_- in this macro invocation + = note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = note: calling non-const function `::drop` + | +note: inside `std::ptr::drop_in_place:: - shim(Some(ConstImplWithDropGlue))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `check::` + --> $DIR/const-drop-fail.rs:24:43 + | +LL | const fn check(_: T) {} + | ^ +note: inside `_` + --> $DIR/const-drop-fail.rs:28:23 + | +LL | const _: () = check($exp); + | ^^^^^^^^^^^ +... +LL | / check_all! { +LL | | NonTrivialDrop, +LL | | ConstImplWithDropGlue(NonTrivialDrop), +LL | | } + | |_- in this macro invocation + = note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0080, E0493. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr index f166bdf6cec..5ff3be713a7 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr @@ -1,15 +1,92 @@ +error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time + --> $DIR/const-drop.rs:24:13 + | +LL | let _ = S(&mut c); + | ^^^^^^^^^ the destructor for this type cannot be evaluated in constant functions + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = note: calling non-const function ` as Drop>::drop` + | +note: inside `std::ptr::drop_in_place::> - shim(Some(S<'_>))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `b` + --> $DIR/const-drop.rs:24:22 + | +LL | let _ = S(&mut c); + | ^ +note: inside `C` + --> $DIR/const-drop.rs:30:15 + | +LL | const C: u8 = b(); + | ^^^ + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/const-drop.rs:19:32 | LL | const fn a(_: T) {} | ^ the destructor for this type cannot be evaluated in constant functions -error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time - --> $DIR/const-drop.rs:24:13 +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | let _ = S(&mut c); - | ^^^^^^^^^ the destructor for this type cannot be evaluated in constant functions + = note: calling non-const function `::drop` + | +note: inside `std::ptr::drop_in_place:: - shim(Some(t::ConstDrop))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `a::` + --> $DIR/const-drop.rs:19:39 + | +LL | const fn a(_: T) {} + | ^ +note: inside `_` + --> $DIR/const-drop.rs:35:27 + | +LL | const _: () = a($exp); + | ^^^^^^^ +... +LL | / implements_const_drop! { +LL | | 1u8, +LL | | 2, +LL | | 3.0, +... | +LL | | Result::::Ok(1), +LL | | } + | |_- in this macro invocation + = note: this error originates in the macro `implements_const_drop` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + = note: calling non-const function `::drop` + | +note: inside `std::ptr::drop_in_place:: - shim(Some(t::ConstDrop))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `std::ptr::drop_in_place:: - shim(Some(t::HasConstDrop))` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL +note: inside `a::` + --> $DIR/const-drop.rs:19:39 + | +LL | const fn a(_: T) {} + | ^ +note: inside `_` + --> $DIR/const-drop.rs:35:27 + | +LL | const _: () = a($exp); + | ^^^^^^^ +... +LL | / implements_const_drop! { +LL | | 1u8, +LL | | 2, +LL | | 3.0, +... | +LL | | Result::::Ok(1), +LL | | } + | |_- in this macro invocation + = note: this error originates in the macro `implements_const_drop` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0493`. +Some errors have detailed explanations: E0080, E0493. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr index 23e36887025..40e39cbefbc 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr @@ -1,11 +1,3 @@ -error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/const-drop.rs:19:32 - | -LL | const fn a(_: T) {} - | ^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constant functions - error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time --> $DIR/const-drop.rs:24:13 | @@ -14,6 +6,14 @@ LL | let _ = S(&mut c); | | | the destructor for this type cannot be evaluated in constant functions +error[E0493]: destructor of `T` cannot be evaluated at compile-time + --> $DIR/const-drop.rs:19:32 + | +LL | const fn a(_: T) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/static/static-drop-scope.stderr b/tests/ui/static/static-drop-scope.stderr index 2c55161628f..24658bc601e 100644 --- a/tests/ui/static/static-drop-scope.stderr +++ b/tests/ui/static/static-drop-scope.stderr @@ -30,6 +30,22 @@ LL | const EARLY_DROP_C: i32 = (WithDtor, 0).1; | | | the destructor for this type cannot be evaluated in constants +error[E0493]: destructor of `(Option, i32)` cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:27:34 + | +LL | const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1; + | ^^^^^^^^^^^^^^^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + +error[E0493]: destructor of `(Option, i32)` cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:32:43 + | +LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1; + | ^^^^^^^^^^^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constants + error[E0493]: destructor of `T` cannot be evaluated at compile-time --> $DIR/static-drop-scope.rs:19:24 | @@ -47,22 +63,6 @@ LL | LL | } | - value is dropped here -error[E0493]: destructor of `(Option, i32)` cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:27:34 - | -LL | const EARLY_DROP_C_OPTION: i32 = (Some(WithDtor), 0).1; - | ^^^^^^^^^^^^^^^^^^^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - -error[E0493]: destructor of `(Option, i32)` cannot be evaluated at compile-time - --> $DIR/static-drop-scope.rs:32:43 - | -LL | const EARLY_DROP_C_OPTION_CONSTANT: i32 = (HELPER, 0).1; - | ^^^^^^^^^^^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constants - error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/statics/issue-14227.rs b/tests/ui/statics/issue-14227.rs index a1fde14600a..8a70f51d3b4 100644 --- a/tests/ui/statics/issue-14227.rs +++ b/tests/ui/statics/issue-14227.rs @@ -3,5 +3,6 @@ extern "C" { } static CRASH: u32 = symbol; //~^ ERROR use of extern static is unsafe and requires +//~| ERROR could not evaluate static initializer fn main() {} diff --git a/tests/ui/statics/issue-14227.stderr b/tests/ui/statics/issue-14227.stderr index 085d6df9c41..0aeb973bff3 100644 --- a/tests/ui/statics/issue-14227.stderr +++ b/tests/ui/statics/issue-14227.stderr @@ -1,3 +1,9 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/issue-14227.rs:4:21 + | +LL | static CRASH: u32 = symbol; + | ^^^^^^ cannot access extern static (DefId(0:4 ~ issue_14227[1133]::{extern#0}::symbol)) + error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-14227.rs:4:21 | @@ -6,6 +12,7 @@ LL | static CRASH: u32 = symbol; | = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0133`. +Some errors have detailed explanations: E0080, E0133. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/statics/uninhabited-static.rs b/tests/ui/statics/uninhabited-static.rs index f5c6f444317..a0f83f45079 100644 --- a/tests/ui/statics/uninhabited-static.rs +++ b/tests/ui/statics/uninhabited-static.rs @@ -12,10 +12,8 @@ extern { static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type //~| WARN: previously accepted //~| ERROR could not evaluate static initializer -//~| WARN: type `Void` does not permit zero-initialization static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type //~| WARN: previously accepted //~| ERROR could not evaluate static initializer -//~| WARN: type `Void` does not permit zero-initialization fn main() {} diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr index 9260930473f..f891c0ce25b 100644 --- a/tests/ui/statics/uninhabited-static.stderr +++ b/tests/ui/statics/uninhabited-static.stderr @@ -34,7 +34,7 @@ LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; = note: uninhabited statics cannot be initialized, and any access would be an immediate error error: static of uninhabited type - --> $DIR/uninhabited-static.rs:16:1 + --> $DIR/uninhabited-static.rs:15:1 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; | ^^^^^^^^^^^^^^^^^^^ @@ -49,37 +49,12 @@ error[E0080]: could not evaluate static initializer LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type `Void` -warning: the type `Void` does not permit zero-initialization - --> $DIR/uninhabited-static.rs:12:31 - | -LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed - | -note: enums with no inhabited variants have no valid value - --> $DIR/uninhabited-static.rs:4:1 - | -LL | enum Void {} - | ^^^^^^^^^ - = note: `#[warn(invalid_value)]` on by default - error[E0080]: could not evaluate static initializer - --> $DIR/uninhabited-static.rs:16:32 + --> $DIR/uninhabited-static.rs:15:32 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type `Void` -warning: the type `Void` does not permit zero-initialization - --> $DIR/uninhabited-static.rs:16:32 - | -LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed - | -note: enums with no inhabited variants have no valid value - --> $DIR/uninhabited-static.rs:4:1 - | -LL | enum Void {} - | ^^^^^^^^^ - -error: aborting due to 6 previous errors; 2 warnings emitted +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/treat-err-as-bug/err.stderr b/tests/ui/treat-err-as-bug/err.stderr index ca04ee9e0cf..eb7b50b4210 100644 --- a/tests/ui/treat-err-as-bug/err.stderr +++ b/tests/ui/treat-err-as-bug/err.stderr @@ -8,5 +8,5 @@ error: the compiler unexpectedly panicked. this is a bug. query stack during panic: #0 [eval_static_initializer] evaluating initializer of static `C` -#1 [lint_mod] linting top-level module +#1 [analysis] running analysis passes on this crate end of query stack diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index 18f6edad5c0..c102926fcf5 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -666,12 +666,6 @@ LL | type F: std::ops::Fn(_); LL | impl Qux for Struct { | ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation -error[E0515]: cannot return reference to function parameter `x` - --> $DIR/typeck_type_placeholder_item.rs:50:5 - | -LL | &x - | ^^ returns a reference to data owned by the current function - error[E0015]: cannot call non-const fn ` as Iterator>::filter::<{closure@$DIR/typeck_type_placeholder_item.rs:230:29: 230:32}>` in constants --> $DIR/typeck_type_placeholder_item.rs:230:22 | @@ -690,6 +684,12 @@ LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); = note: calls in constants are limited to constant functions, tuple structs and tuple variants = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable +error[E0515]: cannot return reference to function parameter `x` + --> $DIR/typeck_type_placeholder_item.rs:50:5 + | +LL | &x + | ^^ returns a reference to data owned by the current function + error: aborting due to 75 previous errors Some errors have detailed explanations: E0015, E0046, E0121, E0282, E0403, E0515. -- cgit 1.4.1-3-g733a5 From dc7a01610f2a26dd1e1dadd136b20715909d6b94 Mon Sep 17 00:00:00 2001 From: Kalle Wachsmuth Date: Tue, 20 Feb 2024 00:14:53 +0100 Subject: trigger `unsafe_code` on `global_asm!` invocations --- compiler/rustc_builtin_macros/src/asm.rs | 2 +- compiler/rustc_lint/messages.ftl | 5 +++- compiler/rustc_lint/src/builtin.rs | 4 ++++ compiler/rustc_lint/src/lints.rs | 3 +++ tests/ui/asm/bad-arch.stderr | 2 -- .../lint/unsafe_code/lint-global-asm-as-unsafe.rs | 20 ++++++++++++++++ .../unsafe_code/lint-global-asm-as-unsafe.stderr | 27 ++++++++++++++++++++++ 7 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 tests/ui/lint/unsafe_code/lint-global-asm-as-unsafe.rs create mode 100644 tests/ui/lint/unsafe_code/lint-global-asm-as-unsafe.stderr (limited to 'compiler') diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 0b2e63b403b..c5a73c31995 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -773,7 +773,7 @@ pub(super) fn expand_global_asm<'cx>( kind: ast::VisibilityKind::Inherited, tokens: None, }, - span: ecx.with_def_site_ctxt(sp), + span: sp, tokens: None, })]) } else { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 785895e0ab8..1548646c04a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -72,8 +72,11 @@ lint_builtin_explicit_outlives = outlives requirements can be inferred lint_builtin_export_name_fn = declaration of a function with `export_name` lint_builtin_export_name_method = declaration of a method with `export_name` - lint_builtin_export_name_static = declaration of a static with `export_name` + +lint_builtin_global_asm = usage of `core::arch::global_asm` +lint_builtin_global_macro_unsafety = using this macro is unsafe even though it does not need an `unsafe` block + lint_builtin_impl_unsafe_method = implementation of an `unsafe` method lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index faa35f51cd4..f00177fde7c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -393,6 +393,10 @@ impl EarlyLintPass for UnsafeCode { } } + ast::ItemKind::GlobalAsm(..) => { + self.report_unsafe(cx, it.span, BuiltinUnsafe::GlobalAsm); + } + _ => {} } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c204c67fc1f..7015d813390 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -114,6 +114,9 @@ pub enum BuiltinUnsafe { DeclUnsafeMethod, #[diag(lint_builtin_impl_unsafe_method)] ImplUnsafeMethod, + #[diag(lint_builtin_global_asm)] + #[note(lint_builtin_global_macro_unsafety)] + GlobalAsm, } #[derive(LintDiagnostic)] diff --git a/tests/ui/asm/bad-arch.stderr b/tests/ui/asm/bad-arch.stderr index 23aad9908ef..c6f726600eb 100644 --- a/tests/ui/asm/bad-arch.stderr +++ b/tests/ui/asm/bad-arch.stderr @@ -9,8 +9,6 @@ error[E0472]: inline assembly is unsupported on this target | LL | global_asm!(""); | ^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `global_asm` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/lint/unsafe_code/lint-global-asm-as-unsafe.rs b/tests/ui/lint/unsafe_code/lint-global-asm-as-unsafe.rs new file mode 100644 index 00000000000..02df0e6de95 --- /dev/null +++ b/tests/ui/lint/unsafe_code/lint-global-asm-as-unsafe.rs @@ -0,0 +1,20 @@ +//@ needs-asm-support +#![deny(unsafe_code)] + +use std::arch::global_asm; + +#[allow(unsafe_code)] +mod allowed_unsafe { + std::arch::global_asm!(""); +} + +macro_rules! unsafe_in_macro { + () => { + global_asm!(""); //~ ERROR: usage of `core::arch::global_asm` + }; +} + +global_asm!(""); //~ ERROR: usage of `core::arch::global_asm` +unsafe_in_macro!(); + +fn main() {} diff --git a/tests/ui/lint/unsafe_code/lint-global-asm-as-unsafe.stderr b/tests/ui/lint/unsafe_code/lint-global-asm-as-unsafe.stderr new file mode 100644 index 00000000000..deb67a174f1 --- /dev/null +++ b/tests/ui/lint/unsafe_code/lint-global-asm-as-unsafe.stderr @@ -0,0 +1,27 @@ +error: usage of `core::arch::global_asm` + --> $DIR/lint-global-asm-as-unsafe.rs:17:1 + | +LL | global_asm!(""); + | ^^^^^^^^^^^^^^^ + | + = note: using this macro is unsafe even though it does not need an `unsafe` block +note: the lint level is defined here + --> $DIR/lint-global-asm-as-unsafe.rs:2:9 + | +LL | #![deny(unsafe_code)] + | ^^^^^^^^^^^ + +error: usage of `core::arch::global_asm` + --> $DIR/lint-global-asm-as-unsafe.rs:13:9 + | +LL | global_asm!(""); + | ^^^^^^^^^^^^^^^ +... +LL | unsafe_in_macro!(); + | ------------------ in this macro invocation + | + = note: using this macro is unsafe even though it does not need an `unsafe` block + = note: this error originates in the macro `unsafe_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 84baf2f6f8eda07661ab956659839af9b61cc46b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 19 Feb 2024 22:00:36 +0000 Subject: return ty::Error when equating ty::Error This helps iron out a difference between Sub and Equate --- compiler/rustc_infer/src/infer/relate/equate.rs | 5 ++ tests/ui/generic-associated-types/issue-79636-1.rs | 1 - .../generic-associated-types/issue-79636-1.stderr | 17 +---- tests/ui/impl-trait/where-allowed.rs | 1 - tests/ui/impl-trait/where-allowed.stderr | 86 ++++++++++------------ .../impl-trait-in-type-alias-with-bad-substs.rs | 1 - ...impl-trait-in-type-alias-with-bad-substs.stderr | 10 +-- tests/ui/wf/issue-110157.rs | 3 +- tests/ui/wf/issue-110157.stderr | 25 +------ 9 files changed, 54 insertions(+), 95 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_infer/src/infer/relate/equate.rs b/compiler/rustc_infer/src/infer/relate/equate.rs index cb62f258373..61d1302d816 100644 --- a/compiler/rustc_infer/src/infer/relate/equate.rs +++ b/compiler/rustc_infer/src/infer/relate/equate.rs @@ -89,6 +89,11 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { self.fields.instantiate(a, ty::Invariant, b_id, self.a_is_expected)?; } + (&ty::Error(e), _) | (_, &ty::Error(e)) => { + infcx.set_tainted_by_errors(e); + return Ok(Ty::new_error(self.tcx(), e)); + } + ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), diff --git a/tests/ui/generic-associated-types/issue-79636-1.rs b/tests/ui/generic-associated-types/issue-79636-1.rs index a05311d59c1..3357afb9d4d 100644 --- a/tests/ui/generic-associated-types/issue-79636-1.rs +++ b/tests/ui/generic-associated-types/issue-79636-1.rs @@ -15,7 +15,6 @@ where //~^ ERROR: missing generics for associated type `Monad::Wrapped` { outer.bind(|inner| inner) - //~^ ERROR type annotations needed } fn main() { diff --git a/tests/ui/generic-associated-types/issue-79636-1.stderr b/tests/ui/generic-associated-types/issue-79636-1.stderr index 743d8b7d462..c31064dec62 100644 --- a/tests/ui/generic-associated-types/issue-79636-1.stderr +++ b/tests/ui/generic-associated-types/issue-79636-1.stderr @@ -30,19 +30,8 @@ help: function arguments must have a statically known size, borrowed types alway LL | fn bind(&self, f: F) -> Self::Wrapped { | + -error[E0282]: type annotations needed - --> $DIR/issue-79636-1.rs:17:17 - | -LL | outer.bind(|inner| inner) - | ^^^^^ - | -help: consider giving this closure parameter an explicit type - | -LL | outer.bind(|inner: /* Type */| inner) - | ++++++++++++ - error[E0277]: the trait bound `Option>: Monad` is not satisfied - --> $DIR/issue-79636-1.rs:22:21 + --> $DIR/issue-79636-1.rs:21:21 | LL | assert_eq!(join(Some(Some(true))), Some(true)); | ---- ^^^^^^^^^^^^^^^^ the trait `Monad` is not implemented for `Option>` @@ -63,7 +52,7 @@ LL | where LL | MOuter: Monad, | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `join` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0107, E0277, E0282. +Some errors have detailed explanations: E0107, E0277. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/impl-trait/where-allowed.rs b/tests/ui/impl-trait/where-allowed.rs index 505e2d6c171..72ce617693e 100644 --- a/tests/ui/impl-trait/where-allowed.rs +++ b/tests/ui/impl-trait/where-allowed.rs @@ -59,7 +59,6 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` is not allowed in the parameters of `Fn` trait bounds //~| ERROR nested `impl Trait` is not allowed -//~| ERROR: type annotations needed // Allowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index c22312cce19..f203f4cabc8 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -17,7 +17,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | outer `impl Trait` error[E0658]: `impl Trait` in associated types is unstable - --> $DIR/where-allowed.rs:123:16 + --> $DIR/where-allowed.rs:122:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | type Out = impl Debug; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:160:23 + --> $DIR/where-allowed.rs:159:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | type InTypeAlias = impl Debug; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:163:39 + --> $DIR/where-allowed.rs:162:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds - --> $DIR/where-allowed.rs:69:38 + --> $DIR/where-allowed.rs:68:38 | LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } | ^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds - --> $DIR/where-allowed.rs:73:40 + --> $DIR/where-allowed.rs:72:40 | LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } | ^^^^^^^^^^ @@ -143,7 +143,7 @@ LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:87:32 + --> $DIR/where-allowed.rs:86:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ @@ -151,7 +151,7 @@ LL | struct InBraceStructField { x: impl Debug } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:91:41 + --> $DIR/where-allowed.rs:90:41 | LL | struct InAdtInBraceStructField { x: Vec } | ^^^^^^^^^^ @@ -159,7 +159,7 @@ LL | struct InAdtInBraceStructField { x: Vec } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:95:27 + --> $DIR/where-allowed.rs:94:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | struct InTupleStructField(impl Debug); = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:100:25 + --> $DIR/where-allowed.rs:99:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ @@ -175,7 +175,7 @@ LL | InBraceVariant { x: impl Debug }, = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in field types - --> $DIR/where-allowed.rs:102:20 + --> $DIR/where-allowed.rs:101:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ @@ -183,7 +183,7 @@ LL | InTupleVariant(impl Debug), = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `extern fn` parameters - --> $DIR/where-allowed.rs:144:33 + --> $DIR/where-allowed.rs:143:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ @@ -191,7 +191,7 @@ LL | fn in_foreign_parameters(_: impl Debug); = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `extern fn` return types - --> $DIR/where-allowed.rs:147:31 + --> $DIR/where-allowed.rs:146:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ @@ -199,7 +199,7 @@ LL | fn in_foreign_return() -> impl Debug; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in `fn` pointer return types - --> $DIR/where-allowed.rs:163:39 + --> $DIR/where-allowed.rs:162:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -207,7 +207,7 @@ LL | type InReturnInTypeAlias = fn() -> impl Debug; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in traits - --> $DIR/where-allowed.rs:168:16 + --> $DIR/where-allowed.rs:167:16 | LL | impl PartialEq for () { | ^^^^^^^^^^ @@ -215,7 +215,7 @@ LL | impl PartialEq for () { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in impl headers - --> $DIR/where-allowed.rs:173:24 + --> $DIR/where-allowed.rs:172:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ @@ -223,7 +223,7 @@ LL | impl PartialEq<()> for impl Debug { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in impl headers - --> $DIR/where-allowed.rs:178:6 + --> $DIR/where-allowed.rs:177:6 | LL | impl impl Debug { | ^^^^^^^^^^ @@ -231,7 +231,7 @@ LL | impl impl Debug { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in impl headers - --> $DIR/where-allowed.rs:184:24 + --> $DIR/where-allowed.rs:183:24 | LL | impl InInherentImplAdt { | ^^^^^^^^^^ @@ -239,7 +239,7 @@ LL | impl InInherentImplAdt { = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in bounds - --> $DIR/where-allowed.rs:190:11 + --> $DIR/where-allowed.rs:189:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ @@ -247,7 +247,7 @@ LL | where impl Debug: Debug = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in bounds - --> $DIR/where-allowed.rs:197:15 + --> $DIR/where-allowed.rs:196:15 | LL | where Vec: Debug | ^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | where Vec: Debug = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in bounds - --> $DIR/where-allowed.rs:204:24 + --> $DIR/where-allowed.rs:203:24 | LL | where T: PartialEq | ^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | where T: PartialEq = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the parameters of `Fn` trait bounds - --> $DIR/where-allowed.rs:211:17 + --> $DIR/where-allowed.rs:210:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | where T: Fn(impl Debug) = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds - --> $DIR/where-allowed.rs:218:22 + --> $DIR/where-allowed.rs:217:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | where T: Fn() -> impl Debug = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:224:40 + --> $DIR/where-allowed.rs:223:40 | LL | struct InStructGenericParamDefault(T); | ^^^^^^^^^^ @@ -287,7 +287,7 @@ LL | struct InStructGenericParamDefault(T); = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:228:36 + --> $DIR/where-allowed.rs:227:36 | LL | enum InEnumGenericParamDefault { Variant(T) } | ^^^^^^^^^^ @@ -295,7 +295,7 @@ LL | enum InEnumGenericParamDefault { Variant(T) } = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:232:38 + --> $DIR/where-allowed.rs:231:38 | LL | trait InTraitGenericParamDefault {} | ^^^^^^^^^^ @@ -303,7 +303,7 @@ LL | trait InTraitGenericParamDefault {} = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:236:41 + --> $DIR/where-allowed.rs:235:41 | LL | type InTypeAliasGenericParamDefault = T; | ^^^^^^^^^^ @@ -311,7 +311,7 @@ LL | type InTypeAliasGenericParamDefault = T; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:240:11 + --> $DIR/where-allowed.rs:239:11 | LL | impl T {} | ^^^^^^^^^^ @@ -319,7 +319,7 @@ LL | impl T {} = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in generic parameter defaults - --> $DIR/where-allowed.rs:247:40 + --> $DIR/where-allowed.rs:246:40 | LL | fn in_method_generic_param_default(_: T) {} | ^^^^^^^^^^ @@ -327,7 +327,7 @@ LL | fn in_method_generic_param_default(_: T) {} = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/where-allowed.rs:253:29 + --> $DIR/where-allowed.rs:252:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ @@ -335,7 +335,7 @@ LL | let _in_local_variable: impl Fn() = || {}; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in closure return types - --> $DIR/where-allowed.rs:255:46 + --> $DIR/where-allowed.rs:254:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ @@ -343,7 +343,7 @@ LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:240:7 + --> $DIR/where-allowed.rs:239:7 | LL | impl T {} | ^^^^^^^^^^^^^^ @@ -353,7 +353,7 @@ LL | impl T {} = note: `#[deny(invalid_type_param_default)]` on by default error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:247:36 + --> $DIR/where-allowed.rs:246:36 | LL | fn in_method_generic_param_default(_: T) {} | ^^^^^^^^^^^^^^ @@ -362,7 +362,7 @@ LL | fn in_method_generic_param_default(_: T) {} = note: for more information, see issue #36887 error[E0118]: no nominal type found for inherent implementation - --> $DIR/where-allowed.rs:240:1 + --> $DIR/where-allowed.rs:239:1 | LL | impl T {} | ^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type @@ -377,14 +377,8 @@ LL | fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic! | = note: cannot satisfy `_: Debug` -error[E0282]: type annotations needed - --> $DIR/where-allowed.rs:59:49 - | -LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } - | ^^^^^^^^^^^^^^^^^^^ cannot infer type - error[E0283]: type annotations needed - --> $DIR/where-allowed.rs:65:46 + --> $DIR/where-allowed.rs:64:46 | LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type @@ -396,7 +390,7 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; error[E0599]: no function or associated item named `into_vec` found for slice `[_]` in the current scope - --> $DIR/where-allowed.rs:82:5 + --> $DIR/where-allowed.rs:81:5 | LL | vec![vec![0; 10], vec![12; 7], vec![8; 3]] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item not found in `[_]` @@ -404,7 +398,7 @@ LL | vec![vec![0; 10], vec![12; 7], vec![8; 3]] = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0053]: method `in_trait_impl_return` has an incompatible type for trait - --> $DIR/where-allowed.rs:130:34 + --> $DIR/where-allowed.rs:129:34 | LL | type Out = impl Debug; | ---------- the expected opaque type @@ -416,7 +410,7 @@ LL | fn in_trait_impl_return() -> impl Debug { () } | help: change the output type to match the trait: `<() as DummyTrait>::Out` | note: type in trait - --> $DIR/where-allowed.rs:120:34 + --> $DIR/where-allowed.rs:119:34 | LL | fn in_trait_impl_return() -> Self::Out; | ^^^^^^^^^ @@ -425,14 +419,14 @@ LL | fn in_trait_impl_return() -> Self::Out; = note: distinct uses of `impl Trait` result in different opaque types error: unconstrained opaque type - --> $DIR/where-allowed.rs:123:16 + --> $DIR/where-allowed.rs:122:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ | = note: `Out` must be used in combination with a concrete type within the same impl -error: aborting due to 51 previous errors +error: aborting due to 50 previous errors -Some errors have detailed explanations: E0053, E0118, E0282, E0283, E0562, E0599, E0658, E0666. +Some errors have detailed explanations: E0053, E0118, E0283, E0562, E0599, E0658, E0666. For more information about an error, try `rustc --explain E0053`. diff --git a/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs index a3f65146f75..71416eb531a 100644 --- a/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs +++ b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.rs @@ -18,7 +18,6 @@ impl Foo for () { type Baz = impl Sized; //~^ ERROR type `Baz` has 1 type parameter but its trait declaration has 0 type parameters - //~| ERROR unconstrained opaque type fn test<'a>() -> Self::Bar<'a> { &() diff --git a/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr index 13f5d8b8ea6..e5a21ff8b4e 100644 --- a/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr +++ b/tests/ui/type-alias-impl-trait/impl-trait-in-type-alias-with-bad-substs.stderr @@ -7,14 +7,6 @@ LL | type Baz<'a>; LL | type Baz = impl Sized; | ^ found 1 type parameter -error: unconstrained opaque type - --> $DIR/impl-trait-in-type-alias-with-bad-substs.rs:19:19 - | -LL | type Baz = impl Sized; - | ^^^^^^^^^^ - | - = note: `Baz` must be used in combination with a concrete type within the same impl - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0049`. diff --git a/tests/ui/wf/issue-110157.rs b/tests/ui/wf/issue-110157.rs index 07e2c5d58c3..1a3d13e93b0 100644 --- a/tests/ui/wf/issue-110157.rs +++ b/tests/ui/wf/issue-110157.rs @@ -1,8 +1,7 @@ struct NeedsDropTypes<'tcx, F>(std::marker::PhantomData<&'tcx F>); impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> -//~^ ERROR type annotations needed -//~| ERROR not all trait items implemented +//~^ ERROR not all trait items implemented where F: Fn(&Missing) -> Result, //~^ ERROR cannot find type `Missing` in this scope diff --git a/tests/ui/wf/issue-110157.stderr b/tests/ui/wf/issue-110157.stderr index 16bd34a6d8e..e750ea47d51 100644 --- a/tests/ui/wf/issue-110157.stderr +++ b/tests/ui/wf/issue-110157.stderr @@ -1,37 +1,20 @@ error[E0412]: cannot find type `Missing` in this scope - --> $DIR/issue-110157.rs:7:12 + --> $DIR/issue-110157.rs:6:12 | LL | F: Fn(&Missing) -> Result, | ^^^^^^^ not found in this scope error[E0412]: cannot find type `Missing` in this scope - --> $DIR/issue-110157.rs:9:24 + --> $DIR/issue-110157.rs:8:24 | LL | I: Iterator, | ^^^^^^^ not found in this scope -error[E0283]: type annotations needed - --> $DIR/issue-110157.rs:3:31 - | -LL | impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `I` - | - = note: cannot satisfy `_: Iterator` -note: required for `NeedsDropTypes<'tcx, F>` to implement `Iterator` - --> $DIR/issue-110157.rs:3:18 - | -LL | impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> - | ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | I: Iterator, - | ------------------------ unsatisfied trait bound introduced here - error[E0046]: not all trait items implemented, missing: `Item`, `next` --> $DIR/issue-110157.rs:3:1 | LL | / impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> LL | | -LL | | LL | | where LL | | F: Fn(&Missing) -> Result, LL | | @@ -41,7 +24,7 @@ LL | | I: Iterator, = help: implement the missing item: `type Item = /* Type */;` = help: implement the missing item: `fn next(&mut self) -> Option<::Item> { todo!() }` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0046, E0283, E0412. +Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`. -- cgit 1.4.1-3-g733a5 From 42c4df01a8b498c56bf762c2307fb4a3c55293fe Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Tue, 20 Feb 2024 07:41:48 +0530 Subject: Rename `ConstPropLint` to `KnownPanicsLint` It is a clearer name because it communicates what the lint does instead of the underlying mechanism it uses (const propagation). --- .../rustc_mir_transform/src/const_prop_lint.rs | 973 -------------------- .../rustc_mir_transform/src/known_panics_lint.rs | 975 +++++++++++++++++++++ compiler/rustc_mir_transform/src/lib.rs | 4 +- 3 files changed, 977 insertions(+), 975 deletions(-) delete mode 100644 compiler/rustc_mir_transform/src/const_prop_lint.rs create mode 100644 compiler/rustc_mir_transform/src/known_panics_lint.rs (limited to 'compiler') diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs deleted file mode 100644 index 6f2ef8f9a4f..00000000000 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ /dev/null @@ -1,973 +0,0 @@ -//! Propagates constants for early reporting of statically known -//! assertion failures - -use std::fmt::Debug; - -use rustc_const_eval::interpret::{ - format_interp_error, ImmTy, InterpCx, InterpResult, Projectable, Scalar, -}; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def::DefKind; -use rustc_hir::HirId; -use rustc_index::{bit_set::BitSet, Idx, IndexVec}; -use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::*; -use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; -use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::Span; -use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx}; - -use crate::dataflow_const_prop::DummyMachine; -use crate::errors::{AssertLint, AssertLintKind}; -use crate::MirLint; - -pub struct ConstPropLint; - -impl<'tcx> MirLint<'tcx> for ConstPropLint { - fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - if body.tainted_by_errors.is_some() { - return; - } - - let def_id = body.source.def_id().expect_local(); - let def_kind = tcx.def_kind(def_id); - let is_fn_like = def_kind.is_fn_like(); - let is_assoc_const = def_kind == DefKind::AssocConst; - - // Only run const prop on functions, methods, closures and associated constants - if !is_fn_like && !is_assoc_const { - // skip anon_const/statics/consts because they'll be evaluated by miri anyway - trace!("ConstPropLint skipped for {:?}", def_id); - return; - } - - // FIXME(welseywiser) const prop doesn't work on coroutines because of query cycles - // computing their layout. - if tcx.is_coroutine(def_id.to_def_id()) { - trace!("ConstPropLint skipped for coroutine {:?}", def_id); - return; - } - - trace!("ConstPropLint starting for {:?}", def_id); - - // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold - // constants, instead of just checking for const-folding succeeding. - // That would require a uniform one-def no-mutation analysis - // and RPO (or recursing when needing the value of a local). - let mut linter = ConstPropagator::new(body, tcx); - linter.visit_body(body); - - trace!("ConstPropLint done for {:?}", def_id); - } -} - -/// Finds optimization opportunities on the MIR. -struct ConstPropagator<'mir, 'tcx> { - ecx: InterpCx<'mir, 'tcx, DummyMachine>, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - worklist: Vec, - visited_blocks: BitSet, - locals: IndexVec>, - body: &'mir Body<'tcx>, - written_only_inside_own_block_locals: FxHashSet, - can_const_prop: IndexVec, -} - -#[derive(Debug, Clone)] -enum Value<'tcx> { - Immediate(ImmTy<'tcx>), - Aggregate { variant: VariantIdx, fields: IndexVec> }, - Uninit, -} - -impl<'tcx> From> for Value<'tcx> { - fn from(v: ImmTy<'tcx>) -> Self { - Self::Immediate(v) - } -} - -impl<'tcx> Value<'tcx> { - fn project( - &self, - proj: &[PlaceElem<'tcx>], - prop: &ConstPropagator<'_, 'tcx>, - ) -> Option<&Value<'tcx>> { - let mut this = self; - for proj in proj { - this = match (*proj, this) { - (PlaceElem::Field(idx, _), Value::Aggregate { fields, .. }) => { - fields.get(idx).unwrap_or(&Value::Uninit) - } - (PlaceElem::Index(idx), Value::Aggregate { fields, .. }) => { - let idx = prop.get_const(idx.into())?.immediate()?; - let idx = prop.ecx.read_target_usize(idx).ok()?; - fields.get(FieldIdx::from_u32(idx.try_into().ok()?)).unwrap_or(&Value::Uninit) - } - ( - PlaceElem::ConstantIndex { offset, min_length: _, from_end: false }, - Value::Aggregate { fields, .. }, - ) => fields - .get(FieldIdx::from_u32(offset.try_into().ok()?)) - .unwrap_or(&Value::Uninit), - _ => return None, - }; - } - Some(this) - } - - fn project_mut(&mut self, proj: &[PlaceElem<'_>]) -> Option<&mut Value<'tcx>> { - let mut this = self; - for proj in proj { - this = match (proj, this) { - (PlaceElem::Field(idx, _), Value::Aggregate { fields, .. }) => { - fields.ensure_contains_elem(*idx, || Value::Uninit) - } - (PlaceElem::Field(..), val @ Value::Uninit) => { - *val = Value::Aggregate { - variant: VariantIdx::new(0), - fields: Default::default(), - }; - val.project_mut(&[*proj])? - } - _ => return None, - }; - } - Some(this) - } - - fn immediate(&self) -> Option<&ImmTy<'tcx>> { - match self { - Value::Immediate(op) => Some(op), - _ => None, - } - } -} - -impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> { - type LayoutOfResult = Result, LayoutError<'tcx>>; - - #[inline] - fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> { - err - } -} - -impl HasDataLayout for ConstPropagator<'_, '_> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - &self.tcx.data_layout - } -} - -impl<'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'_, 'tcx> { - #[inline] - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } -} - -impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> { - #[inline] - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } -} - -impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { - fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> { - let def_id = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(def_id); - - let can_const_prop = CanConstProp::check(tcx, param_env, body); - let ecx = InterpCx::new(tcx, tcx.def_span(def_id), param_env, DummyMachine); - - ConstPropagator { - ecx, - tcx, - param_env, - worklist: vec![START_BLOCK], - visited_blocks: BitSet::new_empty(body.basic_blocks.len()), - locals: IndexVec::from_elem_n(Value::Uninit, body.local_decls.len()), - body, - can_const_prop, - written_only_inside_own_block_locals: Default::default(), - } - } - - fn local_decls(&self) -> &'mir LocalDecls<'tcx> { - &self.body.local_decls - } - - fn get_const(&self, place: Place<'tcx>) -> Option<&Value<'tcx>> { - self.locals[place.local].project(&place.projection, self) - } - - /// Remove `local` from the pool of `Locals`. Allows writing to them, - /// but not reading from them anymore. - fn remove_const(&mut self, local: Local) { - self.locals[local] = Value::Uninit; - self.written_only_inside_own_block_locals.remove(&local); - } - - fn access_mut(&mut self, place: &Place<'_>) -> Option<&mut Value<'tcx>> { - match self.can_const_prop[place.local] { - ConstPropMode::NoPropagation => return None, - ConstPropMode::OnlyInsideOwnBlock => { - self.written_only_inside_own_block_locals.insert(place.local); - } - ConstPropMode::FullConstProp => {} - } - self.locals[place.local].project_mut(place.projection) - } - - fn lint_root(&self, source_info: SourceInfo) -> Option { - source_info.scope.lint_root(&self.body.source_scopes) - } - - fn use_ecx(&mut self, f: F) -> Option - where - F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, - { - match f(self) { - Ok(val) => Some(val), - Err(error) => { - trace!("InterpCx operation failed: {:?}", error); - // Some errors shouldn't come up because creating them causes - // an allocation, which we should avoid. When that happens, - // dedicated error variants should be introduced instead. - assert!( - !error.kind().formatted_string(), - "const-prop encountered formatting error: {}", - format_interp_error(self.ecx.tcx.dcx(), error), - ); - None - } - } - } - - /// Returns the value, if any, of evaluating `c`. - fn eval_constant(&mut self, c: &ConstOperand<'tcx>) -> Option> { - // FIXME we need to revisit this for #67176 - if c.has_param() { - return None; - } - - // Normalization needed b/c const prop lint runs in - // `mir_drops_elaborated_and_const_checked`, which happens before - // optimized MIR. Only after optimizing the MIR can we guarantee - // that the `RevealAll` pass has happened and that the body's consts - // are normalized, so any call to resolve before that needs to be - // manually normalized. - let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?; - - self.use_ecx(|this| this.ecx.eval_mir_constant(&val, Some(c.span), None))? - .as_mplace_or_imm() - .right() - } - - /// Returns the value, if any, of evaluating `place`. - #[instrument(level = "trace", skip(self), ret)] - fn eval_place(&mut self, place: Place<'tcx>) -> Option> { - match self.get_const(place)? { - Value::Immediate(imm) => Some(imm.clone()), - Value::Aggregate { .. } => None, - Value::Uninit => None, - } - } - - /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant` - /// or `eval_place`, depending on the variant of `Operand` used. - fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option> { - match *op { - Operand::Constant(ref c) => self.eval_constant(c), - Operand::Move(place) | Operand::Copy(place) => self.eval_place(place), - } - } - - fn report_assert_as_lint( - &self, - location: Location, - lint_kind: AssertLintKind, - assert_kind: AssertKind, - ) { - let source_info = self.body.source_info(location); - if let Some(lint_root) = self.lint_root(*source_info) { - let span = source_info.span; - self.tcx.emit_node_span_lint( - lint_kind.lint(), - lint_root, - span, - AssertLint { span, assert_kind, lint_kind }, - ); - } - } - - fn check_unary_op(&mut self, op: UnOp, arg: &Operand<'tcx>, location: Location) -> Option<()> { - let arg = self.eval_operand(arg)?; - if let (val, true) = self.use_ecx(|this| { - let val = this.ecx.read_immediate(&arg)?; - let (_res, overflow) = this.ecx.overflowing_unary_op(op, &val)?; - Ok((val, overflow)) - })? { - // `AssertKind` only has an `OverflowNeg` variant, so make sure that is - // appropriate to use. - assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow"); - self.report_assert_as_lint( - location, - AssertLintKind::ArithmeticOverflow, - AssertKind::OverflowNeg(val.to_const_int()), - ); - return None; - } - - Some(()) - } - - fn check_binary_op( - &mut self, - op: BinOp, - left: &Operand<'tcx>, - right: &Operand<'tcx>, - location: Location, - ) -> Option<()> { - let r = - self.eval_operand(right).and_then(|r| self.use_ecx(|this| this.ecx.read_immediate(&r))); - let l = - self.eval_operand(left).and_then(|l| self.use_ecx(|this| this.ecx.read_immediate(&l))); - // Check for exceeding shifts *even if* we cannot evaluate the LHS. - if matches!(op, BinOp::Shr | BinOp::Shl) { - let r = r.clone()?; - // We need the type of the LHS. We cannot use `place_layout` as that is the type - // of the result, which for checked binops is not the same! - let left_ty = left.ty(self.local_decls(), self.tcx); - let left_size = self.ecx.layout_of(left_ty).ok()?.size; - let right_size = r.layout.size; - let r_bits = r.to_scalar().to_bits(right_size).ok(); - if r_bits.is_some_and(|b| b >= left_size.bits() as u128) { - debug!("check_binary_op: reporting assert for {:?}", location); - let panic = AssertKind::Overflow( - op, - match l { - Some(l) => l.to_const_int(), - // Invent a dummy value, the diagnostic ignores it anyway - None => ConstInt::new( - ScalarInt::try_from_uint(1_u8, left_size).unwrap(), - left_ty.is_signed(), - left_ty.is_ptr_sized_integral(), - ), - }, - r.to_const_int(), - ); - self.report_assert_as_lint(location, AssertLintKind::ArithmeticOverflow, panic); - return None; - } - } - - if let (Some(l), Some(r)) = (l, r) { - // The remaining operators are handled through `overflowing_binary_op`. - if self.use_ecx(|this| { - let (_res, overflow) = this.ecx.overflowing_binary_op(op, &l, &r)?; - Ok(overflow) - })? { - self.report_assert_as_lint( - location, - AssertLintKind::ArithmeticOverflow, - AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), - ); - return None; - } - } - Some(()) - } - - fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> { - // Perform any special handling for specific Rvalue types. - // Generally, checks here fall into one of two categories: - // 1. Additional checking to provide useful lints to the user - // - In this case, we will do some validation and then fall through to the - // end of the function which evals the assignment. - // 2. Working around bugs in other parts of the compiler - // - In this case, we'll return `None` from this function to stop evaluation. - match rvalue { - // Additional checking: give lints to the user if an overflow would occur. - // We do this here and not in the `Assert` terminator as that terminator is - // only sometimes emitted (overflow checks can be disabled), but we want to always - // lint. - Rvalue::UnaryOp(op, arg) => { - trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); - self.check_unary_op(*op, arg, location)?; - } - Rvalue::BinaryOp(op, box (left, right)) => { - trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); - self.check_binary_op(*op, left, right, location)?; - } - Rvalue::CheckedBinaryOp(op, box (left, right)) => { - trace!( - "checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})", - op, - left, - right - ); - self.check_binary_op(*op, left, right, location)?; - } - - // Do not try creating references (#67862) - Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => { - trace!("skipping AddressOf | Ref for {:?}", place); - - // This may be creating mutable references or immutable references to cells. - // If that happens, the pointed to value could be mutated via that reference. - // Since we aren't tracking references, the const propagator loses track of what - // value the local has right now. - // Thus, all locals that have their reference taken - // must not take part in propagation. - self.remove_const(place.local); - - return None; - } - Rvalue::ThreadLocalRef(def_id) => { - trace!("skipping ThreadLocalRef({:?})", def_id); - - return None; - } - - // There's no other checking to do at this time. - Rvalue::Aggregate(..) - | Rvalue::Use(..) - | Rvalue::CopyForDeref(..) - | Rvalue::Repeat(..) - | Rvalue::Len(..) - | Rvalue::Cast(..) - | Rvalue::ShallowInitBox(..) - | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(..) => {} - } - - // FIXME we need to revisit this for #67176 - if rvalue.has_param() { - return None; - } - if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.param_env) { - // the interpreter doesn't support unsized locals (only unsized arguments), - // but rustc does (in a kinda broken way), so we have to skip them here - return None; - } - - Some(()) - } - - fn check_assertion( - &mut self, - expected: bool, - msg: &AssertKind>, - cond: &Operand<'tcx>, - location: Location, - ) -> Option { - let value = &self.eval_operand(cond)?; - trace!("assertion on {:?} should be {:?}", value, expected); - - let expected = Scalar::from_bool(expected); - let value_const = self.use_ecx(|this| this.ecx.read_scalar(value))?; - - if expected != value_const { - // Poison all places this operand references so that further code - // doesn't use the invalid value - if let Some(place) = cond.place() { - self.remove_const(place.local); - } - - enum DbgVal { - Val(T), - Underscore, - } - impl std::fmt::Debug for DbgVal { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Val(val) => val.fmt(fmt), - Self::Underscore => fmt.write_str("_"), - } - } - } - let mut eval_to_int = |op| { - // This can be `None` if the lhs wasn't const propagated and we just - // triggered the assert on the value of the rhs. - self.eval_operand(op) - .and_then(|op| self.ecx.read_immediate(&op).ok()) - .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int())) - }; - let msg = match msg { - AssertKind::DivisionByZero(op) => AssertKind::DivisionByZero(eval_to_int(op)), - AssertKind::RemainderByZero(op) => AssertKind::RemainderByZero(eval_to_int(op)), - AssertKind::Overflow(bin_op @ (BinOp::Div | BinOp::Rem), op1, op2) => { - // Division overflow is *UB* in the MIR, and different than the - // other overflow checks. - AssertKind::Overflow(*bin_op, eval_to_int(op1), eval_to_int(op2)) - } - AssertKind::BoundsCheck { ref len, ref index } => { - let len = eval_to_int(len); - let index = eval_to_int(index); - AssertKind::BoundsCheck { len, index } - } - // Remaining overflow errors are already covered by checks on the binary operators. - AssertKind::Overflow(..) | AssertKind::OverflowNeg(_) => return None, - // Need proper const propagator for these. - _ => return None, - }; - self.report_assert_as_lint(location, AssertLintKind::UnconditionalPanic, msg); - } - - None - } - - fn ensure_not_propagated(&self, local: Local) { - if cfg!(debug_assertions) { - let val = self.get_const(local.into()); - assert!( - matches!(val, Some(Value::Uninit)) - || self - .layout_of(self.local_decls()[local].ty) - .map_or(true, |layout| layout.is_zst()), - "failed to remove values for `{local:?}`, value={val:?}", - ) - } - } - - #[instrument(level = "trace", skip(self), ret)] - fn eval_rvalue(&mut self, rvalue: &Rvalue<'tcx>, dest: &Place<'tcx>) -> Option<()> { - if !dest.projection.is_empty() { - return None; - } - use rustc_middle::mir::Rvalue::*; - let layout = self.ecx.layout_of(dest.ty(self.body, self.tcx).ty).ok()?; - trace!(?layout); - - let val: Value<'_> = match *rvalue { - ThreadLocalRef(_) => return None, - - Use(ref operand) => self.eval_operand(operand)?.into(), - - CopyForDeref(place) => self.eval_place(place)?.into(), - - BinaryOp(bin_op, box (ref left, ref right)) => { - let left = self.eval_operand(left)?; - let left = self.use_ecx(|this| this.ecx.read_immediate(&left))?; - - let right = self.eval_operand(right)?; - let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?; - - let val = - self.use_ecx(|this| this.ecx.wrapping_binary_op(bin_op, &left, &right))?; - val.into() - } - - CheckedBinaryOp(bin_op, box (ref left, ref right)) => { - let left = self.eval_operand(left)?; - let left = self.use_ecx(|this| this.ecx.read_immediate(&left))?; - - let right = self.eval_operand(right)?; - let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?; - - let (val, overflowed) = - self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?; - let overflowed = ImmTy::from_bool(overflowed, self.tcx); - Value::Aggregate { - variant: VariantIdx::new(0), - fields: [Value::from(val), overflowed.into()].into_iter().collect(), - } - } - - UnaryOp(un_op, ref operand) => { - let operand = self.eval_operand(operand)?; - let val = self.use_ecx(|this| this.ecx.read_immediate(&operand))?; - - let val = self.use_ecx(|this| this.ecx.wrapping_unary_op(un_op, &val))?; - val.into() - } - - Aggregate(ref kind, ref fields) => Value::Aggregate { - fields: fields - .iter() - .map(|field| self.eval_operand(field).map_or(Value::Uninit, Value::Immediate)) - .collect(), - variant: match **kind { - AggregateKind::Adt(_, variant, _, _, _) => variant, - AggregateKind::Array(_) - | AggregateKind::Tuple - | AggregateKind::Closure(_, _) - | AggregateKind::Coroutine(_, _) - | AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0), - }, - }, - - Repeat(ref op, n) => { - trace!(?op, ?n); - return None; - } - - Len(place) => { - let len = match self.get_const(place)? { - Value::Immediate(src) => src.len(&self.ecx).ok()?, - Value::Aggregate { fields, .. } => fields.len() as u64, - Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() { - ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?, - _ => return None, - }, - }; - ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into() - } - - Ref(..) | AddressOf(..) => return None, - - NullaryOp(ref null_op, ty) => { - let op_layout = self.use_ecx(|this| this.ecx.layout_of(ty))?; - let val = match null_op { - NullOp::SizeOf => op_layout.size.bytes(), - NullOp::AlignOf => op_layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - op_layout.offset_of_subfield(self, fields.iter()).bytes() - } - NullOp::DebugAssertions => return None, - }; - ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() - } - - ShallowInitBox(..) => return None, - - Cast(ref kind, ref value, to) => match kind { - CastKind::IntToInt | CastKind::IntToFloat => { - let value = self.eval_operand(value)?; - let value = self.ecx.read_immediate(&value).ok()?; - let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.int_to_int_or_float(&value, to).ok()?; - res.into() - } - CastKind::FloatToFloat | CastKind::FloatToInt => { - let value = self.eval_operand(value)?; - let value = self.ecx.read_immediate(&value).ok()?; - let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.float_to_float_or_int(&value, to).ok()?; - res.into() - } - CastKind::Transmute => { - let value = self.eval_operand(value)?; - let to = self.ecx.layout_of(to).ok()?; - // `offset` for immediates only supports scalar/scalar-pair ABIs, - // so bail out if the target is not one. - match (value.layout.abi, to.abi) { - (Abi::Scalar(..), Abi::Scalar(..)) => {} - (Abi::ScalarPair(..), Abi::ScalarPair(..)) => {} - _ => return None, - } - - value.offset(Size::ZERO, to, &self.ecx).ok()?.into() - } - _ => return None, - }, - - Discriminant(place) => { - let variant = match self.get_const(place)? { - Value::Immediate(op) => { - let op = op.clone(); - self.use_ecx(|this| this.ecx.read_discriminant(&op))? - } - Value::Aggregate { variant, .. } => *variant, - Value::Uninit => return None, - }; - let imm = self.use_ecx(|this| { - this.ecx.discriminant_for_variant( - place.ty(this.local_decls(), this.tcx).ty, - variant, - ) - })?; - imm.into() - } - }; - trace!(?val); - - *self.access_mut(dest)? = val; - - Some(()) - } -} - -impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { - fn visit_body(&mut self, body: &Body<'tcx>) { - while let Some(bb) = self.worklist.pop() { - if !self.visited_blocks.insert(bb) { - continue; - } - - let data = &body.basic_blocks[bb]; - self.visit_basic_block_data(bb, data); - } - } - - fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - self.super_operand(operand, location); - } - - fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { - trace!("visit_constant: {:?}", constant); - self.super_constant(constant, location); - self.eval_constant(constant); - } - - fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { - self.super_assign(place, rvalue, location); - - let Some(()) = self.check_rvalue(rvalue, location) else { return }; - - match self.can_const_prop[place.local] { - // Do nothing if the place is indirect. - _ if place.is_indirect() => {} - ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local), - ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => { - if self.eval_rvalue(rvalue, place).is_none() { - // Const prop failed, so erase the destination, ensuring that whatever happens - // from here on, does not know about the previous value. - // This is important in case we have - // ```rust - // let mut x = 42; - // x = SOME_MUTABLE_STATIC; - // // x must now be uninit - // ``` - // FIXME: we overzealously erase the entire local, because that's easier to - // implement. - trace!( - "propagation into {:?} failed. - Nuking the entire site from orbit, it's the only way to be sure", - place, - ); - self.remove_const(place.local); - } - } - } - } - - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - trace!("visit_statement: {:?}", statement); - - // We want to evaluate operands before any change to the assigned-to value, - // so we recurse first. - self.super_statement(statement, location); - - match statement.kind { - StatementKind::SetDiscriminant { ref place, variant_index } => { - match self.can_const_prop[place.local] { - // Do nothing if the place is indirect. - _ if place.is_indirect() => {} - ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local), - ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => { - match self.access_mut(place) { - Some(Value::Aggregate { variant, .. }) => *variant = variant_index, - _ => self.remove_const(place.local), - } - } - } - } - StatementKind::StorageLive(local) => { - self.remove_const(local); - } - StatementKind::StorageDead(local) => { - self.remove_const(local); - } - _ => {} - } - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - self.super_terminator(terminator, location); - match &terminator.kind { - TerminatorKind::Assert { expected, ref msg, ref cond, .. } => { - self.check_assertion(*expected, msg, cond, location); - } - TerminatorKind::SwitchInt { ref discr, ref targets } => { - if let Some(ref value) = self.eval_operand(discr) - && let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value)) - && let Ok(constant) = value_const.try_to_int() - && let Ok(constant) = constant.to_bits(constant.size()) - { - // We managed to evaluate the discriminant, so we know we only need to visit - // one target. - let target = targets.target_for_value(constant); - self.worklist.push(target); - return; - } - // We failed to evaluate the discriminant, fallback to visiting all successors. - } - // None of these have Operands to const-propagate. - TerminatorKind::Goto { .. } - | TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::Drop { .. } - | TerminatorKind::Yield { .. } - | TerminatorKind::CoroutineDrop - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::Call { .. } - | TerminatorKind::InlineAsm { .. } => {} - } - - self.worklist.extend(terminator.successors()); - } - - fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) { - self.super_basic_block_data(block, data); - - // We remove all Locals which are restricted in propagation to their containing blocks and - // which were modified in the current block. - // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. - let mut written_only_inside_own_block_locals = - std::mem::take(&mut self.written_only_inside_own_block_locals); - - // This loop can get very hot for some bodies: it check each local in each bb. - // To avoid this quadratic behaviour, we only clear the locals that were modified inside - // the current block. - // The order in which we remove consts does not matter. - #[allow(rustc::potential_query_instability)] - for local in written_only_inside_own_block_locals.drain() { - debug_assert_eq!(self.can_const_prop[local], ConstPropMode::OnlyInsideOwnBlock); - self.remove_const(local); - } - self.written_only_inside_own_block_locals = written_only_inside_own_block_locals; - - if cfg!(debug_assertions) { - for (local, &mode) in self.can_const_prop.iter_enumerated() { - match mode { - ConstPropMode::FullConstProp => {} - ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { - self.ensure_not_propagated(local); - } - } - } - } - } -} - -/// The maximum number of bytes that we'll allocate space for a local or the return value. -/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just -/// Severely regress performance. -const MAX_ALLOC_LIMIT: u64 = 1024; - -/// The mode that `ConstProp` is allowed to run in for a given `Local`. -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum ConstPropMode { - /// The `Local` can be propagated into and reads of this `Local` can also be propagated. - FullConstProp, - /// The `Local` can only be propagated into and from its own block. - OnlyInsideOwnBlock, - /// The `Local` cannot be part of propagation at all. Any statement - /// referencing it either for reading or writing will not get propagated. - NoPropagation, -} - -pub struct CanConstProp { - can_const_prop: IndexVec, - // False at the beginning. Once set, no more assignments are allowed to that local. - found_assignment: BitSet, -} - -impl CanConstProp { - /// Returns true if `local` can be propagated - pub fn check<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - body: &Body<'tcx>, - ) -> IndexVec { - let mut cpv = CanConstProp { - can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls), - found_assignment: BitSet::new_empty(body.local_decls.len()), - }; - for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { - let ty = body.local_decls[local].ty; - match tcx.layout_of(param_env.and(ty)) { - Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {} - // Either the layout fails to compute, then we can't use this local anyway - // or the local is too large, then we don't want to. - _ => { - *val = ConstPropMode::NoPropagation; - continue; - } - } - } - // Consider that arguments are assigned on entry. - for arg in body.args_iter() { - cpv.found_assignment.insert(arg); - } - cpv.visit_body(body); - cpv.can_const_prop - } -} - -impl<'tcx> Visitor<'tcx> for CanConstProp { - fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) { - use rustc_middle::mir::visit::PlaceContext::*; - - // Dereferencing just read the addess of `place.local`. - if place.projection.first() == Some(&PlaceElem::Deref) { - context = NonMutatingUse(NonMutatingUseContext::Copy); - } - - self.visit_local(place.local, context, loc); - self.visit_projection(place.as_ref(), context, loc); - } - - fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { - use rustc_middle::mir::visit::PlaceContext::*; - match context { - // These are just stores, where the storing is not propagatable, but there may be later - // mutations of the same local via `Store` - | MutatingUse(MutatingUseContext::Call) - | MutatingUse(MutatingUseContext::AsmOutput) - | MutatingUse(MutatingUseContext::Deinit) - // Actual store that can possibly even propagate a value - | MutatingUse(MutatingUseContext::Store) - | MutatingUse(MutatingUseContext::SetDiscriminant) => { - if !self.found_assignment.insert(local) { - match &mut self.can_const_prop[local] { - // If the local can only get propagated in its own block, then we don't have - // to worry about multiple assignments, as we'll nuke the const state at the - // end of the block anyway, and inside the block we overwrite previous - // states as applicable. - ConstPropMode::OnlyInsideOwnBlock => {} - ConstPropMode::NoPropagation => {} - other @ ConstPropMode::FullConstProp => { - trace!( - "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}", - local, other, - ); - *other = ConstPropMode::OnlyInsideOwnBlock; - } - } - } - } - // Reading constants is allowed an arbitrary number of times - NonMutatingUse(NonMutatingUseContext::Copy) - | NonMutatingUse(NonMutatingUseContext::Move) - | NonMutatingUse(NonMutatingUseContext::Inspect) - | NonMutatingUse(NonMutatingUseContext::PlaceMention) - | NonUse(_) => {} - - // These could be propagated with a smarter analysis or just some careful thinking about - // whether they'd be fine right now. - MutatingUse(MutatingUseContext::Yield) - | MutatingUse(MutatingUseContext::Drop) - | MutatingUse(MutatingUseContext::Retag) - // These can't ever be propagated under any scheme, as we can't reason about indirect - // mutation. - | NonMutatingUse(NonMutatingUseContext::SharedBorrow) - | NonMutatingUse(NonMutatingUseContext::FakeBorrow) - | NonMutatingUse(NonMutatingUseContext::AddressOf) - | MutatingUse(MutatingUseContext::Borrow) - | MutatingUse(MutatingUseContext::AddressOf) => { - trace!("local {:?} can't be propagated because it's used: {:?}", local, context); - self.can_const_prop[local] = ConstPropMode::NoPropagation; - } - MutatingUse(MutatingUseContext::Projection) - | NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"), - } - } -} diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs new file mode 100644 index 00000000000..a9cd688c315 --- /dev/null +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -0,0 +1,975 @@ +//! A lint that checks for known panics like +//! overflows, division by zero, +//! out-of-bound access etc. +//! Uses const propagation to determine the +//! values of operands during checks. + +use std::fmt::Debug; + +use rustc_const_eval::interpret::{ + format_interp_error, ImmTy, InterpCx, InterpResult, Projectable, Scalar, +}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def::DefKind; +use rustc_hir::HirId; +use rustc_index::{bit_set::BitSet, Idx, IndexVec}; +use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; +use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; +use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx}; + +use crate::dataflow_const_prop::DummyMachine; +use crate::errors::{AssertLint, AssertLintKind}; +use crate::MirLint; + +pub struct KnownPanicsLint; + +impl<'tcx> MirLint<'tcx> for KnownPanicsLint { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + if body.tainted_by_errors.is_some() { + return; + } + + let def_id = body.source.def_id().expect_local(); + let def_kind = tcx.def_kind(def_id); + let is_fn_like = def_kind.is_fn_like(); + let is_assoc_const = def_kind == DefKind::AssocConst; + + // Only run const prop on functions, methods, closures and associated constants + if !is_fn_like && !is_assoc_const { + // skip anon_const/statics/consts because they'll be evaluated by miri anyway + trace!("KnownPanicsLint skipped for {:?}", def_id); + return; + } + + // FIXME(welseywiser) const prop doesn't work on coroutines because of query cycles + // computing their layout. + if tcx.is_coroutine(def_id.to_def_id()) { + trace!("KnownPanicsLint skipped for coroutine {:?}", def_id); + return; + } + + trace!("KnownPanicsLint starting for {:?}", def_id); + + let mut linter = ConstPropagator::new(body, tcx); + linter.visit_body(body); + + trace!("KnownPanicsLint done for {:?}", def_id); + } +} + +/// Visits MIR nodes, performs const propagation +/// and runs lint checks as it goes +struct ConstPropagator<'mir, 'tcx> { + ecx: InterpCx<'mir, 'tcx, DummyMachine>, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + worklist: Vec, + visited_blocks: BitSet, + locals: IndexVec>, + body: &'mir Body<'tcx>, + written_only_inside_own_block_locals: FxHashSet, + can_const_prop: IndexVec, +} + +#[derive(Debug, Clone)] +enum Value<'tcx> { + Immediate(ImmTy<'tcx>), + Aggregate { variant: VariantIdx, fields: IndexVec> }, + Uninit, +} + +impl<'tcx> From> for Value<'tcx> { + fn from(v: ImmTy<'tcx>) -> Self { + Self::Immediate(v) + } +} + +impl<'tcx> Value<'tcx> { + fn project( + &self, + proj: &[PlaceElem<'tcx>], + prop: &ConstPropagator<'_, 'tcx>, + ) -> Option<&Value<'tcx>> { + let mut this = self; + for proj in proj { + this = match (*proj, this) { + (PlaceElem::Field(idx, _), Value::Aggregate { fields, .. }) => { + fields.get(idx).unwrap_or(&Value::Uninit) + } + (PlaceElem::Index(idx), Value::Aggregate { fields, .. }) => { + let idx = prop.get_const(idx.into())?.immediate()?; + let idx = prop.ecx.read_target_usize(idx).ok()?; + fields.get(FieldIdx::from_u32(idx.try_into().ok()?)).unwrap_or(&Value::Uninit) + } + ( + PlaceElem::ConstantIndex { offset, min_length: _, from_end: false }, + Value::Aggregate { fields, .. }, + ) => fields + .get(FieldIdx::from_u32(offset.try_into().ok()?)) + .unwrap_or(&Value::Uninit), + _ => return None, + }; + } + Some(this) + } + + fn project_mut(&mut self, proj: &[PlaceElem<'_>]) -> Option<&mut Value<'tcx>> { + let mut this = self; + for proj in proj { + this = match (proj, this) { + (PlaceElem::Field(idx, _), Value::Aggregate { fields, .. }) => { + fields.ensure_contains_elem(*idx, || Value::Uninit) + } + (PlaceElem::Field(..), val @ Value::Uninit) => { + *val = Value::Aggregate { + variant: VariantIdx::new(0), + fields: Default::default(), + }; + val.project_mut(&[*proj])? + } + _ => return None, + }; + } + Some(this) + } + + fn immediate(&self) -> Option<&ImmTy<'tcx>> { + match self { + Value::Immediate(op) => Some(op), + _ => None, + } + } +} + +impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> { + type LayoutOfResult = Result, LayoutError<'tcx>>; + + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> { + err + } +} + +impl HasDataLayout for ConstPropagator<'_, '_> { + #[inline] + fn data_layout(&self) -> &TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'_, 'tcx> { + #[inline] + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} + +impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> { + #[inline] + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } +} + +impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { + fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> { + let def_id = body.source.def_id(); + let param_env = tcx.param_env_reveal_all_normalized(def_id); + + let can_const_prop = CanConstProp::check(tcx, param_env, body); + let ecx = InterpCx::new(tcx, tcx.def_span(def_id), param_env, DummyMachine); + + ConstPropagator { + ecx, + tcx, + param_env, + worklist: vec![START_BLOCK], + visited_blocks: BitSet::new_empty(body.basic_blocks.len()), + locals: IndexVec::from_elem_n(Value::Uninit, body.local_decls.len()), + body, + can_const_prop, + written_only_inside_own_block_locals: Default::default(), + } + } + + fn local_decls(&self) -> &'mir LocalDecls<'tcx> { + &self.body.local_decls + } + + fn get_const(&self, place: Place<'tcx>) -> Option<&Value<'tcx>> { + self.locals[place.local].project(&place.projection, self) + } + + /// Remove `local` from the pool of `Locals`. Allows writing to them, + /// but not reading from them anymore. + fn remove_const(&mut self, local: Local) { + self.locals[local] = Value::Uninit; + self.written_only_inside_own_block_locals.remove(&local); + } + + fn access_mut(&mut self, place: &Place<'_>) -> Option<&mut Value<'tcx>> { + match self.can_const_prop[place.local] { + ConstPropMode::NoPropagation => return None, + ConstPropMode::OnlyInsideOwnBlock => { + self.written_only_inside_own_block_locals.insert(place.local); + } + ConstPropMode::FullConstProp => {} + } + self.locals[place.local].project_mut(place.projection) + } + + fn lint_root(&self, source_info: SourceInfo) -> Option { + source_info.scope.lint_root(&self.body.source_scopes) + } + + fn use_ecx(&mut self, f: F) -> Option + where + F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, + { + match f(self) { + Ok(val) => Some(val), + Err(error) => { + trace!("InterpCx operation failed: {:?}", error); + // Some errors shouldn't come up because creating them causes + // an allocation, which we should avoid. When that happens, + // dedicated error variants should be introduced instead. + assert!( + !error.kind().formatted_string(), + "known panics lint encountered formatting error: {}", + format_interp_error(self.ecx.tcx.dcx(), error), + ); + None + } + } + } + + /// Returns the value, if any, of evaluating `c`. + fn eval_constant(&mut self, c: &ConstOperand<'tcx>) -> Option> { + // FIXME we need to revisit this for #67176 + if c.has_param() { + return None; + } + + // Normalization needed b/c known panics lint runs in + // `mir_drops_elaborated_and_const_checked`, which happens before + // optimized MIR. Only after optimizing the MIR can we guarantee + // that the `RevealAll` pass has happened and that the body's consts + // are normalized, so any call to resolve before that needs to be + // manually normalized. + let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?; + + self.use_ecx(|this| this.ecx.eval_mir_constant(&val, Some(c.span), None))? + .as_mplace_or_imm() + .right() + } + + /// Returns the value, if any, of evaluating `place`. + #[instrument(level = "trace", skip(self), ret)] + fn eval_place(&mut self, place: Place<'tcx>) -> Option> { + match self.get_const(place)? { + Value::Immediate(imm) => Some(imm.clone()), + Value::Aggregate { .. } => None, + Value::Uninit => None, + } + } + + /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant` + /// or `eval_place`, depending on the variant of `Operand` used. + fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option> { + match *op { + Operand::Constant(ref c) => self.eval_constant(c), + Operand::Move(place) | Operand::Copy(place) => self.eval_place(place), + } + } + + fn report_assert_as_lint( + &self, + location: Location, + lint_kind: AssertLintKind, + assert_kind: AssertKind, + ) { + let source_info = self.body.source_info(location); + if let Some(lint_root) = self.lint_root(*source_info) { + let span = source_info.span; + self.tcx.emit_node_span_lint( + lint_kind.lint(), + lint_root, + span, + AssertLint { span, assert_kind, lint_kind }, + ); + } + } + + fn check_unary_op(&mut self, op: UnOp, arg: &Operand<'tcx>, location: Location) -> Option<()> { + let arg = self.eval_operand(arg)?; + if let (val, true) = self.use_ecx(|this| { + let val = this.ecx.read_immediate(&arg)?; + let (_res, overflow) = this.ecx.overflowing_unary_op(op, &val)?; + Ok((val, overflow)) + })? { + // `AssertKind` only has an `OverflowNeg` variant, so make sure that is + // appropriate to use. + assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow"); + self.report_assert_as_lint( + location, + AssertLintKind::ArithmeticOverflow, + AssertKind::OverflowNeg(val.to_const_int()), + ); + return None; + } + + Some(()) + } + + fn check_binary_op( + &mut self, + op: BinOp, + left: &Operand<'tcx>, + right: &Operand<'tcx>, + location: Location, + ) -> Option<()> { + let r = + self.eval_operand(right).and_then(|r| self.use_ecx(|this| this.ecx.read_immediate(&r))); + let l = + self.eval_operand(left).and_then(|l| self.use_ecx(|this| this.ecx.read_immediate(&l))); + // Check for exceeding shifts *even if* we cannot evaluate the LHS. + if matches!(op, BinOp::Shr | BinOp::Shl) { + let r = r.clone()?; + // We need the type of the LHS. We cannot use `place_layout` as that is the type + // of the result, which for checked binops is not the same! + let left_ty = left.ty(self.local_decls(), self.tcx); + let left_size = self.ecx.layout_of(left_ty).ok()?.size; + let right_size = r.layout.size; + let r_bits = r.to_scalar().to_bits(right_size).ok(); + if r_bits.is_some_and(|b| b >= left_size.bits() as u128) { + debug!("check_binary_op: reporting assert for {:?}", location); + let panic = AssertKind::Overflow( + op, + match l { + Some(l) => l.to_const_int(), + // Invent a dummy value, the diagnostic ignores it anyway + None => ConstInt::new( + ScalarInt::try_from_uint(1_u8, left_size).unwrap(), + left_ty.is_signed(), + left_ty.is_ptr_sized_integral(), + ), + }, + r.to_const_int(), + ); + self.report_assert_as_lint(location, AssertLintKind::ArithmeticOverflow, panic); + return None; + } + } + + if let (Some(l), Some(r)) = (l, r) { + // The remaining operators are handled through `overflowing_binary_op`. + if self.use_ecx(|this| { + let (_res, overflow) = this.ecx.overflowing_binary_op(op, &l, &r)?; + Ok(overflow) + })? { + self.report_assert_as_lint( + location, + AssertLintKind::ArithmeticOverflow, + AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()), + ); + return None; + } + } + Some(()) + } + + fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> { + // Perform any special handling for specific Rvalue types. + // Generally, checks here fall into one of two categories: + // 1. Additional checking to provide useful lints to the user + // - In this case, we will do some validation and then fall through to the + // end of the function which evals the assignment. + // 2. Working around bugs in other parts of the compiler + // - In this case, we'll return `None` from this function to stop evaluation. + match rvalue { + // Additional checking: give lints to the user if an overflow would occur. + // We do this here and not in the `Assert` terminator as that terminator is + // only sometimes emitted (overflow checks can be disabled), but we want to always + // lint. + Rvalue::UnaryOp(op, arg) => { + trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); + self.check_unary_op(*op, arg, location)?; + } + Rvalue::BinaryOp(op, box (left, right)) => { + trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); + self.check_binary_op(*op, left, right, location)?; + } + Rvalue::CheckedBinaryOp(op, box (left, right)) => { + trace!( + "checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})", + op, + left, + right + ); + self.check_binary_op(*op, left, right, location)?; + } + + // Do not try creating references (#67862) + Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => { + trace!("skipping AddressOf | Ref for {:?}", place); + + // This may be creating mutable references or immutable references to cells. + // If that happens, the pointed to value could be mutated via that reference. + // Since we aren't tracking references, the const propagator loses track of what + // value the local has right now. + // Thus, all locals that have their reference taken + // must not take part in propagation. + self.remove_const(place.local); + + return None; + } + Rvalue::ThreadLocalRef(def_id) => { + trace!("skipping ThreadLocalRef({:?})", def_id); + + return None; + } + + // There's no other checking to do at this time. + Rvalue::Aggregate(..) + | Rvalue::Use(..) + | Rvalue::CopyForDeref(..) + | Rvalue::Repeat(..) + | Rvalue::Len(..) + | Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) + | Rvalue::Discriminant(..) + | Rvalue::NullaryOp(..) => {} + } + + // FIXME we need to revisit this for #67176 + if rvalue.has_param() { + return None; + } + if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.param_env) { + // the interpreter doesn't support unsized locals (only unsized arguments), + // but rustc does (in a kinda broken way), so we have to skip them here + return None; + } + + Some(()) + } + + fn check_assertion( + &mut self, + expected: bool, + msg: &AssertKind>, + cond: &Operand<'tcx>, + location: Location, + ) -> Option { + let value = &self.eval_operand(cond)?; + trace!("assertion on {:?} should be {:?}", value, expected); + + let expected = Scalar::from_bool(expected); + let value_const = self.use_ecx(|this| this.ecx.read_scalar(value))?; + + if expected != value_const { + // Poison all places this operand references so that further code + // doesn't use the invalid value + if let Some(place) = cond.place() { + self.remove_const(place.local); + } + + enum DbgVal { + Val(T), + Underscore, + } + impl std::fmt::Debug for DbgVal { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Val(val) => val.fmt(fmt), + Self::Underscore => fmt.write_str("_"), + } + } + } + let mut eval_to_int = |op| { + // This can be `None` if the lhs wasn't const propagated and we just + // triggered the assert on the value of the rhs. + self.eval_operand(op) + .and_then(|op| self.ecx.read_immediate(&op).ok()) + .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int())) + }; + let msg = match msg { + AssertKind::DivisionByZero(op) => AssertKind::DivisionByZero(eval_to_int(op)), + AssertKind::RemainderByZero(op) => AssertKind::RemainderByZero(eval_to_int(op)), + AssertKind::Overflow(bin_op @ (BinOp::Div | BinOp::Rem), op1, op2) => { + // Division overflow is *UB* in the MIR, and different than the + // other overflow checks. + AssertKind::Overflow(*bin_op, eval_to_int(op1), eval_to_int(op2)) + } + AssertKind::BoundsCheck { ref len, ref index } => { + let len = eval_to_int(len); + let index = eval_to_int(index); + AssertKind::BoundsCheck { len, index } + } + // Remaining overflow errors are already covered by checks on the binary operators. + AssertKind::Overflow(..) | AssertKind::OverflowNeg(_) => return None, + // Need proper const propagator for these. + _ => return None, + }; + self.report_assert_as_lint(location, AssertLintKind::UnconditionalPanic, msg); + } + + None + } + + fn ensure_not_propagated(&self, local: Local) { + if cfg!(debug_assertions) { + let val = self.get_const(local.into()); + assert!( + matches!(val, Some(Value::Uninit)) + || self + .layout_of(self.local_decls()[local].ty) + .map_or(true, |layout| layout.is_zst()), + "failed to remove values for `{local:?}`, value={val:?}", + ) + } + } + + #[instrument(level = "trace", skip(self), ret)] + fn eval_rvalue(&mut self, rvalue: &Rvalue<'tcx>, dest: &Place<'tcx>) -> Option<()> { + if !dest.projection.is_empty() { + return None; + } + use rustc_middle::mir::Rvalue::*; + let layout = self.ecx.layout_of(dest.ty(self.body, self.tcx).ty).ok()?; + trace!(?layout); + + let val: Value<'_> = match *rvalue { + ThreadLocalRef(_) => return None, + + Use(ref operand) => self.eval_operand(operand)?.into(), + + CopyForDeref(place) => self.eval_place(place)?.into(), + + BinaryOp(bin_op, box (ref left, ref right)) => { + let left = self.eval_operand(left)?; + let left = self.use_ecx(|this| this.ecx.read_immediate(&left))?; + + let right = self.eval_operand(right)?; + let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?; + + let val = + self.use_ecx(|this| this.ecx.wrapping_binary_op(bin_op, &left, &right))?; + val.into() + } + + CheckedBinaryOp(bin_op, box (ref left, ref right)) => { + let left = self.eval_operand(left)?; + let left = self.use_ecx(|this| this.ecx.read_immediate(&left))?; + + let right = self.eval_operand(right)?; + let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?; + + let (val, overflowed) = + self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?; + let overflowed = ImmTy::from_bool(overflowed, self.tcx); + Value::Aggregate { + variant: VariantIdx::new(0), + fields: [Value::from(val), overflowed.into()].into_iter().collect(), + } + } + + UnaryOp(un_op, ref operand) => { + let operand = self.eval_operand(operand)?; + let val = self.use_ecx(|this| this.ecx.read_immediate(&operand))?; + + let val = self.use_ecx(|this| this.ecx.wrapping_unary_op(un_op, &val))?; + val.into() + } + + Aggregate(ref kind, ref fields) => Value::Aggregate { + fields: fields + .iter() + .map(|field| self.eval_operand(field).map_or(Value::Uninit, Value::Immediate)) + .collect(), + variant: match **kind { + AggregateKind::Adt(_, variant, _, _, _) => variant, + AggregateKind::Array(_) + | AggregateKind::Tuple + | AggregateKind::Closure(_, _) + | AggregateKind::Coroutine(_, _) + | AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0), + }, + }, + + Repeat(ref op, n) => { + trace!(?op, ?n); + return None; + } + + Len(place) => { + let len = match self.get_const(place)? { + Value::Immediate(src) => src.len(&self.ecx).ok()?, + Value::Aggregate { fields, .. } => fields.len() as u64, + Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() { + ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?, + _ => return None, + }, + }; + ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into() + } + + Ref(..) | AddressOf(..) => return None, + + NullaryOp(ref null_op, ty) => { + let op_layout = self.use_ecx(|this| this.ecx.layout_of(ty))?; + let val = match null_op { + NullOp::SizeOf => op_layout.size.bytes(), + NullOp::AlignOf => op_layout.align.abi.bytes(), + NullOp::OffsetOf(fields) => { + op_layout.offset_of_subfield(self, fields.iter()).bytes() + } + NullOp::DebugAssertions => return None, + }; + ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() + } + + ShallowInitBox(..) => return None, + + Cast(ref kind, ref value, to) => match kind { + CastKind::IntToInt | CastKind::IntToFloat => { + let value = self.eval_operand(value)?; + let value = self.ecx.read_immediate(&value).ok()?; + let to = self.ecx.layout_of(to).ok()?; + let res = self.ecx.int_to_int_or_float(&value, to).ok()?; + res.into() + } + CastKind::FloatToFloat | CastKind::FloatToInt => { + let value = self.eval_operand(value)?; + let value = self.ecx.read_immediate(&value).ok()?; + let to = self.ecx.layout_of(to).ok()?; + let res = self.ecx.float_to_float_or_int(&value, to).ok()?; + res.into() + } + CastKind::Transmute => { + let value = self.eval_operand(value)?; + let to = self.ecx.layout_of(to).ok()?; + // `offset` for immediates only supports scalar/scalar-pair ABIs, + // so bail out if the target is not one. + match (value.layout.abi, to.abi) { + (Abi::Scalar(..), Abi::Scalar(..)) => {} + (Abi::ScalarPair(..), Abi::ScalarPair(..)) => {} + _ => return None, + } + + value.offset(Size::ZERO, to, &self.ecx).ok()?.into() + } + _ => return None, + }, + + Discriminant(place) => { + let variant = match self.get_const(place)? { + Value::Immediate(op) => { + let op = op.clone(); + self.use_ecx(|this| this.ecx.read_discriminant(&op))? + } + Value::Aggregate { variant, .. } => *variant, + Value::Uninit => return None, + }; + let imm = self.use_ecx(|this| { + this.ecx.discriminant_for_variant( + place.ty(this.local_decls(), this.tcx).ty, + variant, + ) + })?; + imm.into() + } + }; + trace!(?val); + + *self.access_mut(dest)? = val; + + Some(()) + } +} + +impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { + fn visit_body(&mut self, body: &Body<'tcx>) { + while let Some(bb) = self.worklist.pop() { + if !self.visited_blocks.insert(bb) { + continue; + } + + let data = &body.basic_blocks[bb]; + self.visit_basic_block_data(bb, data); + } + } + + fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { + self.super_operand(operand, location); + } + + fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { + trace!("visit_constant: {:?}", constant); + self.super_constant(constant, location); + self.eval_constant(constant); + } + + fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_assign(place, rvalue, location); + + let Some(()) = self.check_rvalue(rvalue, location) else { return }; + + match self.can_const_prop[place.local] { + // Do nothing if the place is indirect. + _ if place.is_indirect() => {} + ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local), + ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => { + if self.eval_rvalue(rvalue, place).is_none() { + // Const prop failed, so erase the destination, ensuring that whatever happens + // from here on, does not know about the previous value. + // This is important in case we have + // ```rust + // let mut x = 42; + // x = SOME_MUTABLE_STATIC; + // // x must now be uninit + // ``` + // FIXME: we overzealously erase the entire local, because that's easier to + // implement. + trace!( + "propagation into {:?} failed. + Nuking the entire site from orbit, it's the only way to be sure", + place, + ); + self.remove_const(place.local); + } + } + } + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + trace!("visit_statement: {:?}", statement); + + // We want to evaluate operands before any change to the assigned-to value, + // so we recurse first. + self.super_statement(statement, location); + + match statement.kind { + StatementKind::SetDiscriminant { ref place, variant_index } => { + match self.can_const_prop[place.local] { + // Do nothing if the place is indirect. + _ if place.is_indirect() => {} + ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local), + ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => { + match self.access_mut(place) { + Some(Value::Aggregate { variant, .. }) => *variant = variant_index, + _ => self.remove_const(place.local), + } + } + } + } + StatementKind::StorageLive(local) => { + self.remove_const(local); + } + StatementKind::StorageDead(local) => { + self.remove_const(local); + } + _ => {} + } + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); + match &terminator.kind { + TerminatorKind::Assert { expected, ref msg, ref cond, .. } => { + self.check_assertion(*expected, msg, cond, location); + } + TerminatorKind::SwitchInt { ref discr, ref targets } => { + if let Some(ref value) = self.eval_operand(discr) + && let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value)) + && let Ok(constant) = value_const.try_to_int() + && let Ok(constant) = constant.to_bits(constant.size()) + { + // We managed to evaluate the discriminant, so we know we only need to visit + // one target. + let target = targets.target_for_value(constant); + self.worklist.push(target); + return; + } + // We failed to evaluate the discriminant, fallback to visiting all successors. + } + // None of these have Operands to const-propagate. + TerminatorKind::Goto { .. } + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate(_) + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::CoroutineDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::InlineAsm { .. } => {} + } + + self.worklist.extend(terminator.successors()); + } + + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) { + self.super_basic_block_data(block, data); + + // We remove all Locals which are restricted in propagation to their containing blocks and + // which were modified in the current block. + // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`. + let mut written_only_inside_own_block_locals = + std::mem::take(&mut self.written_only_inside_own_block_locals); + + // This loop can get very hot for some bodies: it check each local in each bb. + // To avoid this quadratic behaviour, we only clear the locals that were modified inside + // the current block. + // The order in which we remove consts does not matter. + #[allow(rustc::potential_query_instability)] + for local in written_only_inside_own_block_locals.drain() { + debug_assert_eq!(self.can_const_prop[local], ConstPropMode::OnlyInsideOwnBlock); + self.remove_const(local); + } + self.written_only_inside_own_block_locals = written_only_inside_own_block_locals; + + if cfg!(debug_assertions) { + for (local, &mode) in self.can_const_prop.iter_enumerated() { + match mode { + ConstPropMode::FullConstProp => {} + ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => { + self.ensure_not_propagated(local); + } + } + } + } + } +} + +/// The maximum number of bytes that we'll allocate space for a local or the return value. +/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just +/// Severely regress performance. +const MAX_ALLOC_LIMIT: u64 = 1024; + +/// The mode that `ConstProp` is allowed to run in for a given `Local`. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ConstPropMode { + /// The `Local` can be propagated into and reads of this `Local` can also be propagated. + FullConstProp, + /// The `Local` can only be propagated into and from its own block. + OnlyInsideOwnBlock, + /// The `Local` cannot be part of propagation at all. Any statement + /// referencing it either for reading or writing will not get propagated. + NoPropagation, +} + +/// A visitor that determines locals in a MIR body +/// that can be const propagated +pub struct CanConstProp { + can_const_prop: IndexVec, + // False at the beginning. Once set, no more assignments are allowed to that local. + found_assignment: BitSet, +} + +impl CanConstProp { + /// Returns true if `local` can be propagated + pub fn check<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + body: &Body<'tcx>, + ) -> IndexVec { + let mut cpv = CanConstProp { + can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls), + found_assignment: BitSet::new_empty(body.local_decls.len()), + }; + for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { + let ty = body.local_decls[local].ty; + match tcx.layout_of(param_env.and(ty)) { + Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {} + // Either the layout fails to compute, then we can't use this local anyway + // or the local is too large, then we don't want to. + _ => { + *val = ConstPropMode::NoPropagation; + continue; + } + } + } + // Consider that arguments are assigned on entry. + for arg in body.args_iter() { + cpv.found_assignment.insert(arg); + } + cpv.visit_body(body); + cpv.can_const_prop + } +} + +impl<'tcx> Visitor<'tcx> for CanConstProp { + fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) { + use rustc_middle::mir::visit::PlaceContext::*; + + // Dereferencing just read the addess of `place.local`. + if place.projection.first() == Some(&PlaceElem::Deref) { + context = NonMutatingUse(NonMutatingUseContext::Copy); + } + + self.visit_local(place.local, context, loc); + self.visit_projection(place.as_ref(), context, loc); + } + + fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) { + use rustc_middle::mir::visit::PlaceContext::*; + match context { + // These are just stores, where the storing is not propagatable, but there may be later + // mutations of the same local via `Store` + | MutatingUse(MutatingUseContext::Call) + | MutatingUse(MutatingUseContext::AsmOutput) + | MutatingUse(MutatingUseContext::Deinit) + // Actual store that can possibly even propagate a value + | MutatingUse(MutatingUseContext::Store) + | MutatingUse(MutatingUseContext::SetDiscriminant) => { + if !self.found_assignment.insert(local) { + match &mut self.can_const_prop[local] { + // If the local can only get propagated in its own block, then we don't have + // to worry about multiple assignments, as we'll nuke the const state at the + // end of the block anyway, and inside the block we overwrite previous + // states as applicable. + ConstPropMode::OnlyInsideOwnBlock => {} + ConstPropMode::NoPropagation => {} + other @ ConstPropMode::FullConstProp => { + trace!( + "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}", + local, other, + ); + *other = ConstPropMode::OnlyInsideOwnBlock; + } + } + } + } + // Reading constants is allowed an arbitrary number of times + NonMutatingUse(NonMutatingUseContext::Copy) + | NonMutatingUse(NonMutatingUseContext::Move) + | NonMutatingUse(NonMutatingUseContext::Inspect) + | NonMutatingUse(NonMutatingUseContext::PlaceMention) + | NonUse(_) => {} + + // These could be propagated with a smarter analysis or just some careful thinking about + // whether they'd be fine right now. + MutatingUse(MutatingUseContext::Yield) + | MutatingUse(MutatingUseContext::Drop) + | MutatingUse(MutatingUseContext::Retag) + // These can't ever be propagated under any scheme, as we can't reason about indirect + // mutation. + | NonMutatingUse(NonMutatingUseContext::SharedBorrow) + | NonMutatingUse(NonMutatingUseContext::FakeBorrow) + | NonMutatingUse(NonMutatingUseContext::AddressOf) + | MutatingUse(MutatingUseContext::Borrow) + | MutatingUse(MutatingUseContext::AddressOf) => { + trace!("local {:?} can't be propagated because it's used: {:?}", local, context); + self.can_const_prop[local] = ConstPropMode::NoPropagation; + } + MutatingUse(MutatingUseContext::Projection) + | NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"), + } + } +} diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 74b36eb5ee8..945c3c662a6 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -59,7 +59,6 @@ mod remove_place_mention; mod add_subtyping_projections; pub mod cleanup_post_borrowck; mod const_debuginfo; -mod const_prop_lint; mod copy_prop; mod coroutine; mod cost_checker; @@ -83,6 +82,7 @@ mod gvn; pub mod inline; mod instsimplify; mod jump_threading; +mod known_panics_lint; mod large_enums; mod lint; mod lower_intrinsics; @@ -533,7 +533,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &elaborate_box_derefs::ElaborateBoxDerefs, &coroutine::StateTransform, &add_retag::AddRetag, - &Lint(const_prop_lint::ConstPropLint), + &Lint(known_panics_lint::KnownPanicsLint), ]; pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial))); } -- cgit 1.4.1-3-g733a5 From 994d55158dcfe0b1b299591bb552af14c63c6e60 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Feb 2024 02:13:28 +0000 Subject: Simply do not ICE --- compiler/rustc_trait_selection/src/solve/fulfill.rs | 5 ++++- tests/ui/traits/next-solver/coherence-fulfill-overflow.rs | 15 +++++++++++++++ .../traits/next-solver/coherence-fulfill-overflow.stderr | 11 +++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/next-solver/coherence-fulfill-overflow.rs create mode 100644 tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr (limited to 'compiler') diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 63555a305d8..97f715b6386 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -109,7 +109,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut errors = Vec::new(); for i in 0.. { if !infcx.tcx.recursion_limit().value_within_limit(i) { - unimplemented!("overflowed on pending obligations: {:?}", self.obligations); + // Only return true errors that we have accumulated while processing; + // keep ambiguities around, *including overflows*, because they shouldn't + // be considered true errors. + return errors; } let mut has_changed = false; diff --git a/tests/ui/traits/next-solver/coherence-fulfill-overflow.rs b/tests/ui/traits/next-solver/coherence-fulfill-overflow.rs new file mode 100644 index 00000000000..ff577da32c2 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence-fulfill-overflow.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Znext-solver=coherence + +#![recursion_limit = "10"] + +trait Trait {} + +struct W(*const T); +trait TwoW {} +impl TwoW for W> {} + +impl Trait for W {} +impl Trait for T {} +//~^ ERROR conflicting implementations of trait `Trait` for type `W + +fn main() {} diff --git a/tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr new file mode 100644 index 00000000000..406c0ccca97 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `W>>>>>>>>>>>>>>>>>>>>` + --> $DIR/coherence-fulfill-overflow.rs:12:1 + | +LL | impl Trait for W {} + | ------------------------------------- first implementation here +LL | impl Trait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W>>>>>>>>>>>>>>>>>>>>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. -- cgit 1.4.1-3-g733a5 From f6f87798439e2ce7861da761b444fe0978335ed9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 6 Feb 2024 16:44:30 +1100 Subject: Reduce capabilities of `Diagnostic`. Currently many diagnostic modifier methods are available on both `Diagnostic` and `DiagnosticBuilder`. This commit removes most of them from `Diagnostic`. To minimize the diff size, it keeps them within `diagnostic.rs` but changes the surrounding `impl Diagnostic` block to `impl DiagnosticBuilder`. (I intend to move things around later, to give a more sensible code layout.) `Diagnostic` keeps a few methods that it still needs, like `sub`, `arg`, and `replace_args`. The `forward!` macro, which defined two additional methods per call (e.g. `note` and `with_note`), is replaced by the `with_fn!` macro, which defines one additional method per call (e.g. `with_note`). It's now also only used when necessary -- not all modifier methods currently need a `with_*` form. (New ones can be easily added as necessary.) All this also requires changing `trait AddToDiagnostic` so its methods take `DiagnosticBuilder` instead of `Diagnostic`, which leads to many mechanical changes. `SubdiagnosticMessageOp` gains a type parameter `G`. There are three subdiagnostics -- `DelayedAtWithoutNewline`, `DelayedAtWithNewline`, and `InvalidFlushedDelayedDiagnosticLevel` -- that are created within the diagnostics machinery and appended to external diagnostics. These are handled at the `Diagnostic` level, which means it's now hard to construct them via `derive(Diagnostic)`, so instead we construct them by hand. This has no effect on what they look like when printed. There are lots of new `allow` markers for `untranslatable_diagnostics` and `diagnostics_outside_of_impl`. This is because `#[rustc_lint_diagnostics]` annotations were present on the `Diagnostic` modifier methods, but missing from the `DiagnosticBuilder` modifier methods. They're now present. --- compiler/rustc_ast_lowering/src/errors.rs | 9 +- compiler/rustc_ast_passes/src/errors.rs | 17 +- compiler/rustc_ast_passes/src/feature_gate.rs | 3 + .../src/diagnostics/region_errors.rs | 15 ++ compiler/rustc_borrowck/src/lib.rs | 2 + compiler/rustc_builtin_macros/src/errors.rs | 10 +- compiler/rustc_codegen_ssa/src/back/write.rs | 4 +- .../src/transform/check_consts/ops.rs | 7 + compiler/rustc_errors/src/diagnostic.rs | 212 +++++++++++++++------ compiler/rustc_errors/src/diagnostic_builder.rs | 191 ++----------------- compiler/rustc_errors/src/diagnostic_impls.rs | 30 +-- compiler/rustc_errors/src/emitter.rs | 2 +- compiler/rustc_errors/src/lib.rs | 82 ++++---- compiler/rustc_expand/src/base.rs | 2 + compiler/rustc_expand/src/config.rs | 1 + compiler/rustc_expand/src/proc_macro_server.rs | 9 +- compiler/rustc_hir_typeck/src/errors.rs | 24 ++- compiler/rustc_infer/src/errors/mod.rs | 59 ++++-- .../rustc_infer/src/errors/note_and_explain.rs | 11 +- compiler/rustc_lint/src/context/diagnostics.rs | 3 + compiler/rustc_lint/src/errors.rs | 10 +- compiler/rustc_lint/src/levels.rs | 3 + compiler/rustc_lint/src/lints.rs | 66 +++++-- .../rustc_macros/src/diagnostics/subdiagnostic.rs | 10 +- compiler/rustc_metadata/src/errors.rs | 4 + compiler/rustc_mir_build/src/errors.rs | 14 +- compiler/rustc_mir_transform/src/errors.rs | 3 + compiler/rustc_monomorphize/src/errors.rs | 1 + compiler/rustc_parse/src/errors.rs | 8 +- compiler/rustc_passes/src/check_const.rs | 9 +- compiler/rustc_passes/src/errors.rs | 11 +- compiler/rustc_pattern_analysis/src/errors.rs | 8 +- compiler/rustc_session/src/config.rs | 3 + compiler/rustc_trait_selection/src/errors.rs | 10 +- src/tools/clippy/clippy_utils/src/sugg.rs | 4 +- tests/ui-fulldeps/internal-lints/diagnostics.rs | 13 +- .../ui-fulldeps/internal-lints/diagnostics.stderr | 8 +- .../diagnostic-derive-doc-comment-field.stderr | 9 +- .../session-diagnostic/diagnostic-derive.rs | 4 +- .../session-diagnostic/diagnostic-derive.stderr | 6 +- 40 files changed, 502 insertions(+), 395 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 274e6b7458c..834409da675 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,5 +1,6 @@ use rustc_errors::{ - codes::*, AddToDiagnostic, Diagnostic, DiagnosticArgFromDisplay, SubdiagnosticMessageOp, + codes::*, AddToDiagnostic, DiagnosticArgFromDisplay, DiagnosticBuilder, EmissionGuarantee, + SubdiagnosticMessageOp, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -41,7 +42,11 @@ pub struct InvalidAbi { pub struct InvalidAbiReason(pub &'static str); impl AddToDiagnostic for InvalidAbiReason { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _: F, + ) { #[allow(rustc::untranslatable_diagnostic)] diag.note(self.0); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 9662c73ca85..e5153c89790 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,7 +1,10 @@ //! Errors emitted by ast_passes. use rustc_ast::ParamKindOrd; -use rustc_errors::{codes::*, AddToDiagnostic, Applicability, Diagnostic, SubdiagnosticMessageOp}; +use rustc_errors::{ + codes::*, AddToDiagnostic, Applicability, DiagnosticBuilder, EmissionGuarantee, + SubdiagnosticMessageOp, +}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -372,7 +375,11 @@ pub struct EmptyLabelManySpans(pub Vec); // The derive for `Vec` does multiple calls to `span_label`, adding commas between each impl AddToDiagnostic for EmptyLabelManySpans { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _: F, + ) { diag.span_labels(self.0, ""); } } @@ -729,7 +736,11 @@ pub struct StableFeature { } impl AddToDiagnostic for StableFeature { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _: F, + ) { diag.arg("name", self.name); diag.arg("since", self.since); diag.help(fluent::ast_passes_stable_since); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 409aef9185d..1b0dd9acc37 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -22,6 +22,9 @@ macro_rules! gate { }}; ($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{ if !$visitor.features.$feature && !$span.allows_unstable(sym::$feature) { + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit(); } }}; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 1b88d5046d9..50d22881c3e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -251,6 +251,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { hrtb_bounds.iter().for_each(|bound| { let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; }; + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] diag.span_note( *trait_span, "due to current limitations in the borrow checker, this implies a `'static` lifetime" @@ -421,6 +424,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// ``` /// /// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`. + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] pub(crate) fn report_region_error( &mut self, fr: RegionVid, @@ -685,12 +691,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from); if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span { + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] diag.span_label( outlived_fr_span, format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",), ); } + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] if let Some((Some(fr_name), fr_span)) = fr_name_and_span { diag.span_label( fr_span, @@ -714,6 +726,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap(); outlived_fr_region_name.highlight_region_name(&mut diag); + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] diag.span_label( *span, format!( diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 6c2a511538d..dbaa9e5bcfa 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2497,6 +2497,8 @@ mod diags { } for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) { if count > 10 { + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] diag.note(format!("...and {} other attempted mutable borrows", count - 10)); } self.diags.buffered_diags.push(BufferedDiag::Error(diag)); diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 8d2e06bf30d..f304a37be85 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::{ - codes::*, AddToDiagnostic, DiagCtxt, Diagnostic, DiagnosticBuilder, EmissionGuarantee, - IntoDiagnostic, Level, MultiSpan, SingleLabelManySpans, SubdiagnosticMessageOp, + codes::*, AddToDiagnostic, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, + Level, MultiSpan, SingleLabelManySpans, SubdiagnosticMessageOp, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -611,7 +611,11 @@ pub(crate) struct FormatUnusedArg { // Allow the singular form to be a subdiagnostic of the multiple-unused // form of diagnostic. impl AddToDiagnostic for FormatUnusedArg { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { diag.arg("named", self.named); let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into()); diag.span_label(self.span, msg); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 24fdd013509..7a981217b52 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1856,9 +1856,7 @@ impl SharedEmitterMain { Ok(SharedEmitterMessage::Diagnostic(diag)) => { let dcx = sess.dcx(); let mut d = rustc_errors::Diagnostic::new_with_messages(diag.lvl, diag.msgs); - if let Some(code) = diag.code { - d.code(code); - } + d.code = diag.code; // may be `None`, that's ok d.replace_args(diag.args); dcx.emit_diagnostic(d); } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 25ddd5e85f9..5b4bbf8510b 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -93,6 +93,9 @@ pub struct FnCallNonConst<'tcx> { } impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> { let FnCallNonConst { caller, callee, args, span, call_source, feature } = *self; let ConstCx { tcx, param_env, .. } = *ccx; @@ -321,6 +324,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { .dcx() .create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) }); + // FIXME: make this translatable + #[allow(rustc::untranslatable_diagnostic)] if ccx.is_const_stable_const_fn() { err.help("const-stable functions can only call other const-stable functions"); } else if ccx.tcx.sess.is_nightly_build() { @@ -591,6 +596,8 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess { span, format!("referencing statics in {}s is unstable", ccx.const_kind(),), ); + // FIXME: make this translatable + #[allow(rustc::untranslatable_diagnostic)] err .note("`static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.") .help("to fix this, the value can be extracted to a `const` and then used."); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 034636bea48..57610635ee6 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -12,6 +12,7 @@ use rustc_span::{Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt::{self, Debug}; use std::hash::{Hash, Hasher}; +use std::ops::{Deref, DerefMut}; use std::panic::Location; /// Error type for `Diagnostic`'s `suggestions` field, indicating that @@ -71,17 +72,21 @@ where Self: Sized, { /// Add a subdiagnostic to an existing diagnostic. - fn add_to_diagnostic(self, diag: &mut Diagnostic) { + fn add_to_diagnostic(self, diag: &mut DiagnosticBuilder<'_, G>) { self.add_to_diagnostic_with(diag, |_, m| m); } /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used /// (to optionally perform eager translation). - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F); + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ); } -pub trait SubdiagnosticMessageOp = - Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage; +pub trait SubdiagnosticMessageOp = + Fn(&mut DiagnosticBuilder<'_, G>, SubdiagnosticMessage) -> SubdiagnosticMessage; /// Trait implemented by lint types. This should not be implemented manually. Instead, use /// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. @@ -93,6 +98,10 @@ pub trait DecorateLint<'a, G: EmissionGuarantee> { fn msg(&self) -> DiagnosticMessage; } +/// The main part of a diagnostic. Note that `DiagnosticBuilder`, which wraps +/// this type, is used for most operations, and should be used instead whenever +/// possible. This type should only be used when `DiagnosticBuilder`'s lifetime +/// causes difficulties, e.g. when storing diagnostics within `DiagCtxt`. #[must_use] #[derive(Clone, Debug, Encodable, Decodable)] pub struct Diagnostic { @@ -289,6 +298,90 @@ impl Diagnostic { } } + // See comment on `DiagnosticBuilder::subdiagnostic_message_to_diagnostic_message`. + pub(crate) fn subdiagnostic_message_to_diagnostic_message( + &self, + attr: impl Into, + ) -> DiagnosticMessage { + let msg = + self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages"); + msg.with_subdiagnostic_message(attr.into()) + } + + pub(crate) fn sub( + &mut self, + level: Level, + message: impl Into, + span: MultiSpan, + ) { + let sub = SubDiagnostic { + level, + messages: vec![( + self.subdiagnostic_message_to_diagnostic_message(message), + Style::NoStyle, + )], + span, + }; + self.children.push(sub); + } + + pub(crate) fn arg(&mut self, name: impl Into, arg: impl IntoDiagnosticArg) { + self.args.insert(name.into(), arg.into_diagnostic_arg()); + } + + pub fn args(&self) -> impl Iterator> { + self.args.iter() + } + + pub fn replace_args(&mut self, args: FxIndexMap) { + self.args = args; + } +} + +/// `DiagnosticBuilder` impls many `&mut self -> &mut Self` methods. Each one +/// modifies an existing diagnostic, either in a standalone fashion, e.g. +/// `err.code(code);`, or in a chained fashion to make multiple modifications, +/// e.g. `err.code(code).span(span);`. +/// +/// This macro creates an equivalent `self -> Self` method, with a `with_` +/// prefix. This can be used in a chained fashion when making a new diagnostic, +/// e.g. `let err = struct_err(msg).with_code(code);`, or emitting a new +/// diagnostic, e.g. `struct_err(msg).with_code(code).emit();`. +/// +/// Although the latter method can be used to modify an existing diagnostic, +/// e.g. `err = err.with_code(code);`, this should be avoided because the former +/// method gives shorter code, e.g. `err.code(code);`. +/// +/// Note: the `with_` methods are added only when needed. If you want to use +/// one and it's not defined, feel free to add it. +/// +/// Note: any doc comments must be within the `with_fn!` call. +macro_rules! with_fn { + { + $with_f:ident, + $(#[$attrs:meta])* + pub fn $f:ident(&mut $self:ident, $($name:ident: $ty:ty),* $(,)?) -> &mut Self { + $($body:tt)* + } + } => { + // The original function. + $(#[$attrs])* + #[doc = concat!("See [`DiagnosticBuilder::", stringify!($f), "()`].")] + pub fn $f(&mut $self, $($name: $ty),*) -> &mut Self { + $($body)* + } + + // The `with_*` variant. + $(#[$attrs])* + #[doc = concat!("See [`DiagnosticBuilder::", stringify!($f), "()`].")] + pub fn $with_f(mut $self, $($name: $ty),*) -> Self { + $self.$f($($name),*); + $self + } + }; +} + +impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Delay emission of this diagnostic as a bug. /// /// This can be useful in contexts where an error indicates a bug but @@ -309,6 +402,7 @@ impl Diagnostic { self.level = Level::DelayedBug; } + with_fn! { with_span_label, /// Appends a labeled span to the diagnostic. /// /// Labels are used to convey additional context for the diagnostic's primary span. They will @@ -323,10 +417,12 @@ impl Diagnostic { /// primary. #[rustc_lint_diagnostics] pub fn span_label(&mut self, span: Span, label: impl Into) -> &mut Self { - self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label)); + let msg = self.subdiagnostic_message_to_diagnostic_message(label); + self.span.push_span_label(span, msg); self - } + } } + with_fn! { with_span_labels, /// Labels all the given spans with the provided label. /// See [`Self::span_label()`] for more information. pub fn span_labels(&mut self, spans: impl IntoIterator, label: &str) -> &mut Self { @@ -334,7 +430,7 @@ impl Diagnostic { self.span_label(span, label.to_string()); } self - } + } } pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self { let before = self.span.clone(); @@ -412,39 +508,40 @@ impl Diagnostic { self } + with_fn! { with_note, /// Add a note attached to this diagnostic. #[rustc_lint_diagnostics] pub fn note(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::Note, msg, MultiSpan::new()); self - } + } } fn highlighted_note(&mut self, msg: Vec) -> &mut Self { self.sub_with_highlights(Level::Note, msg, MultiSpan::new()); self } - /// Prints the span with a note above it. - /// This is like [`Diagnostic::note()`], but it gets its own span. + /// This is like [`DiagnosticBuilder::note()`], but it's only printed once. pub fn note_once(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::OnceNote, msg, MultiSpan::new()); self } + with_fn! { with_span_note, /// Prints the span with a note above it. - /// This is like [`Diagnostic::note()`], but it gets its own span. + /// This is like [`DiagnosticBuilder::note()`], but it gets its own span. #[rustc_lint_diagnostics] - pub fn span_note>( + pub fn span_note( &mut self, - sp: S, + sp: impl Into, msg: impl Into, ) -> &mut Self { self.sub(Level::Note, msg, sp.into()); self - } + } } /// Prints the span with a note above it. - /// This is like [`Diagnostic::note()`], but it gets its own span. + /// This is like [`DiagnosticBuilder::note_once()`], but it gets its own span. pub fn span_note_once>( &mut self, sp: S, @@ -454,15 +551,16 @@ impl Diagnostic { self } + with_fn! { with_warn, /// Add a warning attached to this diagnostic. #[rustc_lint_diagnostics] pub fn warn(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::Warning, msg, MultiSpan::new()); self - } + } } /// Prints the span with a warning above it. - /// This is like [`Diagnostic::warn()`], but it gets its own span. + /// This is like [`DiagnosticBuilder::warn()`], but it gets its own span. #[rustc_lint_diagnostics] pub fn span_warn>( &mut self, @@ -473,15 +571,15 @@ impl Diagnostic { self } + with_fn! { with_help, /// Add a help message attached to this diagnostic. #[rustc_lint_diagnostics] pub fn help(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::Help, msg, MultiSpan::new()); self - } + } } - /// Prints the span with a help above it. - /// This is like [`Diagnostic::help()`], but it gets its own span. + /// This is like [`DiagnosticBuilder::help()`], but it's only printed once. pub fn help_once(&mut self, msg: impl Into) -> &mut Self { self.sub(Level::OnceHelp, msg, MultiSpan::new()); self @@ -494,7 +592,7 @@ impl Diagnostic { } /// Prints the span with some help above it. - /// This is like [`Diagnostic::help()`], but it gets its own span. + /// This is like [`DiagnosticBuilder::help()`], but it gets its own span. #[rustc_lint_diagnostics] pub fn span_help>( &mut self, @@ -531,6 +629,7 @@ impl Diagnostic { } } + with_fn! { with_multipart_suggestion, /// Show a suggestion that has multiple parts to it. /// In other words, multiple changes need to be applied as part of this suggestion. pub fn multipart_suggestion( @@ -545,7 +644,7 @@ impl Diagnostic { applicability, SuggestionStyle::ShowCode, ) - } + } } /// Show a suggestion that has multiple parts to it, always as it's own subdiagnostic. /// In other words, multiple changes need to be applied as part of this suggestion. @@ -562,7 +661,8 @@ impl Diagnostic { SuggestionStyle::ShowAlways, ) } - /// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`]. + + /// [`DiagnosticBuilder::multipart_suggestion()`] but you can set the [`SuggestionStyle`]. pub fn multipart_suggestion_with_style( &mut self, msg: impl Into, @@ -619,6 +719,7 @@ impl Diagnostic { ) } + with_fn! { with_span_suggestion, /// Prints out a message with a suggested edit of the code. /// /// In case of short messages and a simple suggestion, rustc displays it as a label: @@ -651,9 +752,9 @@ impl Diagnostic { SuggestionStyle::ShowCode, ); self - } + } } - /// [`Diagnostic::span_suggestion()`] but you can set the [`SuggestionStyle`]. + /// [`DiagnosticBuilder::span_suggestion()`] but you can set the [`SuggestionStyle`]. pub fn span_suggestion_with_style( &mut self, sp: Span, @@ -677,6 +778,7 @@ impl Diagnostic { self } + with_fn! { with_span_suggestion_verbose, /// Always show the suggested change. pub fn span_suggestion_verbose( &mut self, @@ -693,10 +795,11 @@ impl Diagnostic { SuggestionStyle::ShowAlways, ); self - } + } } + with_fn! { with_span_suggestions, /// Prints out a message with multiple suggested edits of the code. - /// See also [`Diagnostic::span_suggestion()`]. + /// See also [`DiagnosticBuilder::span_suggestion()`]. pub fn span_suggestions( &mut self, sp: Span, @@ -711,9 +814,8 @@ impl Diagnostic { applicability, SuggestionStyle::ShowCode, ) - } + } } - /// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`]. pub fn span_suggestions_with_style( &mut self, sp: Span, @@ -743,7 +845,7 @@ impl Diagnostic { /// Prints out a message with multiple suggested edits of the code, where each edit consists of /// multiple parts. - /// See also [`Diagnostic::multipart_suggestion()`]. + /// See also [`DiagnosticBuilder::multipart_suggestion()`]. pub fn multipart_suggestions( &mut self, msg: impl Into, @@ -785,6 +887,7 @@ impl Diagnostic { self } + with_fn! { with_span_suggestion_short, /// Prints out a message with a suggested edit of the code. If the suggestion is presented /// inline, it will only show the message and not the suggestion. /// @@ -804,7 +907,7 @@ impl Diagnostic { SuggestionStyle::HideCodeInline, ); self - } + } } /// Prints out a message for a suggestion without showing the suggested code. /// @@ -829,6 +932,7 @@ impl Diagnostic { self } + with_fn! { with_tool_only_span_suggestion, /// Adds a suggestion to the JSON output that will not be shown in the CLI. /// /// This is intended to be used for suggestions that are *very* obvious in what the changes @@ -849,7 +953,7 @@ impl Diagnostic { SuggestionStyle::CompletelyHidden, ); self - } + } } /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see /// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages @@ -868,45 +972,45 @@ impl Diagnostic { self } - pub fn span>(&mut self, sp: S) -> &mut Self { + with_fn! { with_span, + /// Add a span. + pub fn span(&mut self, sp: impl Into) -> &mut Self { self.span = sp.into(); if let Some(span) = self.span.primary_span() { self.sort_span = span; } self - } + } } pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self { self.is_lint = Some(IsLint { name, has_future_breakage }); self } + with_fn! { with_code, + /// Add an error code. pub fn code(&mut self, code: ErrCode) -> &mut Self { self.code = Some(code); self - } + } } + with_fn! { with_primary_message, + /// Add a primary message. pub fn primary_message(&mut self, msg: impl Into) -> &mut Self { self.messages[0] = (msg.into(), Style::NoStyle); self - } - - pub fn args(&self) -> impl Iterator> { - self.args.iter() - } + } } + with_fn! { with_arg, + /// Add an argument. pub fn arg( &mut self, name: impl Into, arg: impl IntoDiagnosticArg, ) -> &mut Self { - self.args.insert(name.into(), arg.into_diagnostic_arg()); + self.deref_mut().arg(name, arg); self - } - - pub fn replace_args(&mut self, args: FxIndexMap) { - self.args = args; - } + } } /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by /// combining it with the primary message of the diagnostic (if translatable, otherwise it just @@ -915,9 +1019,7 @@ impl Diagnostic { &self, attr: impl Into, ) -> DiagnosticMessage { - let msg = - self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages"); - msg.with_subdiagnostic_message(attr.into()) + self.deref().subdiagnostic_message_to_diagnostic_message(attr) } /// Convenience function for internal use, clients should use one of the @@ -925,15 +1027,7 @@ impl Diagnostic { /// /// Used by `proc_macro_server` for implementing `server::Diagnostic`. pub fn sub(&mut self, level: Level, message: impl Into, span: MultiSpan) { - let sub = SubDiagnostic { - level, - messages: vec![( - self.subdiagnostic_message_to_diagnostic_message(message), - Style::NoStyle, - )], - span, - }; - self.children.push(sub); + self.deref_mut().sub(level, message, span); } /// Convenience function for internal use, clients should use one of the @@ -946,7 +1040,9 @@ impl Diagnostic { let sub = SubDiagnostic { level, messages, span }; self.children.push(sub); } +} +impl Diagnostic { /// Fields used for Hash, and PartialEq trait fn keys( &self, diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 0572df69ca9..3a6a494af95 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -1,14 +1,8 @@ -use crate::diagnostic::IntoDiagnosticArg; -use crate::{DiagCtxt, Level, MultiSpan, StashKey}; use crate::{ - Diagnostic, DiagnosticMessage, DiagnosticStyledString, ErrCode, ErrorGuaranteed, ExplicitBug, - SubdiagnosticMessage, + DiagCtxt, Diagnostic, DiagnosticMessage, ErrorGuaranteed, ExplicitBug, Level, StashKey, }; -use rustc_lint_defs::Applicability; use rustc_span::source_map::Spanned; - use rustc_span::Span; -use std::borrow::Cow; use std::fmt::{self, Debug}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; @@ -35,6 +29,11 @@ where } /// Used for emitting structured error messages and other diagnostic information. +/// Wraps a `Diagnostic`, adding some useful things. +/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check +/// that it has been emitted or cancelled. +/// - The `EmissionGuarantee`, which determines the type returned from `emit`. +/// /// Each constructed `DiagnosticBuilder` must be consumed by a function such as /// `emit`, `cancel`, `delay_as_bug`, or `into_diagnostic`. A panic occurrs if a /// `DiagnosticBuilder` is dropped without being consumed by one of these @@ -56,9 +55,11 @@ pub struct DiagnosticBuilder<'a, G: EmissionGuarantee = ErrorGuaranteed> { /// often used as a return value, especially within the frequently-used /// `PResult` type. In theory, return value optimization (RVO) should avoid /// unnecessary copying. In practice, it does not (at the time of writing). - diag: Option>, + // FIXME(nnethercote) Make private once this moves to diagnostic.rs. + pub(crate) diag: Option>, - _marker: PhantomData, + // FIXME(nnethercote) Make private once this moves to diagnostic.rs. + pub(crate) _marker: PhantomData, } // Cloning a `DiagnosticBuilder` is a recipe for a diagnostic being emitted @@ -88,18 +89,21 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Takes the diagnostic. For use by methods that consume the /// DiagnosticBuilder: `emit`, `cancel`, etc. Afterwards, `drop` is the /// only code that will be run on `self`. - fn take_diag(&mut self) -> Diagnostic { + // FIXME(nnethercote) Make private once this moves to diagnostic.rs. + pub(crate) fn take_diag(&mut self) -> Diagnostic { Box::into_inner(self.diag.take().unwrap()) } /// Most `emit_producing_guarantee` functions use this as a starting point. - fn emit_producing_nothing(mut self) { + // FIXME(nnethercote) Make private once this moves to diagnostic.rs. + pub(crate) fn emit_producing_nothing(mut self) { let diag = self.take_diag(); self.dcx.emit_diagnostic(diag); } /// `ErrorGuaranteed::emit_producing_guarantee` uses this. - fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { + // FIXME(nnethercote) Make private once this moves to diagnostic.rs. + pub(crate) fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { let diag = self.take_diag(); // The only error levels that produce `ErrorGuaranteed` are @@ -168,40 +172,6 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { } } -/// `DiagnosticBuilder` impls `DerefMut`, which allows access to the fields and -/// methods of the embedded `Diagnostic`. However, that doesn't allow method -/// chaining at the `DiagnosticBuilder` level. Each use of this macro defines -/// two builder methods at that level, both of which wrap the equivalent method -/// in `Diagnostic`. -/// - A `&mut self -> &mut Self` method, with the same name as the underlying -/// `Diagnostic` method. It is mostly to modify existing diagnostics, either -/// in a standalone fashion, e.g. `err.code(code)`, or in a chained fashion -/// to make multiple modifications, e.g. `err.code(code).span(span)`. -/// - A `self -> Self` method, which has a `with_` prefix added. -/// It is mostly used in a chained fashion when producing a new diagnostic, -/// e.g. `let err = struct_err(msg).with_code(code)`, or when emitting a new -/// diagnostic , e.g. `struct_err(msg).with_code(code).emit()`. -/// -/// Although the latter method can be used to modify an existing diagnostic, -/// e.g. `err = err.with_code(code)`, this should be avoided because the former -/// method gives shorter code, e.g. `err.code(code)`. -macro_rules! forward { - ( - ($f:ident, $with_f:ident)($($name:ident: $ty:ty),* $(,)?) - ) => { - #[doc = concat!("See [`Diagnostic::", stringify!($f), "()`].")] - pub fn $f(&mut self, $($name: $ty),*) -> &mut Self { - self.diag.as_mut().unwrap().$f($($name),*); - self - } - #[doc = concat!("See [`Diagnostic::", stringify!($f), "()`].")] - pub fn $with_f(mut self, $($name: $ty),*) -> Self { - self.diag.as_mut().unwrap().$f($($name),*); - self - } - }; -} - impl Deref for DiagnosticBuilder<'_, G> { type Target = Diagnostic; @@ -278,135 +248,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { self.downgrade_to_delayed_bug(); self.emit() } - - forward!((span_label, with_span_label)( - span: Span, - label: impl Into, - )); - forward!((span_labels, with_span_labels)( - spans: impl IntoIterator, - label: &str, - )); - forward!((note_expected_found, with_note_expected_found)( - expected_label: &dyn fmt::Display, - expected: DiagnosticStyledString, - found_label: &dyn fmt::Display, - found: DiagnosticStyledString, - )); - forward!((note_expected_found_extra, with_note_expected_found_extra)( - expected_label: &dyn fmt::Display, - expected: DiagnosticStyledString, - found_label: &dyn fmt::Display, - found: DiagnosticStyledString, - expected_extra: &dyn fmt::Display, - found_extra: &dyn fmt::Display, - )); - forward!((note, with_note)( - msg: impl Into, - )); - forward!((note_once, with_note_once)( - msg: impl Into, - )); - forward!((span_note, with_span_note)( - sp: impl Into, - msg: impl Into, - )); - forward!((span_note_once, with_span_note_once)( - sp: impl Into, - msg: impl Into, - )); - forward!((warn, with_warn)( - msg: impl Into, - )); - forward!((span_warn, with_span_warn)( - sp: impl Into, - msg: impl Into, - )); - forward!((help, with_help)( - msg: impl Into, - )); - forward!((help_once, with_help_once)( - msg: impl Into, - )); - forward!((span_help, with_span_help_once)( - sp: impl Into, - msg: impl Into, - )); - forward!((multipart_suggestion, with_multipart_suggestion)( - msg: impl Into, - suggestion: Vec<(Span, String)>, - applicability: Applicability, - )); - forward!((multipart_suggestion_verbose, with_multipart_suggestion_verbose)( - msg: impl Into, - suggestion: Vec<(Span, String)>, - applicability: Applicability, - )); - forward!((tool_only_multipart_suggestion, with_tool_only_multipart_suggestion)( - msg: impl Into, - suggestion: Vec<(Span, String)>, - applicability: Applicability, - )); - forward!((span_suggestion, with_span_suggestion)( - sp: Span, - msg: impl Into, - suggestion: impl ToString, - applicability: Applicability, - )); - forward!((span_suggestions, with_span_suggestions)( - sp: Span, - msg: impl Into, - suggestions: impl IntoIterator, - applicability: Applicability, - )); - forward!((multipart_suggestions, with_multipart_suggestions)( - msg: impl Into, - suggestions: impl IntoIterator>, - applicability: Applicability, - )); - forward!((span_suggestion_short, with_span_suggestion_short)( - sp: Span, - msg: impl Into, - suggestion: impl ToString, - applicability: Applicability, - )); - forward!((span_suggestion_verbose, with_span_suggestion_verbose)( - sp: Span, - msg: impl Into, - suggestion: impl ToString, - applicability: Applicability, - )); - forward!((span_suggestion_hidden, with_span_suggestion_hidden)( - sp: Span, - msg: impl Into, - suggestion: impl ToString, - applicability: Applicability, - )); - forward!((tool_only_span_suggestion, with_tool_only_span_suggestion)( - sp: Span, - msg: impl Into, - suggestion: impl ToString, - applicability: Applicability, - )); - forward!((primary_message, with_primary_message)( - msg: impl Into, - )); - forward!((span, with_span)( - sp: impl Into, - )); - forward!((is_lint, with_is_lint)( - name: String, has_future_breakage: bool, - )); - forward!((code, with_code)( - code: ErrCode, - )); - forward!((arg, with_arg)( - name: impl Into>, arg: impl IntoDiagnosticArg, - )); - forward!((subdiagnostic, with_subdiagnostic)( - dcx: &DiagCtxt, - subdiagnostic: impl crate::AddToDiagnostic, - )); } impl Debug for DiagnosticBuilder<'_, G> { diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index eaf75539f59..bc1e81642ff 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -299,7 +299,11 @@ pub struct SingleLabelManySpans { pub label: &'static str, } impl AddToDiagnostic for SingleLabelManySpans { - fn add_to_diagnostic_with(self, diag: &mut crate::Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _: F, + ) { diag.span_labels(self.spans, self.label); } } @@ -312,23 +316,6 @@ pub struct ExpectedLifetimeParameter { pub count: usize, } -#[derive(Subdiagnostic)] -#[note(errors_delayed_at_with_newline)] -pub struct DelayedAtWithNewline { - #[primary_span] - pub span: Span, - pub emitted_at: DiagnosticLocation, - pub note: Backtrace, -} -#[derive(Subdiagnostic)] -#[note(errors_delayed_at_without_newline)] -pub struct DelayedAtWithoutNewline { - #[primary_span] - pub span: Span, - pub emitted_at: DiagnosticLocation, - pub note: Backtrace, -} - impl IntoDiagnosticArg for DiagnosticLocation { fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::from(self.to_string())) @@ -341,13 +328,6 @@ impl IntoDiagnosticArg for Backtrace { } } -#[derive(Subdiagnostic)] -#[note(errors_invalid_flushed_delayed_diagnostic_level)] -pub struct InvalidFlushedDelayedDiagnosticLevel { - #[primary_span] - pub span: Span, - pub level: Level, -} impl IntoDiagnosticArg for Level { fn into_diagnostic_arg(self) -> DiagnosticArgValue { DiagnosticArgValue::Str(Cow::from(self.to_string())) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index e09c041c1d0..df94b69004b 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -599,7 +599,7 @@ impl Emitter for SilentEmitter { fn emit_diagnostic(&mut self, mut diag: Diagnostic) { if diag.level == Level::Fatal { - diag.note(self.fatal_note.clone()); + diag.sub(Level::Note, self.fatal_note.clone(), MultiSpan::new()); self.fatal_dcx.emit_diagnostic(diag); } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 8643596b446..73cda64f1cc 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -46,7 +46,7 @@ pub use diagnostic_builder::{ }; pub use diagnostic_impls::{ DiagnosticArgFromDisplay, DiagnosticSymbolList, ExpectedLifetimeParameter, - IndicateAnonymousLifetime, InvalidFlushedDelayedDiagnosticLevel, SingleLabelManySpans, + IndicateAnonymousLifetime, SingleLabelManySpans, }; pub use emitter::ColorConfig; pub use rustc_error_messages::{ @@ -62,7 +62,6 @@ pub use snippet::Style; // See https://github.com/rust-lang/rust/pull/115393. pub use termcolor::{Color, ColorSpec, WriteColor}; -use crate::diagnostic_impls::{DelayedAtWithNewline, DelayedAtWithoutNewline}; use emitter::{is_case_difference, DynEmitter, Emitter, HumanEmitter}; use registry::Registry; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; @@ -1395,9 +1394,8 @@ impl DiagCtxtInner { }; diagnostic.children.extract_if(already_emitted_sub).for_each(|_| {}); if already_emitted { - diagnostic.note( - "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`", - ); + let msg = "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`"; + diagnostic.sub(Level::Note, msg, MultiSpan::new()); } if is_error { @@ -1483,6 +1481,16 @@ impl DiagCtxtInner { self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string() } + fn eagerly_translate_for_subdiag( + &self, + diag: &Diagnostic, + msg: impl Into, + ) -> SubdiagnosticMessage { + let args = diag.args(); + let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); + self.eagerly_translate(msg, args) + } + fn flush_delayed(&mut self) { if self.delayed_bugs.is_empty() { return; @@ -1527,17 +1535,14 @@ impl DiagCtxtInner { if bug.level != DelayedBug { // NOTE(eddyb) not panicking here because we're already producing // an ICE, and the more information the merrier. - let subdiag = InvalidFlushedDelayedDiagnosticLevel { - span: bug.span.primary_span().unwrap(), - level: bug.level, - }; - // FIXME: Cannot use `Diagnostic::subdiagnostic` which takes `DiagCtxt`, but it - // just uses `DiagCtxtInner` functions. - subdiag.add_to_diagnostic_with(&mut bug, |diag, msg| { - let args = diag.args(); - let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); - self.eagerly_translate(msg, args) - }); + // + // We are at the `Diagnostic`/`DiagCtxtInner` level rather than + // the usual `DiagnosticBuilder`/`DiagCtxt` level, so we must + // augment `bug` in a lower-level fashion. + bug.arg("level", bug.level); + let msg = crate::fluent_generated::errors_invalid_flushed_delayed_diagnostic_level; + let msg = self.eagerly_translate_for_subdiag(&bug, msg); // after the `arg` call + bug.sub(Level::Note, msg, bug.span.primary_span().unwrap().into()); } bug.level = Bug; @@ -1571,39 +1576,22 @@ impl DelayedDiagnostic { DelayedDiagnostic { inner: diagnostic, note: backtrace } } - fn decorate(mut self, dcx: &DiagCtxtInner) -> Diagnostic { - // FIXME: Cannot use `Diagnostic::subdiagnostic` which takes `DiagCtxt`, but it - // just uses `DiagCtxtInner` functions. - let subdiag_with = |diag: &mut Diagnostic, msg| { - let args = diag.args(); - let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); - dcx.eagerly_translate(msg, args) - }; - - match self.note.status() { - BacktraceStatus::Captured => { - let inner = &self.inner; - let subdiag = DelayedAtWithNewline { - span: inner.span.primary_span().unwrap_or(DUMMY_SP), - emitted_at: inner.emitted_at.clone(), - note: self.note, - }; - subdiag.add_to_diagnostic_with(&mut self.inner, subdiag_with); - } + fn decorate(self, dcx: &DiagCtxtInner) -> Diagnostic { + // We are at the `Diagnostic`/`DiagCtxtInner` level rather than the + // usual `DiagnosticBuilder`/`DiagCtxt` level, so we must construct + // `diag` in a lower-level fashion. + let mut diag = self.inner; + let msg = match self.note.status() { + BacktraceStatus::Captured => crate::fluent_generated::errors_delayed_at_with_newline, // Avoid the needless newline when no backtrace has been captured, // the display impl should just be a single line. - _ => { - let inner = &self.inner; - let subdiag = DelayedAtWithoutNewline { - span: inner.span.primary_span().unwrap_or(DUMMY_SP), - emitted_at: inner.emitted_at.clone(), - note: self.note, - }; - subdiag.add_to_diagnostic_with(&mut self.inner, subdiag_with); - } - } - - self.inner + _ => crate::fluent_generated::errors_delayed_at_without_newline, + }; + diag.arg("emitted_at", diag.emitted_at.clone()); + diag.arg("note", self.note); + let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); // after the `arg` calls + diag.sub(Level::Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into()); + diag } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 09144523658..3226362ad10 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1176,6 +1176,8 @@ impl<'a> ExtCtxt<'a> { for (span, notes) in self.expansions.iter() { let mut db = self.dcx().create_note(errors::TraceMacro { span: *span }); for note in notes { + // FIXME: make this translatable + #[allow(rustc::untranslatable_diagnostic)] db.note(note.clone()); } db.emit(); diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 781186764fa..435135d1959 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -384,6 +384,7 @@ impl<'a> StripUnconfigured<'a> { ); if attr.is_doc_comment() { + #[allow(rustc::untranslatable_diagnostic)] err.help("`///` is for documentation comments. For a plain comment, use `//`."); } diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 8f31b5801da..b80ecbc9c65 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -10,7 +10,7 @@ use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use rustc_errors::{ErrorGuaranteed, MultiSpan, PResult}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; @@ -509,13 +509,14 @@ impl server::FreeFunctions for Rustc<'_, '_> { } fn emit_diagnostic(&mut self, diagnostic: Diagnostic) { - let mut diag = - rustc_errors::Diagnostic::new(diagnostic.level.to_internal(), diagnostic.message); + let message = rustc_errors::DiagnosticMessage::from(diagnostic.message); + let mut diag: DiagnosticBuilder<'_, rustc_errors::ErrorGuaranteed> = + DiagnosticBuilder::new(&self.sess().dcx, diagnostic.level.to_internal(), message); diag.span(MultiSpan::from_spans(diagnostic.spans)); for child in diagnostic.children { diag.sub(child.level.to_internal(), child.message, MultiSpan::from_spans(child.spans)); } - self.sess().dcx.emit_diagnostic(diag); + diag.emit(); } } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 1af0b75bd23..f609d0f7e8f 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -3,8 +3,8 @@ use std::borrow::Cow; use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, - MultiSpan, SubdiagnosticMessageOp, + codes::*, AddToDiagnostic, Applicability, DiagnosticArgValue, DiagnosticBuilder, + EmissionGuarantee, IntoDiagnosticArg, MultiSpan, SubdiagnosticMessageOp, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -195,7 +195,11 @@ pub struct TypeMismatchFruTypo { } impl AddToDiagnostic for TypeMismatchFruTypo { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { diag.arg("expr", self.expr.as_deref().unwrap_or("NONE")); // Only explain that `a ..b` is a range if it's split up @@ -370,7 +374,11 @@ pub struct RemoveSemiForCoerce { } impl AddToDiagnostic for RemoveSemiForCoerce { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { let mut multispan: MultiSpan = self.semi.into(); multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr); multispan.push_span_label(self.ret, fluent::hir_typeck_remove_semi_for_coerce_ret); @@ -541,8 +549,12 @@ pub enum CastUnknownPointerSub { From(Span), } -impl AddToDiagnostic for CastUnknownPointerSub { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) { +impl rustc_errors::AddToDiagnostic for CastUnknownPointerSub { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { match self { CastUnknownPointerSub::To(span) => { let msg = f(diag, crate::fluent_generated::hir_typeck_label_to); diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 8bfc05d6a96..f29ba70be98 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,7 +1,8 @@ use hir::GenericParamKind; use rustc_errors::{ - codes::*, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, - DiagnosticStyledString, IntoDiagnosticArg, MultiSpan, SubdiagnosticMessageOp, + codes::*, AddToDiagnostic, Applicability, DiagnosticBuilder, DiagnosticMessage, + DiagnosticStyledString, EmissionGuarantee, IntoDiagnosticArg, MultiSpan, + SubdiagnosticMessageOp, }; use rustc_hir as hir; use rustc_hir::FnRetTy; @@ -225,7 +226,11 @@ pub enum RegionOriginNote<'a> { } impl AddToDiagnostic for RegionOriginNote<'_> { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { let mut label_or_note = |span, msg: DiagnosticMessage| { let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); @@ -286,7 +291,11 @@ pub enum LifetimeMismatchLabels { } impl AddToDiagnostic for LifetimeMismatchLabels { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { diag.span_label(param_span, fluent::infer_declared_different); @@ -330,7 +339,11 @@ pub struct AddLifetimeParamsSuggestion<'a> { } impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { let mut mk_suggestion = || { let ( hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. }, @@ -428,7 +441,11 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq { } impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { - fn add_to_diagnostic_with(mut self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + mut self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { self.unmet_requirements .push_span_label(self.binding_span, fluent::infer_msl_introduces_static); diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req); @@ -743,7 +760,11 @@ pub struct ConsiderBorrowingParamHelp { } impl AddToDiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { // Seems like we can't call f() here as Into is required @@ -784,7 +805,11 @@ pub struct DynTraitConstraintSuggestion { } impl AddToDiagnostic for DynTraitConstraintSuggestion { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { let mut multi_span: MultiSpan = vec![self.span].into(); multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label); multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement); @@ -827,7 +852,11 @@ pub struct ReqIntroducedLocations { } impl AddToDiagnostic for ReqIntroducedLocations { - fn add_to_diagnostic_with(mut self, diag: &mut Diagnostic, f: F) { + fn add_to_diagnostic_with>( + mut self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { for sp in self.spans { self.span.push_span_label(sp, fluent::infer_ril_introduced_here); } @@ -846,7 +875,11 @@ pub struct MoreTargeted { } impl AddToDiagnostic for MoreTargeted { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _f: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { diag.code(E0772); diag.primary_message(fluent::infer_more_targeted); diag.arg("ident", self.ident); @@ -1265,7 +1298,11 @@ pub struct SuggestTuplePatternMany { } impl AddToDiagnostic for SuggestTuplePatternMany { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { diag.arg("path", self.path); let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into()); diag.multipart_suggestions( diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index a59a4df7729..c272aa63b08 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -1,6 +1,9 @@ use crate::fluent_generated as fluent; use crate::infer::error_reporting::nice_region_error::find_anon_type; -use rustc_errors::{AddToDiagnostic, Diagnostic, IntoDiagnosticArg, SubdiagnosticMessageOp}; +use rustc_errors::{ + AddToDiagnostic, DiagnosticBuilder, EmissionGuarantee, IntoDiagnosticArg, + SubdiagnosticMessageOp, +}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{symbol::kw, Span}; @@ -160,7 +163,11 @@ impl RegionExplanation<'_> { } impl AddToDiagnostic for RegionExplanation<'_> { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { diag.arg("pref_kind", self.prefix); diag.arg("suff_kind", self.suffix); diag.arg("desc_kind", self.desc.kind); diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 5af2b6daec1..86434002e2c 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -1,3 +1,6 @@ +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_errors::{add_elided_lifetime_in_path_suggestion, DiagnosticBuilder}; use rustc_errors::{Applicability, SuggestionStyle}; diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 21d4b6fa65b..bcff20fc260 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,5 +1,7 @@ use crate::fluent_generated as fluent; -use rustc_errors::{codes::*, AddToDiagnostic, Diagnostic, SubdiagnosticMessageOp}; +use rustc_errors::{ + codes::*, AddToDiagnostic, DiagnosticBuilder, EmissionGuarantee, SubdiagnosticMessageOp, +}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::lint::Level; use rustc_span::{Span, Symbol}; @@ -24,7 +26,11 @@ pub enum OverruledAttributeSub { } impl AddToDiagnostic for OverruledAttributeSub { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { match self { OverruledAttributeSub::DefaultSource { id } => { diag.note(fluent::lint_default_source); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 40fb12b2107..c1a083bde8d 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1062,6 +1062,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { if self.lint_added_lints { let lint = builtin::UNKNOWN_LINTS; let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS); + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] lint_level( self.sess, lint, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c204c67fc1f..e4a7eb1d953 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -5,8 +5,8 @@ use std::num::NonZero; use crate::errors::RequestedLevel; use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, AddToDiagnostic, Applicability, DecorateLint, Diagnostic, DiagnosticBuilder, - DiagnosticMessage, DiagnosticStyledString, SubdiagnosticMessageOp, SuggestionStyle, + codes::*, AddToDiagnostic, Applicability, DecorateLint, DiagnosticBuilder, DiagnosticMessage, + DiagnosticStyledString, EmissionGuarantee, SubdiagnosticMessageOp, SuggestionStyle, }; use rustc_hir::def_id::DefId; use rustc_macros::{LintDiagnostic, Subdiagnostic}; @@ -267,17 +267,21 @@ pub struct SuggestChangingAssocTypes<'a, 'b> { pub ty: &'a rustc_hir::Ty<'b>, } -impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { +impl<'a, 'b> AddToDiagnostic for SuggestChangingAssocTypes<'a, 'b> { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { // Access to associates types should use `::Assoc`, which does not need a // bound. Let's see if this type does that. // We use a HIR visitor to walk the type. use rustc_hir::intravisit::{self, Visitor}; - struct WalkAssocTypes<'a> { - err: &'a mut Diagnostic, + struct WalkAssocTypes<'a, 'b, G: EmissionGuarantee> { + err: &'a mut DiagnosticBuilder<'b, G>, } - impl Visitor<'_> for WalkAssocTypes<'_> { + impl<'a, 'b, G: EmissionGuarantee> Visitor<'_> for WalkAssocTypes<'a, 'b, G> { fn visit_qpath( &mut self, qpath: &rustc_hir::QPath<'_>, @@ -320,7 +324,11 @@ pub struct BuiltinTypeAliasGenericBoundsSuggestion { } impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { diag.multipart_suggestion( fluent::lint_suggestion, self.suggestions, @@ -437,7 +445,11 @@ pub struct BuiltinUnpermittedTypeInitSub { } impl AddToDiagnostic for BuiltinUnpermittedTypeInitSub { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { let mut err = self.err; loop { if let Some(span) = err.span { @@ -488,7 +500,11 @@ pub struct BuiltinClashingExternSub<'a> { } impl AddToDiagnostic for BuiltinClashingExternSub<'_> { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { let mut expected_str = DiagnosticStyledString::new(); expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); let mut found_str = DiagnosticStyledString::new(); @@ -766,7 +782,11 @@ pub struct HiddenUnicodeCodepointsDiagLabels { } impl AddToDiagnostic for HiddenUnicodeCodepointsDiagLabels { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { for (c, span) in self.spans { diag.span_label(span, format!("{c:?}")); } @@ -780,7 +800,11 @@ pub enum HiddenUnicodeCodepointsDiagSub { // Used because of multiple multipart_suggestion and note impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { match self { HiddenUnicodeCodepointsDiagSub::Escape { spans } => { diag.multipart_suggestion_with_style( @@ -928,7 +952,11 @@ pub struct NonBindingLetSub { } impl AddToDiagnostic for NonBindingLetSub { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar; if can_suggest_binding { @@ -1208,7 +1236,11 @@ pub enum NonSnakeCaseDiagSub { } impl AddToDiagnostic for NonSnakeCaseDiagSub { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { match self { NonSnakeCaseDiagSub::Label { span } => { diag.span_label(span, fluent::lint_label); @@ -1401,7 +1433,11 @@ pub enum OverflowingBinHexSign { } impl AddToDiagnostic for OverflowingBinHexSign { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { match self { OverflowingBinHexSign::Positive => { diag.note(fluent::lint_positive_note); diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 3a5f289559e..323614c222f 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -87,9 +87,13 @@ impl SubdiagnosticDeriveBuilder { let f = &self.f; let ret = structure.gen_impl(quote! { gen impl rustc_errors::AddToDiagnostic for @Self { - fn add_to_diagnostic_with<__F>(self, #diag: &mut rustc_errors::Diagnostic, #f: __F) - where - __F: rustc_errors::SubdiagnosticMessageOp, + fn add_to_diagnostic_with<__G, __F>( + self, + #diag: &mut rustc_errors::DiagnosticBuilder<'_, __G>, + #f: __F + ) where + __G: rustc_errors::EmissionGuarantee, + __F: rustc_errors::SubdiagnosticMessageOp<__G>, { #implementation } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index d17bf0cf708..7e0a4fb72d4 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -505,6 +505,8 @@ impl IntoDiagnostic<'_, G> for MultipleCandidates { diag.code(E0464); diag.span(self.span); for (i, candidate) in self.candidates.iter().enumerate() { + // FIXME: make this translatable + #[allow(rustc::untranslatable_diagnostic)] diag.note(format!("candidate #{}: {}", i + 1, candidate.display())); } diag @@ -601,6 +603,8 @@ impl IntoDiagnostic<'_, G> for InvalidMetadataFiles { diag.code(E0786); diag.span(self.span); for crate_rejection in self.crate_rejections { + // FIXME: make this translatable + #[allow(rustc::untranslatable_diagnostic)] diag.note(crate_rejection); } diag diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 0bc5fe6ef89..2a42dae289b 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,7 +1,7 @@ use crate::fluent_generated as fluent; use rustc_errors::DiagnosticArgValue; use rustc_errors::{ - codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, MultiSpan, SubdiagnosticMessageOp, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -420,7 +420,11 @@ pub struct UnsafeNotInheritedLintNote { } impl AddToDiagnostic for UnsafeNotInheritedLintNote { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body); let body_start = self.body_span.shrink_to_lo(); let body_end = self.body_span.shrink_to_hi(); @@ -863,7 +867,11 @@ pub struct Variant { } impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { diag.arg("ty", self.ty); let mut spans = MultiSpan::from(self.adt_def_span); diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index ff4918df9a2..af2d7d4946f 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -87,6 +87,9 @@ pub(crate) struct RequiresUnsafeDetail { } impl RequiresUnsafeDetail { + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] fn add_subdiagnostics(&self, diag: &mut DiagnosticBuilder<'_, G>) { use UnsafetyViolationDetails::*; match self.violation { diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index bd89874b5cc..e4c30679146 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -56,6 +56,7 @@ impl IntoDiagnostic<'_, G> for UnusedGenericParamsHint { // FIXME: I can figure out how to do a label with a fluent string with a fixed message, // or a label with a dynamic value in a hard-coded string, but I haven't figured out // how to combine the two. 😢 + #[allow(rustc::untranslatable_diagnostic)] diag.span_label(span, format!("generic parameter `{name}` is unused")); } diag diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 674f7218ea6..fde67ac089a 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; use rustc_errors::{ - codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, IntoDiagnostic, Level, SubdiagnosticMessageOp, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -1475,7 +1475,11 @@ pub(crate) struct FnTraitMissingParen { } impl AddToDiagnostic for FnTraitMissingParen { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _: F, + ) { diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren); let applicability = if self.machine_applicable { Applicability::MachineApplicable diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 3676eb92a3f..02792491f5e 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -156,9 +156,12 @@ impl<'tcx> CheckConstVisitor<'tcx> { // is a pretty narrow case, however. if tcx.sess.is_nightly_build() { for gate in missing_secondary { - let note = - format!("add `#![feature({gate})]` to the crate attributes to enable",); - err.help(note); + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] + err.help(format!( + "add `#![feature({gate})]` to the crate attributes to enable" + )); } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index a732bdbca51..982def54d30 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -6,9 +6,8 @@ use std::{ use crate::fluent_generated as fluent; use rustc_ast::Label; use rustc_errors::{ - codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, - DiagnosticSymbolList, EmissionGuarantee, IntoDiagnostic, Level, MultiSpan, - SubdiagnosticMessageOp, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, DiagnosticSymbolList, + EmissionGuarantee, IntoDiagnostic, Level, MultiSpan, SubdiagnosticMessageOp, }; use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -1754,7 +1753,11 @@ pub struct UnusedVariableStringInterp { } impl AddToDiagnostic for UnusedVariableStringInterp { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation); diag.multipart_suggestion( crate::fluent_generated::passes_string_interpolation_only_works, diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 2dffdc9846c..27619b74a66 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{AddToDiagnostic, Diagnostic, SubdiagnosticMessageOp}; +use rustc_errors::{AddToDiagnostic, DiagnosticBuilder, EmissionGuarantee, SubdiagnosticMessageOp}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::thir::Pat; use rustc_middle::ty::Ty; @@ -62,7 +62,11 @@ pub struct Overlap<'tcx> { } impl<'tcx> AddToDiagnostic for Overlap<'tcx> { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _: F, + ) { let Overlap { span, range } = self; // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index ef0512bf686..0a330da87b0 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2468,6 +2468,9 @@ pub fn parse_externs( )); let adjusted_name = name.replace('-', "_"); if is_ascii_ident(&adjusted_name) { + // FIXME: make this translatable + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] error.help(format!( "consider replacing the dashes with underscores: `{adjusted_name}`" )); diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 407fff03e15..10911c0d002 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,7 +1,7 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, - EmissionGuarantee, IntoDiagnostic, Level, SubdiagnosticMessageOp, + codes::*, AddToDiagnostic, Applicability, DiagCtxt, DiagnosticBuilder, EmissionGuarantee, + IntoDiagnostic, Level, SubdiagnosticMessageOp, }; use rustc_macros::Diagnostic; use rustc_middle::ty::{self, ClosureKind, PolyTraitRef, Ty}; @@ -102,7 +102,11 @@ pub enum AdjustSignatureBorrow { } impl AddToDiagnostic for AdjustSignatureBorrow { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + _f: F, + ) { match self { AdjustSignatureBorrow::Borrow { to_borrow } => { diag.arg("len", to_borrow.len()); diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index c86362c427c..b355e66b7b1 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -683,7 +683,7 @@ fn indentation(cx: &T, span: Span) -> Option { }) } -/// Convenience extension trait for `Diagnostic`. +/// Convenience extension trait for `DiagnosticBuilder`. pub trait DiagnosticExt { /// Suggests to add an attribute to an item. /// @@ -731,7 +731,7 @@ pub trait DiagnosticExt { fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability); } -impl DiagnosticExt for rustc_errors::Diagnostic { +impl DiagnosticExt for rustc_errors::DiagnosticBuilder<'_, ()> { fn suggest_item_with_attr( &mut self, cx: &T, diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index 5a2099865d6..dcf948d2a88 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -55,8 +55,11 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for TranslatableInIntoDiagn pub struct UntranslatableInAddToDiagnostic; impl AddToDiagnostic for UntranslatableInAddToDiagnostic { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) - { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { diag.note("untranslatable diagnostic"); //~^ ERROR diagnostics should be created using translatable messages } @@ -65,7 +68,11 @@ impl AddToDiagnostic for UntranslatableInAddToDiagnostic { pub struct TranslatableInAddToDiagnostic; impl AddToDiagnostic for TranslatableInAddToDiagnostic { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) { + fn add_to_diagnostic_with>( + self, + diag: &mut DiagnosticBuilder<'_, G>, + f: F, + ) { diag.note(crate::fluent_generated::no_crate_note); } } diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr index 108b7c8ea9c..a69a71bf50e 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr +++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr @@ -11,13 +11,13 @@ LL | #![deny(rustc::untranslatable_diagnostic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:60:14 + --> $DIR/diagnostics.rs:63:14 | LL | diag.note("untranslatable diagnostic"); | ^^^^ error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls - --> $DIR/diagnostics.rs:74:21 + --> $DIR/diagnostics.rs:81:21 | LL | let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example); | ^^^^^^^^^^ @@ -29,13 +29,13 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls - --> $DIR/diagnostics.rs:77:21 + --> $DIR/diagnostics.rs:84:21 | LL | let _diag = dcx.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:77:21 + --> $DIR/diagnostics.rs:84:21 | LL | let _diag = dcx.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index f07b69326b0..0d61e15b0f1 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -8,9 +8,9 @@ LL | arg: NotIntoDiagnosticArg, | ^^^^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg` | = help: normalized in stderr -note: required by a bound in `DiagnosticBuilder::<'a, G>::arg` - --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC - = note: this error originates in the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `rustc_errors::diagnostic::>::arg` + --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied --> $DIR/diagnostic-derive-doc-comment-field.rs:46:10 @@ -22,8 +22,9 @@ LL | arg: NotIntoDiagnosticArg, | ^^^^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg` | = help: normalized in stderr -note: required by a bound in `Diagnostic::arg` +note: required by a bound in `rustc_errors::diagnostic::>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index 6cc6fdfc0eb..856f32fafa0 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -1,8 +1,8 @@ // check-fail // Tests error conditions for specifying diagnostics using #[derive(Diagnostic)] - // normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr" -// normalize-stderr-test "diagnostic_builder\.rs:[0-9]+:[0-9]+" -> "diagnostic_builder.rs:LL:CC" +// normalize-stderr-test "(COMPILER_DIR/.*\.rs):[0-9]+:[0-9]+" -> "$1:LL:CC" + // The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly, // changing the output of this test. Since Diagnostic is strictly internal to the compiler // the test is just ignored on stable and beta: diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index f2dbc718c76..ddbb3c6df26 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -628,9 +628,9 @@ LL | other: Hello, | ^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello` | = help: normalized in stderr -note: required by a bound in `DiagnosticBuilder::<'a, G>::arg` - --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC - = note: this error originates in the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `rustc_errors::diagnostic::>::arg` + --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC + = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 86 previous errors -- cgit 1.4.1-3-g733a5 From 18fdf59bf5fc20d1c651f1d0e1dfae5cf421f685 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Feb 2024 02:58:07 +0000 Subject: Don't use raw parameter types in find_builder_fn --- compiler/rustc_hir_typeck/src/method/suggest.rs | 8 ++++++-- tests/ui/issues/issue-30123.stderr | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 4151298b42f..5aededa62bd 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -34,8 +34,8 @@ use rustc_middle::ty::IsSuggestable; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::DefIdSet; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Symbol; use rustc_span::{edit_distance, ExpnKind, FileName, MacroKind, Span}; +use rustc_span::{Symbol, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote; use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _; @@ -1597,7 +1597,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter) .filter_map(|item| { // Only assoc fns that return `Self`, `Option` or `Result`. - let ret_ty = self.tcx.fn_sig(item.def_id).skip_binder().output(); + let ret_ty = self + .tcx + .fn_sig(item.def_id) + .instantiate(self.tcx, self.fresh_args_for_item(DUMMY_SP, item.def_id)) + .output(); let ret_ty = self.tcx.instantiate_bound_regions_with_erased(ret_ty); let ty::Adt(def, args) = ret_ty.kind() else { return None; diff --git a/tests/ui/issues/issue-30123.stderr b/tests/ui/issues/issue-30123.stderr index cf71a01b58a..c086b45ac9b 100644 --- a/tests/ui/issues/issue-30123.stderr +++ b/tests/ui/issues/issue-30123.stderr @@ -4,6 +4,11 @@ error[E0599]: no function or associated item named `new_undirected` found for st LL | let ug = Graph::::new_undirected(); | ^^^^^^^^^^^^^^ function or associated item not found in `Graph` | +note: if you're trying to build a new `issue_30123_aux::Graph`, consider using `issue_30123_aux::Graph::::new` which returns `issue_30123_aux::Graph<_, _>` + --> $DIR/auxiliary/issue-30123-aux.rs:14:5 + | +LL | pub fn new() -> Self { + | ^^^^^^^^^^^^^^^^^^^^ = note: the function or associated item was found for - `issue_30123_aux::Graph` -- cgit 1.4.1-3-g733a5 From f68682fd484fc219192aa7ccf7bb1d809288df5e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Tue, 20 Feb 2024 08:31:13 +0200 Subject: make "proc-macro derive panicked" translatable --- compiler/rustc_expand/messages.ftl | 4 ++++ compiler/rustc_expand/src/errors.rs | 15 +++++++++++++++ compiler/rustc_expand/src/proc_macro.rs | 13 ++++++++----- 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index cae4df6cd4b..c82a0242c5b 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -114,6 +114,10 @@ expand_only_one_argument = expand_only_one_word = must only be one word +expand_proc_macro_derive_panicked = + proc-macro derive panicked + .help = message: {$message} + expand_proc_macro_derive_tokens = proc-macro derive produced unparsable tokens diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 5bbf4411bc3..299ba8a1fdf 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -392,6 +392,21 @@ pub(crate) struct ProcMacroPanickedHelp { pub message: String, } +#[derive(Diagnostic)] +#[diag(expand_proc_macro_derive_panicked)] +pub(crate) struct ProcMacroDerivePanicked { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub message: Option, +} + +#[derive(Subdiagnostic)] +#[help(expand_help)] +pub(crate) struct ProcMacroDerivePanickedHelp { + pub message: String, +} + #[derive(Diagnostic)] #[diag(expand_custom_attribute_panicked)] pub(crate) struct CustomAttributePanicked { diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 170857e62ff..23caf2f193a 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -147,11 +147,14 @@ impl MultiItemModifier for DeriveProcMacro { match self.client.run(&strategy, server, input, proc_macro_backtrace) { Ok(stream) => stream, Err(e) => { - let mut err = ecx.dcx().struct_span_err(span, "proc-macro derive panicked"); - if let Some(s) = e.as_str() { - err.help(format!("message: {s}")); - } - err.emit(); + ecx.dcx().emit_err({ + errors::ProcMacroDerivePanicked { + span, + message: e.as_str().map(|message| { + errors::ProcMacroDerivePanickedHelp { message: message.into() } + }), + } + }); return ExpandResult::Ready(vec![]); } } -- cgit 1.4.1-3-g733a5 From e54ef0a7ab42f6af8804632b1b5858c606fe1c3c Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Tue, 20 Feb 2024 01:20:00 +0100 Subject: Make --verbose imply -Z write-long-types-to-disk=no When shortening the type it is necessary to take into account the `--verbose` flag, if it is activated, we must always show the entire type and not write it in a file. Fixes: https://github.com/rust-lang/rust/issues/119130 --- compiler/rustc_middle/src/ty/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'compiler') diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 80b763d1469..e15f0378846 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -351,7 +351,7 @@ impl<'tcx> TyCtxt<'tcx> { }) .expect("could not write to `String`"); - if !self.sess.opts.unstable_opts.write_long_types_to_disk { + if !self.sess.opts.unstable_opts.write_long_types_to_disk || self.sess.opts.verbose { return regular; } -- cgit 1.4.1-3-g733a5 From 762febdaf33667995578ec8183a2379e28bb6b40 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Feb 2024 15:43:29 +0000 Subject: Fix stray trait mismatch in resolve_associated_item for AsyncFn --- compiler/rustc_ty_utils/src/instance.rs | 18 +++--------------- tests/ui/async-await/async-fn/auxiliary/block-on.rs | 20 ++++++++++++++++++++ tests/ui/async-await/async-fn/simple.rs | 7 ++++++- 3 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 tests/ui/async-await/async-fn/auxiliary/block-on.rs (limited to 'compiler') diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 5fc93d666ab..3e3bccce47f 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -246,7 +246,7 @@ fn resolve_associated_item<'tcx>( span: tcx.def_span(trait_item_id), }) } - } else if tcx.fn_trait_kind_from_def_id(trait_ref.def_id).is_some() { + } else if let Some(target_kind) = tcx.fn_trait_kind_from_def_id(trait_ref.def_id) { // FIXME: This doesn't check for malformed libcore that defines, e.g., // `trait Fn { fn call_once(&self) { .. } }`. This is mostly for extension // methods. @@ -265,13 +265,7 @@ fn resolve_associated_item<'tcx>( } match *rcvr_args.type_at(0).kind() { ty::Closure(closure_def_id, args) => { - let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap(); - Some(Instance::resolve_closure( - tcx, - closure_def_id, - args, - trait_closure_kind, - )) + Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), @@ -324,13 +318,7 @@ fn resolve_associated_item<'tcx>( } } ty::Closure(closure_def_id, args) => { - let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap(); - Some(Instance::resolve_closure( - tcx, - closure_def_id, - args, - trait_closure_kind, - )) + Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), diff --git a/tests/ui/async-await/async-fn/auxiliary/block-on.rs b/tests/ui/async-await/async-fn/auxiliary/block-on.rs new file mode 100644 index 00000000000..dcb710fc97c --- /dev/null +++ b/tests/ui/async-await/async-fn/auxiliary/block-on.rs @@ -0,0 +1,20 @@ +//@ edition: 2021 + +#![feature(async_closure, noop_waker)] + +use std::future::Future; +use std::pin::pin; +use std::task::*; + +pub fn block_on(fut: impl Future) -> T { + let mut fut = pin!(fut); + // Poll loop, just to test the future... + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match unsafe { fut.as_mut().poll(ctx) } { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs index e2a183a8c0b..21972ba5aef 100644 --- a/tests/ui/async-await/async-fn/simple.rs +++ b/tests/ui/async-await/async-fn/simple.rs @@ -1,8 +1,11 @@ +//@ aux-build:block-on.rs //@ edition: 2021 //@ build-pass #![feature(async_fn_traits)] +extern crate block_on; + use std::ops::AsyncFn; async fn foo() {} @@ -12,5 +15,7 @@ async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 { } fn main() { - let fut = call_asyncly(|x| async move { x + 1 }); + block_on::block_on(async { + call_asyncly(|x| async move { x + 1 }).await; + }); } -- cgit 1.4.1-3-g733a5 From a45d8925b8af132d2dce4e16bd9599b82ddc5659 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Feb 2024 16:53:16 +0100 Subject: Upgrade a `debug_assert` to `assert` --- compiler/rustc_mir_build/src/build/matches/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 2585e731ab0..81a1d3acb06 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1279,10 +1279,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BasicBlock { assert!(candidate.otherwise_block.is_none()); assert!(candidate.pre_binding_block.is_none()); - debug_assert!( - candidate.subcandidates.is_empty(), - "subcandidates should be empty in select_matched_candidates", - ); + assert!(candidate.subcandidates.is_empty()); if let Some(fake_borrows) = fake_borrows { // Insert a borrows of prefixes of places that are bound and are -- cgit 1.4.1-3-g733a5 From 9c8b107955194b80941ce825646bc2f34edc5dd5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Feb 2024 16:09:03 +0000 Subject: Support async trait bounds in macros --- compiler/rustc_parse/messages.ftl | 2 + compiler/rustc_parse/src/errors.rs | 7 ++++ compiler/rustc_parse/src/parser/item.rs | 9 +++++ compiler/rustc_parse/src/parser/ty.rs | 9 +++-- tests/ui/async-await/async-fn/impl-header.rs | 6 ++- tests/ui/async-await/async-fn/impl-header.stderr | 45 +++++++++++++++++++-- ...mbe-async-trait-bound-theoretical-regression.rs | 21 ++++++++++ ...async-trait-bound-theoretical-regression.stderr | 47 ++++++++++++++++++++++ .../async-await/async-fn/trait-bounds-in-macro.rs | 12 ++++++ .../async-fn/trait-bounds-in-macro.stderr | 14 +++++++ tests/ui/parser/bad-recover-kw-after-impl.rs | 4 +- tests/ui/parser/bad-recover-kw-after-impl.stderr | 23 +++++++++++ tests/ui/parser/trait-object-delimiters.rs | 2 +- tests/ui/parser/trait-object-delimiters.stderr | 4 +- ...mbe-const-trait-bound-theoretical-regression.rs | 13 +++--- ...const-trait-bound-theoretical-regression.stderr | 40 ++++++++++++------ 16 files changed, 228 insertions(+), 30 deletions(-) create mode 100644 tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.rs create mode 100644 tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.stderr create mode 100644 tests/ui/async-await/async-fn/trait-bounds-in-macro.rs create mode 100644 tests/ui/async-await/async-fn/trait-bounds-in-macro.stderr create mode 100644 tests/ui/parser/bad-recover-kw-after-impl.stderr (limited to 'compiler') diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 7c2ecf34c17..55baf6f9f2e 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -27,6 +27,8 @@ parse_async_bound_modifier_in_2015 = `async` trait bounds are only allowed in Ru parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015 .label = to use `async fn`, switch to Rust 2018 or later +parse_async_impl = `async` trait implementations are unsupported + parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 2018 or later parse_async_move_order_incorrect = the order of `move` and `async` is incorrect diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index fde67ac089a..2d4447a42c2 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2975,3 +2975,10 @@ pub(crate) struct ArrayIndexInOffsetOf(#[primary_span] pub Span); #[derive(Diagnostic)] #[diag(parse_invalid_offset_of)] pub(crate) struct InvalidOffsetOf(#[primary_span] pub Span); + +#[derive(Diagnostic)] +#[diag(parse_async_impl)] +pub(crate) struct AsyncImpl { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index e7b9076bd3c..71453a88e2c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -562,6 +562,15 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::const_trait_impl, span); } + // Parse stray `impl async Trait` + if (self.token.uninterpolated_span().at_least_rust_2018() + && self.token.is_keyword(kw::Async)) + || self.is_kw_followed_by_ident(kw::Async) + { + self.bump(); + self.dcx().emit_err(errors::AsyncImpl { span: self.prev_token.span }); + } + let polarity = self.parse_polarity(); // Parse both types and traits as a type, then reinterpret if necessary. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index f79f2a813b2..23a92e6dd3d 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -778,9 +778,10 @@ impl<'a> Parser<'a> { || self.check(&token::Not) || self.check(&token::Question) || self.check(&token::Tilde) - || self.check_keyword(kw::Const) || self.check_keyword(kw::For) || self.check(&token::OpenDelim(Delimiter::Parenthesis)) + || self.check_keyword(kw::Const) + || self.check_keyword(kw::Async) } /// Parses a bound according to the grammar: @@ -882,11 +883,13 @@ impl<'a> Parser<'a> { BoundConstness::Never }; - let asyncness = if self.token.span.at_least_rust_2018() && self.eat_keyword(kw::Async) { + let asyncness = if self.token.uninterpolated_span().at_least_rust_2018() + && self.eat_keyword(kw::Async) + { self.sess.gated_spans.gate(sym::async_closure, self.prev_token.span); BoundAsyncness::Async(self.prev_token.span) } else if self.may_recover() - && self.token.span.is_rust_2015() + && self.token.uninterpolated_span().is_rust_2015() && self.is_kw_followed_by_ident(kw::Async) { self.bump(); // eat `async` diff --git a/tests/ui/async-await/async-fn/impl-header.rs b/tests/ui/async-await/async-fn/impl-header.rs index b9ae90292bb..9af5f1f42a9 100644 --- a/tests/ui/async-await/async-fn/impl-header.rs +++ b/tests/ui/async-await/async-fn/impl-header.rs @@ -3,6 +3,10 @@ struct F; impl async Fn<()> for F {} -//~^ ERROR expected type, found keyword `async` +//~^ ERROR `async` trait implementations are unsupported +//~| ERROR the precise format of `Fn`-family traits' type parameters is subject to change +//~| ERROR manual implementations of `Fn` are experimental +//~| ERROR expected a `FnMut()` closure, found `F` +//~| ERROR not all trait items implemented, missing: `call` fn main() {} diff --git a/tests/ui/async-await/async-fn/impl-header.stderr b/tests/ui/async-await/async-fn/impl-header.stderr index 02cb4326242..2fb862af04e 100644 --- a/tests/ui/async-await/async-fn/impl-header.stderr +++ b/tests/ui/async-await/async-fn/impl-header.stderr @@ -1,8 +1,47 @@ -error: expected type, found keyword `async` +error: `async` trait implementations are unsupported --> $DIR/impl-header.rs:5:6 | LL | impl async Fn<()> for F {} - | ^^^^^ expected type + | ^^^^^ -error: aborting due to 1 previous error +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change + --> $DIR/impl-header.rs:5:12 + | +LL | impl async Fn<()> for F {} + | ^^^^^^ + | + = note: see issue #29625 for more information + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0183]: manual implementations of `Fn` are experimental + --> $DIR/impl-header.rs:5:12 + | +LL | impl async Fn<()> for F {} + | ^^^^^^ manual implementations of `Fn` are experimental + | + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error[E0277]: expected a `FnMut()` closure, found `F` + --> $DIR/impl-header.rs:5:23 + | +LL | impl async Fn<()> for F {} + | ^ expected an `FnMut()` closure, found `F` + | + = help: the trait `FnMut<()>` is not implemented for `F` + = note: wrap the `F` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `Fn` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + +error[E0046]: not all trait items implemented, missing: `call` + --> $DIR/impl-header.rs:5:1 + | +LL | impl async Fn<()> for F {} + | ^^^^^^^^^^^^^^^^^^^^^^^ missing `call` in implementation + | + = help: implement the missing item: `fn call(&self, _: ()) -> >::Output { todo!() }` + +error: aborting due to 5 previous errors +Some errors have detailed explanations: E0046, E0183, E0277, E0658. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.rs b/tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.rs new file mode 100644 index 00000000000..abc429772fd --- /dev/null +++ b/tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.rs @@ -0,0 +1,21 @@ +// Demonstrates and records a theoretical regressions / breaking changes caused by the +// introduction of async trait bounds. + +// Setting the edition to 2018 since we don't regress `demo! { dyn async }` in Rust <2018. +//@ edition:2018 + +macro_rules! demo { + ($ty:ty) => { compile_error!("ty"); }; + //~^ ERROR ty + //~| ERROR ty + (impl $c:ident Trait) => {}; + (dyn $c:ident Trait) => {}; +} + +demo! { impl async Trait } +//~^ ERROR async closures are unstable + +demo! { dyn async Trait } +//~^ ERROR async closures are unstable + +fn main() {} diff --git a/tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.stderr b/tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.stderr new file mode 100644 index 00000000000..13b8e72b49d --- /dev/null +++ b/tests/ui/async-await/async-fn/mbe-async-trait-bound-theoretical-regression.stderr @@ -0,0 +1,47 @@ +error: ty + --> $DIR/mbe-async-trait-bound-theoretical-regression.rs:8:19 + | +LL | ($ty:ty) => { compile_error!("ty"); }; + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | demo! { impl async Trait } + | -------------------------- in this macro invocation + | + = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: ty + --> $DIR/mbe-async-trait-bound-theoretical-regression.rs:8:19 + | +LL | ($ty:ty) => { compile_error!("ty"); }; + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | demo! { dyn async Trait } + | ------------------------- in this macro invocation + | + = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: async closures are unstable + --> $DIR/mbe-async-trait-bound-theoretical-regression.rs:15:14 + | +LL | demo! { impl async Trait } + | ^^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: to use an async block, remove the `||`: `async {` + +error[E0658]: async closures are unstable + --> $DIR/mbe-async-trait-bound-theoretical-regression.rs:18:13 + | +LL | demo! { dyn async Trait } + | ^^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: to use an async block, remove the `||`: `async {` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/async-fn/trait-bounds-in-macro.rs b/tests/ui/async-await/async-fn/trait-bounds-in-macro.rs new file mode 100644 index 00000000000..329a1528e8b --- /dev/null +++ b/tests/ui/async-await/async-fn/trait-bounds-in-macro.rs @@ -0,0 +1,12 @@ +//@ edition: 2021 + +macro_rules! x { + ($x:item) => {} +} + +x! { + async fn foo() -> impl async Fn() { } + //~^ ERROR async closures are unstable +} + +fn main() {} diff --git a/tests/ui/async-await/async-fn/trait-bounds-in-macro.stderr b/tests/ui/async-await/async-fn/trait-bounds-in-macro.stderr new file mode 100644 index 00000000000..f68c09737db --- /dev/null +++ b/tests/ui/async-await/async-fn/trait-bounds-in-macro.stderr @@ -0,0 +1,14 @@ +error[E0658]: async closures are unstable + --> $DIR/trait-bounds-in-macro.rs:8:28 + | +LL | async fn foo() -> impl async Fn() { } + | ^^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: to use an async block, remove the `||`: `async {` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/parser/bad-recover-kw-after-impl.rs b/tests/ui/parser/bad-recover-kw-after-impl.rs index 23abceaf493..15c0b377c8a 100644 --- a/tests/ui/parser/bad-recover-kw-after-impl.rs +++ b/tests/ui/parser/bad-recover-kw-after-impl.rs @@ -1,4 +1,4 @@ -//@ check-pass +// This is just `mbe-async-trait-bound-theoretical-regression.rs` in practice. //@ edition:2021 // for the `impl` + keyword test @@ -11,5 +11,7 @@ macro_rules! impl_primitive { } impl_primitive!(impl async); +//~^ ERROR expected identifier, found `` +//~| ERROR async closures are unstable fn main() {} diff --git a/tests/ui/parser/bad-recover-kw-after-impl.stderr b/tests/ui/parser/bad-recover-kw-after-impl.stderr new file mode 100644 index 00000000000..f617cf65498 --- /dev/null +++ b/tests/ui/parser/bad-recover-kw-after-impl.stderr @@ -0,0 +1,23 @@ +error: expected identifier, found `` + --> $DIR/bad-recover-kw-after-impl.rs:13:22 + | +LL | ($ty:ty) => { + | ------ while parsing argument for this `ty` macro fragment +... +LL | impl_primitive!(impl async); + | ^^^^^ expected identifier + +error[E0658]: async closures are unstable + --> $DIR/bad-recover-kw-after-impl.rs:13:22 + | +LL | impl_primitive!(impl async); + | ^^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: to use an async block, remove the `||`: `async {` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs index 84cd16c2796..d6bc629aa11 100644 --- a/tests/ui/parser/trait-object-delimiters.rs +++ b/tests/ui/parser/trait-object-delimiters.rs @@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef)) {} //~ ERROR incorrect parentheses around t fn foo2_no_space(_: &dyn(Drop + AsRef)) {} //~ ERROR incorrect parentheses around trait bounds fn foo3(_: &dyn {Drop + AsRef}) {} //~ ERROR expected parameter name, found `{` -//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `const`, `for`, `~`, lifetime, or path, found `{` +//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{` //~| ERROR at least one trait is required for an object type fn foo4(_: &dyn >) {} //~ ERROR expected identifier, found `<` diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index 2ddb734cee0..2b1f8df991f 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -34,11 +34,11 @@ error: expected parameter name, found `{` LL | fn foo3(_: &dyn {Drop + AsRef}) {} | ^ expected parameter name -error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `const`, `for`, `~`, lifetime, or path, found `{` +error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{` --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef}) {} - | -^ expected one of 11 possible tokens + | -^ expected one of 12 possible tokens | | | help: missing `,` diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs index 99806922ba5..3dcdb0cad94 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs @@ -6,15 +6,16 @@ macro_rules! demo { ($ty:ty) => { compile_error!("ty"); }; - (impl $c:ident) => {}; - (dyn $c:ident) => {}; + //~^ ERROR ty + //~| ERROR ty + (impl $c:ident Trait) => {}; + (dyn $c:ident Trait) => {}; } -demo! { impl const } -//~^ ERROR expected identifier, found `` +demo! { impl const Trait } +//~^ ERROR const trait impls are experimental -demo! { dyn const } +demo! { dyn const Trait } //~^ ERROR const trait impls are experimental -//~| ERROR expected identifier, found `` fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr index fd9184b9dff..f4b401b7386 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr @@ -1,31 +1,45 @@ -error: expected identifier, found `` - --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:13:14 +error: ty + --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:8:19 | LL | ($ty:ty) => { compile_error!("ty"); }; - | ------ while parsing argument for this `ty` macro fragment + | ^^^^^^^^^^^^^^^^^^^^ ... -LL | demo! { impl const } - | ^^^^^ expected identifier +LL | demo! { impl const Trait } + | -------------------------- in this macro invocation + | + = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected identifier, found `` - --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13 +error: ty + --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:8:19 | LL | ($ty:ty) => { compile_error!("ty"); }; - | ------ while parsing argument for this `ty` macro fragment + | ^^^^^^^^^^^^^^^^^^^^ ... -LL | demo! { dyn const } - | ^^^^^ expected identifier +LL | demo! { dyn const Trait } + | ------------------------- in this macro invocation + | + = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: const trait impls are experimental + --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:15:14 + | +LL | demo! { impl const Trait } + | ^^^^^ + | + = note: see issue #67792 for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: const trait impls are experimental - --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13 + --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:18:13 | -LL | demo! { dyn const } +LL | demo! { dyn const Trait } | ^^^^^ | = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From 05ce209d20232f6d933421f8b8ac58d94557a2aa Mon Sep 17 00:00:00 2001 From: León Orell Valerian Liehr Date: Tue, 20 Feb 2024 10:34:51 +0100 Subject: Rename some normalization-related items --- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 32 ++++++++++++++------- compiler/rustc_middle/src/traits/query.rs | 6 ++-- .../rustc_trait_selection/src/traits/normalize.rs | 2 -- .../src/traits/query/normalize.rs | 16 +++++------ .../rustc_traits/src/normalize_projection_ty.rs | 33 +++++++++++----------- 6 files changed, 51 insertions(+), 40 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index c648b2bfe9b..a532635669d 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -47,7 +47,7 @@ macro_rules! arena_types { rustc_middle::traits::query::DropckOutlivesResult<'tcx> > >, - [] normalize_projection_ty: + [] normalize_canonicalized_projection_ty: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::traits::query::NormalizationResult<'tcx> diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5be45c33e11..c931d2e5313 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -31,7 +31,7 @@ use crate::query::plumbing::{ }; use crate::thir; use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalAliasGoal, CanonicalPredicateGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, }; @@ -1931,9 +1931,13 @@ rustc_queries! { arena_cache } - /// Do not call this query directly: invoke `normalize` instead. - query normalize_projection_ty( - goal: CanonicalProjectionGoal<'tcx> + ///

+ /// + /// Do not call this query directly: Invoke `normalize` instead. + /// + ///
+ query normalize_canonicalized_projection_ty( + goal: CanonicalAliasGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution, @@ -1941,9 +1945,13 @@ rustc_queries! { desc { "normalizing `{}`", goal.value.value } } - /// Do not call this query directly: invoke `normalize` instead. - query normalize_weak_ty( - goal: CanonicalProjectionGoal<'tcx> + ///
+ /// + /// Do not call this query directly: Invoke `normalize` instead. + /// + ///
+ query normalize_canonicalized_weak_ty( + goal: CanonicalAliasGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution, @@ -1951,9 +1959,13 @@ rustc_queries! { desc { "normalizing `{}`", goal.value.value } } - /// Do not call this query directly: invoke `normalize` instead. - query normalize_inherent_projection_ty( - goal: CanonicalProjectionGoal<'tcx> + ///
+ /// + /// Do not call this query directly: Invoke `normalize` instead. + /// + ///
+ query normalize_canonicalized_inherent_projection_ty( + goal: CanonicalAliasGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution, diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 61d96cad57d..12e4f70ba57 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -67,7 +67,7 @@ pub mod type_op { } } -pub type CanonicalProjectionGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>; +pub type CanonicalAliasGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>; pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; @@ -177,10 +177,10 @@ pub struct MethodAutoderefBadTy<'tcx> { pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, } -/// Result from the `normalize_projection_ty` query. +/// Result of the `normalize_canonicalized_{{,inherent_}projection,weak}_ty` queries. #[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct NormalizationResult<'tcx> { - /// Result of normalization. + /// Result of the normalization. pub normalized_ty: Ty<'tcx>, } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index ac62f875fb9..f37d917b4a0 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -355,8 +355,6 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx let data = data.fold_with(self); - // FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement` - // here like `ty::Projection`? project::normalize_inherent_projection( self.selcx, self.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 26da065246d..70fd0b7e50b 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -1,6 +1,6 @@ //! Code for the 'normalization' query. This consists of a wrapper //! which folds deeply, invoking the underlying -//! `normalize_projection_ty` query when it encounters projections. +//! `normalize_canonicalized_projection_ty` query when it encounters projections. use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; @@ -271,9 +271,9 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); let result = match kind { - ty::Projection => tcx.normalize_projection_ty(c_data), - ty::Weak => tcx.normalize_weak_ty(c_data), - ty::Inherent => tcx.normalize_inherent_projection_ty(c_data), + ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data), + ty::Weak => tcx.normalize_canonicalized_weak_ty(c_data), + ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data), kind => unreachable!("did not expect {kind:?} due to match arm above"), }?; // We don't expect ambiguity. @@ -308,10 +308,10 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> } else { result.normalized_ty }; - // `tcx.normalize_projection_ty` may normalize to a type that still has - // unevaluated consts, so keep normalizing here if that's the case. - // Similarly, `tcx.normalize_weak_ty` will only unwrap one layer of type - // and we need to continue folding it to reveal the TAIT behind it. + // `tcx.normalize_canonicalized_projection_ty` may normalize to a type that + // still has unevaluated consts, so keep normalizing here if that's the case. + // Similarly, `tcx.normalize_canonicalized_weak_ty` will only unwrap one layer + // of type and we need to continue folding it to reveal the TAIT behind it. if res != ty && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Weak) { diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 94df28a1454..92a19fb9119 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::{ - normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution, + normalize::NormalizationResult, CanonicalAliasGoal, NoSolution, }; use rustc_trait_selection::traits::{ self, FulfillmentErrorCode, ObligationCause, SelectionContext, @@ -13,18 +13,19 @@ use rustc_trait_selection::traits::{ pub(crate) fn provide(p: &mut Providers) { *p = Providers { - normalize_projection_ty, - normalize_weak_ty, - normalize_inherent_projection_ty, + normalize_canonicalized_projection_ty, + normalize_canonicalized_weak_ty, + normalize_canonicalized_inherent_projection_ty, ..*p }; } -fn normalize_projection_ty<'tcx>( +fn normalize_canonicalized_projection_ty<'tcx>( tcx: TyCtxt<'tcx>, - goal: CanonicalProjectionGoal<'tcx>, + goal: CanonicalAliasGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { - debug!("normalize_provider(goal={:#?})", goal); + debug!("normalize_canonicalized_projection_ty(goal={:#?})", goal); + tcx.infer_ctxt().enter_canonical_trait_query( &goal, |ocx, ParamEnvAnd { param_env, value: goal }| { @@ -61,19 +62,19 @@ fn normalize_projection_ty<'tcx>( return Err(NoSolution); } - // FIXME(associated_const_equality): All users of normalize_projection_ty expected - // a type, but there is the possibility it could've been a const now. Maybe change - // it to a Term later? + // FIXME(associated_const_equality): All users of normalize_canonicalized_projection_ty + // expected a type, but there is the possibility it could've been a const now. + // Maybe change it to a Term later? Ok(NormalizationResult { normalized_ty: answer.ty().unwrap() }) }, ) } -fn normalize_weak_ty<'tcx>( +fn normalize_canonicalized_weak_ty<'tcx>( tcx: TyCtxt<'tcx>, - goal: CanonicalProjectionGoal<'tcx>, + goal: CanonicalAliasGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { - debug!("normalize_provider(goal={:#?})", goal); + debug!("normalize_canonicalized_weak_ty(goal={:#?})", goal); tcx.infer_ctxt().enter_canonical_trait_query( &goal, @@ -95,11 +96,11 @@ fn normalize_weak_ty<'tcx>( ) } -fn normalize_inherent_projection_ty<'tcx>( +fn normalize_canonicalized_inherent_projection_ty<'tcx>( tcx: TyCtxt<'tcx>, - goal: CanonicalProjectionGoal<'tcx>, + goal: CanonicalAliasGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { - debug!("normalize_provider(goal={:#?})", goal); + debug!("normalize_canonicalized_inherent_projection_ty(goal={:#?})", goal); tcx.infer_ctxt().enter_canonical_trait_query( &goal, -- cgit 1.4.1-3-g733a5 From 515d805a0e76b57853bf9e929a2e7b084c475824 Mon Sep 17 00:00:00 2001 From: León Orell Valerian Liehr Date: Tue, 20 Feb 2024 12:38:23 +0100 Subject: Introduce expand_weak_alias_tys --- compiler/rustc_middle/src/ty/flags.rs | 5 +- compiler/rustc_middle/src/ty/util.rs | 61 ++++++++++++++++++++++ compiler/rustc_middle/src/ty/visit.rs | 25 ++++----- .../rustc_trait_selection/src/traits/normalize.rs | 20 ++++--- compiler/rustc_type_ir/src/flags.rs | 31 ++++++----- .../constrained-late-bound-regions.rs | 15 ++++++ .../lazy-type-alias/constrained-params-in-impl.rs | 27 ++++++++++ tests/ui/lazy-type-alias/constrained-params.rs | 27 ---------- .../unconstrained-late-bound-regions.rs | 23 ++++++++ .../unconstrained-late-bound-regions.stderr | 22 ++++++++ .../unconstrained-param-due-to-overflow.rs | 8 --- .../unconstrained-param-due-to-overflow.stderr | 9 ---- ...unconstrained-params-in-impl-due-to-overflow.rs | 8 +++ ...nstrained-params-in-impl-due-to-overflow.stderr | 9 ++++ .../unconstrained-params-in-impl.rs | 12 +++++ .../unconstrained-params-in-impl.stderr | 9 ++++ tests/ui/lazy-type-alias/unconstrained-params.rs | 12 ----- .../ui/lazy-type-alias/unconstrained-params.stderr | 9 ---- 18 files changed, 228 insertions(+), 104 deletions(-) create mode 100644 tests/ui/lazy-type-alias/constrained-late-bound-regions.rs create mode 100644 tests/ui/lazy-type-alias/constrained-params-in-impl.rs delete mode 100644 tests/ui/lazy-type-alias/constrained-params.rs create mode 100644 tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs create mode 100644 tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr delete mode 100644 tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs delete mode 100644 tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr create mode 100644 tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.rs create mode 100644 tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr create mode 100644 tests/ui/lazy-type-alias/unconstrained-params-in-impl.rs create mode 100644 tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr delete mode 100644 tests/ui/lazy-type-alias/unconstrained-params.rs delete mode 100644 tests/ui/lazy-type-alias/unconstrained-params.stderr (limited to 'compiler') diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 0f4b5fe228c..18cf5445e56 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -181,9 +181,10 @@ impl FlagComputation { &ty::Alias(kind, data) => { self.add_flags(match kind { - ty::Weak | ty::Projection => TypeFlags::HAS_TY_PROJECTION, - ty::Inherent => TypeFlags::HAS_TY_INHERENT, + 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); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 3f539945841..ff9d1ed6ae9 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -11,6 +11,7 @@ use crate::ty::{GenericArgKind, GenericArgsRef}; use rustc_apfloat::Float as _; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -867,6 +868,30 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param)) } + + /// Expand any [weak alias types][weak] contained within the given `value`. + /// + /// This should be used over other normalization routines in situations where + /// it's important not to normalize other alias types and where the predicates + /// on the corresponding type alias shouldn't be taken into consideration. + /// + /// Whenever possible **prefer not to use this function**! Instead, use standard + /// normalization routines or if feasible don't normalize at all. + /// + /// This function comes in handy if you want to mimic the behavior of eager + /// type alias expansion in a localized manner. + /// + ///
+ /// This delays a bug on overflow! Therefore you need to be certain that the + /// contained types get fully normalized at a later stage. Note that even on + /// overflow all well-behaved weak alias types get expanded correctly, so the + /// result is still useful. + ///
+ /// + /// [weak]: ty::Weak + pub fn expand_weak_alias_tys>>(self, value: T) -> T { + value.fold_with(&mut WeakAliasTypeExpander { tcx: self, depth: 0 }) + } } struct OpaqueTypeExpander<'tcx> { @@ -1002,6 +1027,42 @@ impl<'tcx> TypeFolder> for OpaqueTypeExpander<'tcx> { } } +struct WeakAliasTypeExpander<'tcx> { + tcx: TyCtxt<'tcx>, + depth: usize, +} + +impl<'tcx> TypeFolder> for WeakAliasTypeExpander<'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !ty.has_type_flags(ty::TypeFlags::HAS_TY_WEAK) { + return ty; + } + let ty::Alias(ty::Weak, alias) = ty.kind() else { + return ty.super_fold_with(self); + }; + if !self.tcx.recursion_limit().value_within_limit(self.depth) { + let guar = self.tcx.dcx().delayed_bug("overflow expanding weak alias type"); + return Ty::new_error(self.tcx, guar); + } + + self.depth += 1; + ensure_sufficient_stack(|| { + self.tcx.type_of(alias.def_id).instantiate(self.tcx, alias.args).fold_with(self) + }) + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + if !ct.ty().has_type_flags(ty::TypeFlags::HAS_TY_WEAK) { + return ct; + } + ct.super_fold_with(self) + } +} + impl<'tcx> Ty<'tcx> { /// Returns the `Size` for primitive types (bool, uint, int, char, float). pub fn primitive_size(self, tcx: TyCtxt<'tcx>) -> Size { diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 59292a281ed..1de2ceecae7 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -131,12 +131,13 @@ impl<'tcx> TyCtxt<'tcx> { fn collect_late_bound_regions( self, value: &Binder<'tcx, T>, - just_constraint: bool, + just_constrained: bool, ) -> FxHashSet where T: TypeVisitable>, { - let mut collector = LateBoundRegionsCollector::new(just_constraint); + let mut collector = LateBoundRegionsCollector::new(self, just_constrained); + let value = if just_constrained { self.expand_weak_alias_tys(value) } else { value }; let result = value.as_ref().skip_binder().visit_with(&mut collector); assert!(result.is_continue()); // should never have stopped early collector.regions @@ -258,11 +259,7 @@ struct LateBoundRegionsCollector { impl LateBoundRegionsCollector { fn new(just_constrained: bool) -> Self { - LateBoundRegionsCollector { - current_index: ty::INNERMOST, - regions: Default::default(), - just_constrained, - } + Self { current_index: ty::INNERMOST, regions: Default::default(), just_constrained } } } @@ -278,12 +275,16 @@ impl<'tcx> TypeVisitor> for LateBoundRegionsCollector { } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - // if we are only looking for "constrained" region, we have to - // ignore the inputs to a projection, as they may not appear - // in the normalized form if self.just_constrained { - if let ty::Alias(..) = t.kind() { - return ControlFlow::Continue(()); + match t.kind() { + // If we are only looking for "constrained" regions, we have to ignore the + // inputs to a projection as they may not appear in the normalized form. + ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) => { + return ControlFlow::Continue(()); + } + // All weak alias types should've been expanded beforehand. + ty::Alias(ty::Weak, _) => bug!("unexpected weak alias type"), + _ => {} } } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index f37d917b4a0..429e5a5d7a4 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -101,19 +101,17 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable>>( value: &T, reveal: Reveal, ) -> bool { + let mut flags = ty::TypeFlags::HAS_TY_PROJECTION + | ty::TypeFlags::HAS_TY_WEAK + | ty::TypeFlags::HAS_TY_INHERENT + | ty::TypeFlags::HAS_CT_PROJECTION; + match reveal { - Reveal::UserFacing => value.has_type_flags( - ty::TypeFlags::HAS_TY_PROJECTION - | ty::TypeFlags::HAS_TY_INHERENT - | ty::TypeFlags::HAS_CT_PROJECTION, - ), - Reveal::All => value.has_type_flags( - ty::TypeFlags::HAS_TY_PROJECTION - | ty::TypeFlags::HAS_TY_INHERENT - | ty::TypeFlags::HAS_TY_OPAQUE - | ty::TypeFlags::HAS_CT_PROJECTION, - ), + Reveal::UserFacing => {} + Reveal::All => flags |= ty::TypeFlags::HAS_TY_OPAQUE, } + + value.has_type_flags(flags) } struct AssocTypeNormalizer<'a, 'b, 'tcx> { diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 1da26cfc242..b38ef2ad84d 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -69,32 +69,35 @@ bitflags! { /// Does this have `Projection`? const HAS_TY_PROJECTION = 1 << 10; - /// Does this have `Inherent`? - const HAS_TY_INHERENT = 1 << 11; + /// Does this have `Weak`? + const HAS_TY_WEAK = 1 << 11; /// Does this have `Opaque`? const HAS_TY_OPAQUE = 1 << 12; + /// Does this have `Inherent`? + const HAS_TY_INHERENT = 1 << 13; /// Does this have `ConstKind::Unevaluated`? - const HAS_CT_PROJECTION = 1 << 13; + const HAS_CT_PROJECTION = 1 << 14; /// Could this type be normalized further? const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits() + | TypeFlags::HAS_TY_WEAK.bits() | TypeFlags::HAS_TY_OPAQUE.bits() | TypeFlags::HAS_TY_INHERENT.bits() | TypeFlags::HAS_CT_PROJECTION.bits(); /// Is an error type/const reachable? - const HAS_ERROR = 1 << 14; + const HAS_ERROR = 1 << 15; /// Does this have any region that "appears free" in the type? /// Basically anything but `ReBound` and `ReErased`. - const HAS_FREE_REGIONS = 1 << 15; + const HAS_FREE_REGIONS = 1 << 16; /// Does this have any `ReBound` regions? - const HAS_RE_BOUND = 1 << 16; + const HAS_RE_BOUND = 1 << 17; /// Does this have any `Bound` types? - const HAS_TY_BOUND = 1 << 17; + const HAS_TY_BOUND = 1 << 18; /// Does this have any `ConstKind::Bound` consts? - const HAS_CT_BOUND = 1 << 18; + const HAS_CT_BOUND = 1 << 19; /// Does this have any bound variables? /// Used to check if a global bound is safe to evaluate. const HAS_BOUND_VARS = TypeFlags::HAS_RE_BOUND.bits() @@ -102,22 +105,22 @@ bitflags! { | TypeFlags::HAS_CT_BOUND.bits(); /// Does this have any `ReErased` regions? - const HAS_RE_ERASED = 1 << 19; + const HAS_RE_ERASED = 1 << 20; /// Does this value have parameters/placeholders/inference variables which could be /// replaced later, in a way that would change the results of `impl` specialization? - const STILL_FURTHER_SPECIALIZABLE = 1 << 20; + const STILL_FURTHER_SPECIALIZABLE = 1 << 21; /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`? - const HAS_TY_FRESH = 1 << 21; + const HAS_TY_FRESH = 1 << 22; /// Does this value have `InferConst::Fresh`? - const HAS_CT_FRESH = 1 << 22; + const HAS_CT_FRESH = 1 << 23; /// Does this have `Coroutine` or `CoroutineWitness`? - const HAS_TY_COROUTINE = 1 << 23; + const HAS_TY_COROUTINE = 1 << 24; /// Does this have any binders with bound vars (e.g. that need to be anonymized)? - const HAS_BINDER_VARS = 1 << 24; + const HAS_BINDER_VARS = 1 << 25; } } diff --git a/tests/ui/lazy-type-alias/constrained-late-bound-regions.rs b/tests/ui/lazy-type-alias/constrained-late-bound-regions.rs new file mode 100644 index 00000000000..e759e72d745 --- /dev/null +++ b/tests/ui/lazy-type-alias/constrained-late-bound-regions.rs @@ -0,0 +1,15 @@ +//@ check-pass +// Weak alias types constrain late-bound regions if their normalized form constrains them. + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type Ref<'a> = &'a (); + +type FnPtr = for<'a> fn(Ref<'a>) -> &'a (); // OK +type DynCl = dyn for<'a> Fn(Ref<'a>) -> &'a (); // OK + +fn map0(_: Ref) -> Ref { &() } // OK +fn map1(_: Ref<'_>) -> Ref<'_> { &() } // OK + +fn main() {} diff --git a/tests/ui/lazy-type-alias/constrained-params-in-impl.rs b/tests/ui/lazy-type-alias/constrained-params-in-impl.rs new file mode 100644 index 00000000000..59693dd5461 --- /dev/null +++ b/tests/ui/lazy-type-alias/constrained-params-in-impl.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type Injective = Local; +struct Local(T); + +impl Injective { + fn take(_: T) {} +} + +trait Trait { + type Out; + fn produce() -> Self::Out; +} + +impl Trait for Injective { + type Out = T; + fn produce() -> Self::Out { T::default() } +} + +fn main() { + Injective::take(0); + let _: String = Injective::produce(); + let _: bool = Local::produce(); +} diff --git a/tests/ui/lazy-type-alias/constrained-params.rs b/tests/ui/lazy-type-alias/constrained-params.rs deleted file mode 100644 index 59693dd5461..00000000000 --- a/tests/ui/lazy-type-alias/constrained-params.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ check-pass - -#![feature(lazy_type_alias)] -#![allow(incomplete_features)] - -type Injective = Local; -struct Local(T); - -impl Injective { - fn take(_: T) {} -} - -trait Trait { - type Out; - fn produce() -> Self::Out; -} - -impl Trait for Injective { - type Out = T; - fn produce() -> Self::Out { T::default() } -} - -fn main() { - Injective::take(0); - let _: String = Injective::produce(); - let _: bool = Local::produce(); -} diff --git a/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs new file mode 100644 index 00000000000..844570e22d2 --- /dev/null +++ b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs @@ -0,0 +1,23 @@ +// Weak alias types only constrain late-bound regions if their normalized form constrains them. + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type NotInjective<'a> = <() as Discard>::Output<'a>; + +type FnPtr0 = for<'a> fn(NotInjective<'a>) -> &'a (); +//~^ ERROR references lifetime `'a`, which is not constrained by the fn input types +type FnPtr1 = for<'a> fn(NotInjectiveEither<'a, ()>) -> NotInjectiveEither<'a, ()>; +//~^ ERROR references lifetime `'a`, which is not constrained by the fn input types +type DynCl = dyn for<'a> Fn(NotInjective<'a>) -> &'a (); +//~^ ERROR references lifetime `'a`, which does not appear in the trait input types + +trait Discard { type Output<'a>; } +impl Discard for () { type Output<'_a> = (); } + +type NotInjectiveEither<'a, Linchpin> = Linchpin +where + Linchpin: Fn() -> &'a (); + + +fn main() {} diff --git a/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr new file mode 100644 index 00000000000..241c7761c60 --- /dev/null +++ b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr @@ -0,0 +1,22 @@ +error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types + --> $DIR/unconstrained-late-bound-regions.rs:8:47 + | +LL | type FnPtr0 = for<'a> fn(NotInjective<'a>) -> &'a (); + | ^^^^^^ + +error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types + --> $DIR/unconstrained-late-bound-regions.rs:10:57 + | +LL | type FnPtr1 = for<'a> fn(NotInjectiveEither<'a, ()>) -> NotInjectiveEither<'a, ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/unconstrained-late-bound-regions.rs:12:50 + | +LL | type DynCl = dyn for<'a> Fn(NotInjective<'a>) -> &'a (); + | ^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0581, E0582. +For more information about an error, try `rustc --explain E0581`. diff --git a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs b/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs deleted file mode 100644 index eceefa719ec..00000000000 --- a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(lazy_type_alias)] -#![allow(incomplete_features)] - -impl Loop {} //~ ERROR the type parameter `T` is not constrained - -type Loop = Loop; - -fn main() {} diff --git a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr b/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr deleted file mode 100644 index 9af6f5dda0b..00000000000 --- a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/unconstrained-param-due-to-overflow.rs:4:6 - | -LL | impl Loop {} - | ^ unconstrained type parameter - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.rs b/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.rs new file mode 100644 index 00000000000..eceefa719ec --- /dev/null +++ b/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.rs @@ -0,0 +1,8 @@ +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +impl Loop {} //~ ERROR the type parameter `T` is not constrained + +type Loop = Loop; + +fn main() {} diff --git a/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr b/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr new file mode 100644 index 00000000000..b65c84226ce --- /dev/null +++ b/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-params-in-impl-due-to-overflow.rs:4:6 + | +LL | impl Loop {} + | ^ unconstrained type parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/lazy-type-alias/unconstrained-params-in-impl.rs b/tests/ui/lazy-type-alias/unconstrained-params-in-impl.rs new file mode 100644 index 00000000000..d58938b3070 --- /dev/null +++ b/tests/ui/lazy-type-alias/unconstrained-params-in-impl.rs @@ -0,0 +1,12 @@ +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +impl NotInjective {} //~ ERROR the type parameter `T` is not constrained + +type NotInjective = Local<::Out>; +struct Local(T); + +trait Discard { type Out; } +impl Discard for T { type Out = (); } + +fn main() {} diff --git a/tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr b/tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr new file mode 100644 index 00000000000..2419c78cba8 --- /dev/null +++ b/tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-params-in-impl.rs:4:6 + | +LL | impl NotInjective {} + | ^ unconstrained type parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/lazy-type-alias/unconstrained-params.rs b/tests/ui/lazy-type-alias/unconstrained-params.rs deleted file mode 100644 index d58938b3070..00000000000 --- a/tests/ui/lazy-type-alias/unconstrained-params.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![feature(lazy_type_alias)] -#![allow(incomplete_features)] - -impl NotInjective {} //~ ERROR the type parameter `T` is not constrained - -type NotInjective = Local<::Out>; -struct Local(T); - -trait Discard { type Out; } -impl Discard for T { type Out = (); } - -fn main() {} diff --git a/tests/ui/lazy-type-alias/unconstrained-params.stderr b/tests/ui/lazy-type-alias/unconstrained-params.stderr deleted file mode 100644 index 3c52a06c319..00000000000 --- a/tests/ui/lazy-type-alias/unconstrained-params.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/unconstrained-params.rs:4:6 - | -LL | impl NotInjective {} - | ^ unconstrained type parameter - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0207`. -- cgit 1.4.1-3-g733a5 From da01cced15b1a59e5eb40bdf5bb0be9a143d4e5a Mon Sep 17 00:00:00 2001 From: León Orell Valerian Liehr Date: Tue, 20 Feb 2024 13:50:39 +0100 Subject: Expand weak alias types before collecting constrained and referenced late bound regions --- compiler/rustc_hir_analysis/src/astconv/bounds.rs | 4 ++-- compiler/rustc_hir_analysis/src/astconv/mod.rs | 4 ++-- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../infer/error_reporting/nice_region_error/util.rs | 6 +++--- compiler/rustc_middle/src/ty/visit.rs | 18 ++++++++++-------- src/librustdoc/clean/auto_trait.rs | 17 ++++++++--------- 6 files changed, 26 insertions(+), 25 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 6940b4a5045..6d8a5bc0e90 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -454,9 +454,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { // for<'a> ::Item = &'a str // <-- 'a is bad // for<'a> >::Output = &'a str // <-- 'a is ok let late_bound_in_projection_ty = - tcx.collect_constrained_late_bound_regions(&projection_ty); + tcx.collect_constrained_late_bound_regions(projection_ty); let late_bound_in_term = - tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(term)); + tcx.collect_referenced_late_bound_regions(trait_ref.rebind(term)); debug!(?late_bound_in_projection_ty); debug!(?late_bound_in_term); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 296b63a8292..997392b6c4a 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2678,9 +2678,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // for<'a> fn(&'a String) -> &'a str <-- 'a is ok let inputs = bare_fn_ty.inputs(); let late_bound_in_args = - tcx.collect_constrained_late_bound_regions(&inputs.map_bound(|i| i.to_owned())); + tcx.collect_constrained_late_bound_regions(inputs.map_bound(|i| i.to_owned())); let output = bare_fn_ty.output(); - let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); + let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(output); self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { struct_span_code_err!( diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index cffb88a1365..6a42fdb1079 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -520,7 +520,7 @@ fn get_new_lifetime_name<'tcx>( generics: &hir::Generics<'tcx>, ) -> String { let existing_lifetimes = tcx - .collect_referenced_late_bound_regions(&poly_trait_ref) + .collect_referenced_late_bound_regions(poly_trait_ref) .into_iter() .filter_map(|lt| { if let ty::BoundRegionKind::BrNamed(_, name) = lt { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index bfff00b948e..f1f8314661f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -5,7 +5,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::TyCtxt; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::{self, Binder, Region, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Binder, Region, Ty, TypeFoldable}; use rustc_span::Span; /// Information about the anonymous region we are searching for. @@ -142,10 +142,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { fn includes_region( &self, - ty: Binder<'tcx, impl TypeVisitable>>, + ty: Binder<'tcx, impl TypeFoldable>>, region: ty::BoundRegionKind, ) -> bool { - let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty); + let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(ty); // We are only checking is any region meets the condition so order doesn't matter #[allow(rustc::potential_query_instability)] late_bound_regions.iter().any(|r| *r == region) diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 1de2ceecae7..59d09c3dc78 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -2,6 +2,7 @@ use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; +use rustc_type_ir::fold::TypeFoldable; use std::ops::ControlFlow; pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; @@ -109,10 +110,10 @@ impl<'tcx> TyCtxt<'tcx> { /// variables will also be equated. pub fn collect_constrained_late_bound_regions( self, - value: &Binder<'tcx, T>, + value: Binder<'tcx, T>, ) -> FxHashSet where - T: TypeVisitable>, + T: TypeFoldable>, { self.collect_late_bound_regions(value, true) } @@ -120,25 +121,26 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns a set of all late-bound regions that appear in `value` anywhere. pub fn collect_referenced_late_bound_regions( self, - value: &Binder<'tcx, T>, + value: Binder<'tcx, T>, ) -> FxHashSet where - T: TypeVisitable>, + T: TypeFoldable>, { self.collect_late_bound_regions(value, false) } fn collect_late_bound_regions( self, - value: &Binder<'tcx, T>, + value: Binder<'tcx, T>, just_constrained: bool, ) -> FxHashSet where - T: TypeVisitable>, + T: TypeFoldable>, { - let mut collector = LateBoundRegionsCollector::new(self, just_constrained); + let mut collector = LateBoundRegionsCollector::new(just_constrained); + let value = value.skip_binder(); let value = if just_constrained { self.expand_weak_alias_tys(value) } else { value }; - let result = value.as_ref().skip_binder().visit_with(&mut collector); + let result = value.visit_with(&mut collector); assert!(result.is_continue()); // should never have stopped early collector.regions } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 8cc4201c3fc..fbc2c3c5af4 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -318,15 +318,14 @@ where fn extract_for_generics(&self, pred: ty::Clause<'tcx>) -> FxHashSet { let bound_predicate = pred.kind(); let tcx = self.cx.tcx; - let regions = match bound_predicate.skip_binder() { - ty::ClauseKind::Trait(poly_trait_pred) => { - tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred)) - } - ty::ClauseKind::Projection(poly_proj_pred) => { - tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred)) - } - _ => return FxHashSet::default(), - }; + let regions = + match bound_predicate.skip_binder() { + ty::ClauseKind::Trait(poly_trait_pred) => tcx + .collect_referenced_late_bound_regions(bound_predicate.rebind(poly_trait_pred)), + ty::ClauseKind::Projection(poly_proj_pred) => tcx + .collect_referenced_late_bound_regions(bound_predicate.rebind(poly_proj_pred)), + _ => return FxHashSet::default(), + }; regions .into_iter() -- cgit 1.4.1-3-g733a5 From 1b3df6f068cb676486c511890148dbb7981b62b1 Mon Sep 17 00:00:00 2001 From: León Orell Valerian Liehr Date: Tue, 20 Feb 2024 14:29:50 +0100 Subject: Use expand_weak_alias_tys when collecting constrained generics params in impls --- .../src/constrained_generic_params.rs | 53 ++++++++-------------- compiler/rustc_hir_analysis/src/impl_wf_check.rs | 2 +- .../src/impl_wf_check/min_specialization.rs | 10 ++-- 3 files changed, 25 insertions(+), 40 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 4ce43bb4887..b8de2e46934 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -1,8 +1,8 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; +use rustc_type_ir::fold::TypeFoldable; use std::ops::ControlFlow; #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -33,62 +33,47 @@ pub fn parameters_for_impl<'tcx>( impl_trait_ref: Option>, ) -> FxHashSet { let vec = match impl_trait_ref { - Some(tr) => parameters_for(tcx, &tr, false), - None => parameters_for(tcx, &impl_self_ty, false), + Some(tr) => parameters_for(tcx, tr, false), + None => parameters_for(tcx, impl_self_ty, false), }; vec.into_iter().collect() } /// If `include_nonconstraining` is false, returns the list of parameters that are -/// constrained by `t` - i.e., the value of each parameter in the list is -/// uniquely determined by `t` (see RFC 447). If it is true, return the list -/// of parameters whose values are needed in order to constrain `ty` - these +/// constrained by `value` - i.e., the value of each parameter in the list is +/// uniquely determined by `value` (see RFC 447). If it is true, return the list +/// of parameters whose values are needed in order to constrain `value` - these /// differ, with the latter being a superset, in the presence of projections. pub fn parameters_for<'tcx>( tcx: TyCtxt<'tcx>, - t: &impl TypeVisitable>, + value: impl TypeFoldable>, include_nonconstraining: bool, ) -> Vec { - let mut collector = - ParameterCollector { tcx, parameters: vec![], include_nonconstraining, depth: 0 }; - t.visit_with(&mut collector); + let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining }; + let value = if !include_nonconstraining { tcx.expand_weak_alias_tys(value) } else { value }; + value.visit_with(&mut collector); collector.parameters } -struct ParameterCollector<'tcx> { - tcx: TyCtxt<'tcx>, +struct ParameterCollector { parameters: Vec, include_nonconstraining: bool, - depth: usize, } -impl<'tcx> TypeVisitor> for ParameterCollector<'tcx> { +impl<'tcx> TypeVisitor> for ParameterCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { + // Projections are not injective in general. ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) if !self.include_nonconstraining => { - // Projections are not injective in general. return ControlFlow::Continue(()); } - ty::Alias(ty::Weak, alias) if !self.include_nonconstraining => { - if !self.tcx.recursion_limit().value_within_limit(self.depth) { - // Other constituent types may still constrain some generic params, consider - // ` (Overflow, T)` for example. Therefore we want to continue instead of - // breaking. Only affects diagnostics. - return ControlFlow::Continue(()); - } - self.depth += 1; - return ensure_sufficient_stack(|| { - self.tcx - .type_of(alias.def_id) - .instantiate(self.tcx, alias.args) - .visit_with(self) - }); - } - ty::Param(data) => { - self.parameters.push(Parameter::from(data)); + // All weak alias types should've been expanded beforehand. + ty::Alias(ty::Weak, _) if !self.include_nonconstraining => { + bug!("unexpected weak alias type") } + ty::Param(param) => self.parameters.push(Parameter::from(param)), _ => {} } @@ -224,12 +209,12 @@ pub fn setup_constraining_predicates<'tcx>( // `<::Baz as Iterator>::Output = ::Output` // Then the projection only applies if `T` is known, but it still // does not determine `U`. - let inputs = parameters_for(tcx, &projection.projection_ty, true); + let inputs = parameters_for(tcx, projection.projection_ty, true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p)); if !relies_only_on_inputs { continue; } - input_parameters.extend(parameters_for(tcx, &projection.term, false)); + input_parameters.extend(parameters_for(tcx, projection.term, false)); } else { continue; } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index b4cec1d9882..9d7866fe3e0 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -111,7 +111,7 @@ fn enforce_impl_params_are_constrained( match item.kind { ty::AssocKind::Type => { if item.defaultness(tcx).has_value() { - cgp::parameters_for(tcx, &tcx.type_of(def_id).instantiate_identity(), true) + cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true) } else { vec![] } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index bd4fce81377..be1be1a1354 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -133,7 +133,7 @@ fn check_always_applicable( res = res.and(check_constness(tcx, impl1_def_id, impl2_node, span)); res = res.and(check_static_lifetimes(tcx, &parent_args, span)); - res = res.and(check_duplicate_params(tcx, impl1_args, &parent_args, span)); + res = res.and(check_duplicate_params(tcx, impl1_args, parent_args, span)); res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span)); res @@ -266,15 +266,15 @@ fn unconstrained_parent_impl_args<'tcx>( continue; } - unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true)); + unconstrained_parameters.extend(cgp::parameters_for(tcx, projection_ty, true)); - for param in cgp::parameters_for(tcx, &projected_ty, false) { + for param in cgp::parameters_for(tcx, projected_ty, false) { if !unconstrained_parameters.contains(¶m) { constrained_params.insert(param.0); } } - unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true)); + unconstrained_parameters.extend(cgp::parameters_for(tcx, projected_ty, true)); } } @@ -309,7 +309,7 @@ fn unconstrained_parent_impl_args<'tcx>( fn check_duplicate_params<'tcx>( tcx: TyCtxt<'tcx>, impl1_args: GenericArgsRef<'tcx>, - parent_args: &Vec>, + parent_args: Vec>, span: Span, ) -> Result<(), ErrorGuaranteed> { let mut base_params = cgp::parameters_for(tcx, parent_args, true); -- cgit 1.4.1-3-g733a5 From f515f99e9149b1f9c8d247b1d0fd543b1cd1fd37 Mon Sep 17 00:00:00 2001 From: León Orell Valerian Liehr Date: Tue, 20 Feb 2024 15:08:15 +0100 Subject: Move the peeling function for weak alias types --- .../src/coherence/inherent_impls.rs | 29 +------------------ compiler/rustc_middle/src/ty/util.rs | 33 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 28 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 4823472cf96..32f31201254 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -144,7 +144,7 @@ impl<'tcx> InherentCollect<'tcx> { let id = id.owner_id.def_id; let item_span = self.tcx.def_span(id); let self_ty = self.tcx.type_of(id).instantiate_identity(); - let self_ty = peel_off_weak_aliases(self.tcx, self_ty); + let self_ty = self.tcx.peel_off_weak_alias_tys(self_ty); match *self_ty.kind() { ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()), ty::Foreign(did) => self.check_def_id(id, self_ty, did), @@ -186,30 +186,3 @@ impl<'tcx> InherentCollect<'tcx> { } } } - -/// Peel off all weak alias types in this type until there are none left. -/// -///
-/// -/// This assumes that `ty` gets normalized later and that any overflows occurring -/// during said normalization get reported. -/// -///
-fn peel_off_weak_aliases<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> { - let ty::Alias(ty::Weak, _) = ty.kind() else { return ty }; - - let limit = tcx.recursion_limit(); - let mut depth = 0; - - while let ty::Alias(ty::Weak, alias) = ty.kind() { - if !limit.value_within_limit(depth) { - let guar = tcx.dcx().delayed_bug("overflow expanding weak alias type"); - return Ty::new_error(tcx, guar); - } - - ty = tcx.type_of(alias.def_id).instantiate(tcx, alias.args); - depth += 1; - } - - ty -} diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index ff9d1ed6ae9..72a1905c147 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -892,6 +892,39 @@ impl<'tcx> TyCtxt<'tcx> { pub fn expand_weak_alias_tys>>(self, value: T) -> T { value.fold_with(&mut WeakAliasTypeExpander { tcx: self, depth: 0 }) } + + /// Peel off all [weak alias types] in this type until there are none left. + /// + /// This only expands weak alias types in “head” / outermost positions. It can + /// be used over [expand_weak_alias_tys] as an optimization in situations where + /// one only really cares about the *kind* of the final aliased type but not + /// the types the other constituent types alias. + /// + ///
+ /// This delays a bug on overflow! Therefore you need to be certain that the + /// type gets fully normalized at a later stage. + ///
+ /// + /// [weak]: ty::Weak + /// [expand_weak_alias_tys]: Self::expand_weak_alias_tys + pub fn peel_off_weak_alias_tys(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + let ty::Alias(ty::Weak, _) = ty.kind() else { return ty }; + + let limit = self.recursion_limit(); + let mut depth = 0; + + while let ty::Alias(ty::Weak, alias) = ty.kind() { + if !limit.value_within_limit(depth) { + let guar = self.dcx().delayed_bug("overflow expanding weak alias type"); + return Ty::new_error(self, guar); + } + + ty = self.type_of(alias.def_id).instantiate(self, alias.args); + depth += 1; + } + + ty + } } struct OpaqueTypeExpander<'tcx> { -- cgit 1.4.1-3-g733a5 From 4d386d9f049da498b5f072b6c358a6fbbe0baf59 Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" Date: Tue, 20 Feb 2024 11:35:13 +0000 Subject: Downgrade ambiguous_wide_pointer_comparisons suggestions to MaybeIncorrect It is possible to have more than one valid suggestion, which when applied together via rustfix causes the code to no longer compile. This is a temporary workaround; the real long term solution to these issues is to solve . --- compiler/rustc_lint/src/lints.rs | 9 ++++++--- ...mbiguous_wide_pointer_comparisons_suggestions.fixed | 13 +++++++++++++ .../ambiguous_wide_pointer_comparisons_suggestions.rs | 13 +++++++++++++ ...biguous_wide_pointer_comparisons_suggestions.stderr | 18 ++++++++++++++++++ 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.fixed create mode 100644 tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.rs create mode 100644 tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.stderr (limited to 'compiler') diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c204c67fc1f..71107be206b 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1543,7 +1543,8 @@ pub enum AmbiguousWidePointerComparisons<'a> { #[multipart_suggestion( lint_addr_metadata_suggestion, style = "verbose", - applicability = "machine-applicable" + // FIXME(#53934): make machine-applicable again + applicability = "maybe-incorrect" )] pub struct AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a> { pub ne: &'a str, @@ -1562,7 +1563,8 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> { #[multipart_suggestion( lint_addr_suggestion, style = "verbose", - applicability = "machine-applicable" + // FIXME(#53934): make machine-applicable again + applicability = "maybe-incorrect" )] AddrEq { ne: &'a str, @@ -1578,7 +1580,8 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> { #[multipart_suggestion( lint_addr_suggestion, style = "verbose", - applicability = "machine-applicable" + // FIXME(#53934): make machine-applicable again + applicability = "maybe-incorrect" )] Cast { deref_left: &'a str, diff --git a/tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.fixed b/tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.fixed new file mode 100644 index 00000000000..6ce68ff9640 --- /dev/null +++ b/tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.fixed @@ -0,0 +1,13 @@ +//@ run-rustfix +//@ rustfix-only-machine-applicable +//@ check-pass + +// See . + +fn cmp(a: *mut T, b: *mut T) -> bool { + let _ = a == b; + //~^ WARN ambiguous wide pointer comparison + panic!(); +} + +fn main() {} diff --git a/tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.rs b/tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.rs new file mode 100644 index 00000000000..6ce68ff9640 --- /dev/null +++ b/tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.rs @@ -0,0 +1,13 @@ +//@ run-rustfix +//@ rustfix-only-machine-applicable +//@ check-pass + +// See . + +fn cmp(a: *mut T, b: *mut T) -> bool { + let _ = a == b; + //~^ WARN ambiguous wide pointer comparison + panic!(); +} + +fn main() {} diff --git a/tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.stderr b/tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.stderr new file mode 100644 index 00000000000..d9190dbb813 --- /dev/null +++ b/tests/ui/lint/ambiguous_wide_pointer_comparisons_suggestions.stderr @@ -0,0 +1,18 @@ +warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected + --> $DIR/ambiguous_wide_pointer_comparisons_suggestions.rs:8:13 + | +LL | let _ = a == b; + | ^^^^^^ + | + = note: `#[warn(ambiguous_wide_pointer_comparisons)]` on by default +help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses + | +LL | let _ = std::ptr::addr_eq(a, b); + | ++++++++++++++++++ ~ + +help: use explicit `std::ptr::eq` method to compare metadata and addresses + | +LL | let _ = std::ptr::eq(a, b); + | +++++++++++++ ~ + + +warning: 1 warning emitted + -- cgit 1.4.1-3-g733a5 From 6181f3a566b62d8a16d1c8c7318b54f84c3f32d2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 2 Feb 2024 13:26:18 -0800 Subject: wasm: Store rlib metadata in wasm object files The goal of this commit is to remove warnings using LLVM tip-of-tree `wasm-ld`. In llvm/llvm-project#78658 the `wasm-ld` LLD driver no longer looks at archive indices and instead looks at all the objects in archives. Previously `lib.rmeta` files were simply raw rustc metadata bytes, not wasm objects, meaning that `wasm-ld` would emit a warning indicating so. WebAssembly targets previously passed `--fatal-warnings` to `wasm-ld` by default which meant that if Rust were to update to LLVM 18 then all wasm targets would not work. This immediate blocker was resolved in rust-lang/rust#120278 which removed `--fatal-warnings` which enabled a theoretical update to LLVM 18 for wasm targets. This current state is ok-enough for now because rustc squashes all linker output by default if it doesn't fail. This means, for example, that rustc squashes all the linker warnings coming out of `wasm-ld` about `lib.rmeta` files with LLVM 18. This again isn't a pressing issue because the information is all hidden, but it runs the risk of being annoying if another linker error were to happen and then the output would have all these unrelated warnings that couldn't be fixed. Thus, this PR comes into the picture. The goal of this PR is to resolve these warnings by using the WebAssembly object file format on wasm targets instead of using raw rustc metadata. When I first implemented the rlib-in-objects scheme in #84449 I remember either concluding that `wasm-ld` would either include the metadata in the output or I thought we didn't have to do anything there at all. I think I was wrong on both counts as `wasm-ld` does not include the metadata in the final output unless the object is referenced and we do actually need to do something to resolve these warnings. This PR updates the object file format containing rustc metadata on WebAssembly targets to be an actual WebAssembly file. This enables the `wasm` feature of the `object` crate to be able to read the custom section in the same manner as other platforms, but currently `object` doesn't support writing wasm object files so a handwritten encoder is used instead. The only caveat I know of with this is that if `wasm-ld` does indeed look at the object file then the metadata will be included in the final output. I believe the only thing that could cause that at this time is `--whole-archive` which I don't think is passed for rlibs. I would clarify that I'm not 100% certain about this, however. --- Cargo.lock | 11 ++++ compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_codegen_ssa/src/back/metadata.rs | 88 +++++++++++++++++++------ src/tools/tidy/src/deps.rs | 17 +++++ 4 files changed, 97 insertions(+), 21 deletions(-) (limited to 'compiler') diff --git a/Cargo.lock b/Cargo.lock index 61f9c130e38..848c826f940 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2627,6 +2627,7 @@ dependencies = [ "rustc-std-workspace-alloc", "rustc-std-workspace-core", "ruzstd", + "wasmparser", ] [[package]] @@ -6128,6 +6129,16 @@ version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" +[[package]] +name = "wasmparser" +version = "0.118.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f1154f1ab868e2a01d9834a805faca7bf8b50d041b4ca714d005d0dab1c50c" +dependencies = [ + "indexmap", + "semver", +] + [[package]] name = "web-sys" version = "0.3.68" diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index e144b1dc1bd..781c54bdef8 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -48,7 +48,7 @@ libc = "0.2.50" [dependencies.object] version = "0.32.1" default-features = false -features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write"] +features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"] [target.'cfg(windows)'.dependencies.windows] version = "0.52.0" diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index b683e1b45a8..8e76e47cfef 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -15,6 +15,7 @@ use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice}; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::fs::METADATA_FILENAME; use rustc_metadata::EncodedMetadata; +use rustc_serialize::leb128; use rustc_session::Session; use rustc_span::sym; use rustc_target::abi::Endian; @@ -420,10 +421,9 @@ pub enum MetadataPosition { /// it's not in an allowlist of otherwise well known dwarf section names to /// go into the final artifact. /// -/// * WebAssembly - we actually don't have any container format for this -/// target. WebAssembly doesn't support the `dylib` crate type anyway so -/// there's no need for us to support this at this time. Consequently the -/// metadata bytes are simply stored as-is into an rlib. +/// * WebAssembly - this uses wasm files themselves as the object file format +/// so an empty file with no linking metadata but a single custom section is +/// created holding our metadata. /// /// * COFF - Windows-like targets create an object with a section that has /// the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker @@ -438,22 +438,13 @@ pub fn create_wrapper_file( data: &[u8], ) -> (Vec, MetadataPosition) { let Some(mut file) = create_object_file(sess) else { - // This is used to handle all "other" targets. This includes targets - // in two categories: - // - // * Some targets don't have support in the `object` crate just yet - // to write an object file. These targets are likely to get filled - // out over time. - // - // * Targets like WebAssembly don't support dylibs, so the purpose - // of putting metadata in object files, to support linking rlibs - // into dylibs, is moot. - // - // In both of these cases it means that linking into dylibs will - // not be supported by rustc. This doesn't matter for targets like - // WebAssembly and for targets not supported by the `object` crate - // yet it means that work will need to be done in the `object` crate - // to add a case above. + if sess.target.is_like_wasm { + return (create_metadata_file_for_wasm(data, §ion_name), MetadataPosition::First); + } + + // Targets using this branch don't have support implemented here yet or + // they're not yet implemented in the `object` crate and will likely + // fill out this module over time. return (data.to_vec(), MetadataPosition::Last); }; let section = if file.format() == BinaryFormat::Xcoff { @@ -532,6 +523,9 @@ pub fn create_compressed_metadata_file( packed_metadata.extend(metadata.raw_data()); let Some(mut file) = create_object_file(sess) else { + if sess.target.is_like_wasm { + return create_metadata_file_for_wasm(&packed_metadata, b".rustc"); + } return packed_metadata.to_vec(); }; if file.format() == BinaryFormat::Xcoff { @@ -624,3 +618,57 @@ pub fn create_compressed_metadata_file_for_xcoff( file.append_section_data(section, data, 1); file.write().unwrap() } + +/// Creates a simple WebAssembly object file, which is itself a wasm module, +/// that contains a custom section of the name `section_name` with contents +/// `data`. +/// +/// NB: the `object` crate does not yet have support for writing the the wasm +/// object file format. The format is simple enough that for now an extra crate +/// from crates.io (such as `wasm-encoder`). The file format is: +/// +/// * 4-byte header "\0asm" +/// * 4-byte version number - 1u32 in little-endian format +/// * concatenated sections, which for this object is always "custom sections" +/// +/// Custom sections are then defined by: +/// * 1-byte section identifier - 0 for a custom section +/// * leb-encoded section length (size of the contents beneath this bullet) +/// * leb-encoded custom section name length +/// * custom section name +/// * section contents +/// +/// One custom section, `linking`, is added here in accordance with +/// +/// which is required to inform LLD that this is an object file but it should +/// otherwise basically ignore it if it otherwise looks at it. The linking +/// section currently is defined by a single version byte (2) and then further +/// sections, but we have no more sections, so it's just the byte "2". +/// +/// The next custom section is the one we're interested in. +pub fn create_metadata_file_for_wasm(data: &[u8], section_name: &[u8]) -> Vec { + let mut bytes = b"\0asm\x01\0\0\0".to_vec(); + + let mut append_custom_section = |section_name: &[u8], data: &[u8]| { + let mut section_name_len = [0; leb128::max_leb128_len::()]; + let off = leb128::write_usize_leb128(&mut section_name_len, section_name.len()); + let section_name_len = §ion_name_len[..off]; + + let mut section_len = [0; leb128::max_leb128_len::()]; + let off = leb128::write_usize_leb128( + &mut section_len, + data.len() + section_name_len.len() + section_name.len(), + ); + let section_len = §ion_len[..off]; + + bytes.push(0u8); + bytes.extend_from_slice(section_len); + bytes.extend_from_slice(section_name_len); + bytes.extend_from_slice(section_name); + bytes.extend_from_slice(data); + }; + + append_custom_section(b"linking", &[2]); + append_custom_section(section_name, data); + bytes +} diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b36b6da308e..cff219285dc 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -92,6 +92,7 @@ const EXCEPTIONS: ExceptionList = &[ ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 // cargo/... (because of serde) ("self_cell", "Apache-2.0"), // rustc (fluent translations) ("snap", "BSD-3-Clause"), // rustc + ("wasmparser", "Apache-2.0 WITH LLVM-exception"), // rustc // tidy-alphabetical-end ]; @@ -379,6 +380,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "valuable", "version_check", "wasi", + "wasmparser", "winapi", "winapi-i686-pc-windows-gnu", "winapi-util", @@ -564,6 +566,21 @@ fn check_runtime_license_exceptions( if pkg.name == "fortanix-sgx-abi" && pkg.license.as_deref() == Some("MPL-2.0") { continue; } + + // This exception is due to the fact that the feature set of the + // `object` crate is different between rustc and libstd. In the + // standard library only a conservative set of features are enabled + // which notably does not include the `wasm` feature which pulls in + // this dependency. In the compiler, however, the `wasm` feature is + // enabled. This exception is intended to be here so long as the + // `EXCEPTIONS` above contains `wasmparser`, but once that goes away + // this can be removed. + if pkg.name == "wasmparser" + && pkg.license.as_deref() == Some("Apache-2.0 WITH LLVM-exception") + { + continue; + } + tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id); } } -- cgit 1.4.1-3-g733a5 From cc73b71e8e568c6421a23fc2954a86e1947aac66 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 6 Feb 2024 14:32:00 -0500 Subject: Add "algebraic" versions of the fast-math intrinsics --- .../rustc_codegen_cranelift/src/intrinsics/mod.rs | 21 +++++++--- compiler/rustc_codegen_gcc/src/builder.rs | 25 +++++++++++ compiler/rustc_codegen_llvm/src/builder.rs | 48 ++++++++++++++++++++-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 32 +++++++++++++++ compiler/rustc_codegen_ssa/src/traits/builder.rs | 5 +++ compiler/rustc_hir_analysis/src/check/intrinsic.rs | 12 +++++- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 25 ++++++++++- compiler/rustc_span/src/symbol.rs | 5 +++ library/core/src/intrinsics.rs | 40 ++++++++++++++++++ tests/codegen/simd/issue-120720-reduce-nan.rs | 22 ++++++++++ 12 files changed, 226 insertions(+), 14 deletions(-) create mode 100644 tests/codegen/simd/issue-120720-reduce-nan.rs (limited to 'compiler') diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 476752c7230..199d5df29e7 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1152,17 +1152,26 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, ret_val); } - sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { + sym::fadd_fast + | sym::fsub_fast + | sym::fmul_fast + | sym::fdiv_fast + | sym::frem_fast + | sym::fadd_algebraic + | sym::fsub_algebraic + | sym::fmul_algebraic + | sym::fdiv_algebraic + | sym::frem_algebraic => { intrinsic_args!(fx, args => (x, y); intrinsic); let res = crate::num::codegen_float_binop( fx, match intrinsic { - sym::fadd_fast => BinOp::Add, - sym::fsub_fast => BinOp::Sub, - sym::fmul_fast => BinOp::Mul, - sym::fdiv_fast => BinOp::Div, - sym::frem_fast => BinOp::Rem, + sym::fadd_fast | sym::fadd_algebraic => BinOp::Add, + sym::fsub_fast | sym::fsub_algebraic => BinOp::Sub, + sym::fmul_fast | sym::fmul_algebraic => BinOp::Mul, + sym::fdiv_fast | sym::fdiv_algebraic => BinOp::Div, + sym::frem_fast | sym::frem_algebraic => BinOp::Rem, _ => unreachable!(), }, x, diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 42e61b3ccb5..5f1e4538376 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -705,6 +705,31 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.frem(lhs, rhs) } + fn fadd_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs + rhs + } + + fn fsub_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs - rhs + } + + fn fmul_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs * rhs + } + + fn fdiv_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + lhs / rhs + } + + fn frem_algebraic(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + // NOTE: it seems like we cannot enable fast-mode for a single operation in GCC. + self.frem(lhs, rhs) + } + fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) { self.gcc_checked_binop(oop, typ, lhs, rhs) } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 7ed27b33dce..cfa266720d2 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -340,6 +340,46 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } + fn fadd_algebraic(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + unsafe { + let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, UNNAMED); + llvm::LLVMRustSetAlgebraicMath(instr); + instr + } + } + + fn fsub_algebraic(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + unsafe { + let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, UNNAMED); + llvm::LLVMRustSetAlgebraicMath(instr); + instr + } + } + + fn fmul_algebraic(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + unsafe { + let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, UNNAMED); + llvm::LLVMRustSetAlgebraicMath(instr); + instr + } + } + + fn fdiv_algebraic(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + unsafe { + let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, UNNAMED); + llvm::LLVMRustSetAlgebraicMath(instr); + instr + } + } + + fn frem_algebraic(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { + unsafe { + let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, UNNAMED); + llvm::LLVMRustSetAlgebraicMath(instr); + instr + } + } + fn checked_binop( &mut self, oop: OverflowOp, @@ -1327,17 +1367,17 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { pub fn vector_reduce_fmul(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { unsafe { llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src) } } - pub fn vector_reduce_fadd_fast(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { + pub fn vector_reduce_fadd_algebraic(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { unsafe { let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src); - llvm::LLVMRustSetFastMath(instr); + llvm::LLVMRustSetAlgebraicMath(instr); instr } } - pub fn vector_reduce_fmul_fast(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { + pub fn vector_reduce_fmul_algebraic(&mut self, acc: &'ll Value, src: &'ll Value) -> &'ll Value { unsafe { let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src); - llvm::LLVMRustSetFastMath(instr); + llvm::LLVMRustSetAlgebraicMath(instr); instr } } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 4415c51acf6..3b091fca28b 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1880,14 +1880,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>( arith_red!(simd_reduce_mul_ordered: vector_reduce_mul, vector_reduce_fmul, true, mul, 1.0); arith_red!( simd_reduce_add_unordered: vector_reduce_add, - vector_reduce_fadd_fast, + vector_reduce_fadd_algebraic, false, add, 0.0 ); arith_red!( simd_reduce_mul_unordered: vector_reduce_mul, - vector_reduce_fmul_fast, + vector_reduce_fmul_algebraic, false, mul, 1.0 diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d0044086c61..f9eb1da5dc7 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1618,6 +1618,7 @@ extern "C" { ) -> &'a Value; pub fn LLVMRustSetFastMath(Instr: &Value); + pub fn LLVMRustSetAlgebraicMath(Instr: &Value); // Miscellaneous instructions pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value; diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index e4633acd817..82488829b6e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -250,6 +250,38 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } + sym::fadd_algebraic + | sym::fsub_algebraic + | sym::fmul_algebraic + | sym::fdiv_algebraic + | sym::frem_algebraic => match float_type_width(arg_tys[0]) { + Some(_width) => match name { + sym::fadd_algebraic => { + bx.fadd_algebraic(args[0].immediate(), args[1].immediate()) + } + sym::fsub_algebraic => { + bx.fsub_algebraic(args[0].immediate(), args[1].immediate()) + } + sym::fmul_algebraic => { + bx.fmul_algebraic(args[0].immediate(), args[1].immediate()) + } + sym::fdiv_algebraic => { + bx.fdiv_algebraic(args[0].immediate(), args[1].immediate()) + } + sym::frem_algebraic => { + bx.frem_algebraic(args[0].immediate(), args[1].immediate()) + } + _ => bug!(), + }, + None => { + bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicFloatType { + span, + name, + ty: arg_tys[0], + }); + return Ok(()); + } + }, sym::float_to_int_unchecked => { if float_type_width(arg_tys[0]).is_none() { diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 1c5c78e6ca2..86d3d1260c3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -86,22 +86,27 @@ pub trait BuilderMethods<'a, 'tcx>: fn add(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fadd_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn fadd_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn sub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fsub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fsub_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn fsub_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn mul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fmul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fmul_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn fmul_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn udiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn exactudiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn sdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn exactsdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fdiv_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn fdiv_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn urem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn srem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn frem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn frem_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; + fn frem_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index f0f6bfff64a..f4b994df2ce 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -123,7 +123,12 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::variant_count | sym::is_val_statically_known | sym::ptr_mask - | sym::debug_assertions => hir::Unsafety::Normal, + | sym::debug_assertions + | sym::fadd_algebraic + | sym::fsub_algebraic + | sym::fmul_algebraic + | sym::fdiv_algebraic + | sym::frem_algebraic => hir::Unsafety::Normal, _ => hir::Unsafety::Unsafe, }; @@ -405,6 +410,11 @@ pub fn check_intrinsic_type( sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { (1, 0, vec![param(0), param(0)], param(0)) } + sym::fadd_algebraic + | sym::fsub_algebraic + | sym::fmul_algebraic + | sym::fdiv_algebraic + | sym::frem_algebraic => (1, 0, vec![param(0), param(0)], param(0)), sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)), sym::assume => (0, 0, vec![tcx.types.bool], Ty::new_unit(tcx)), diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b45706fd1e5..7326f2e8e2a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -418,7 +418,11 @@ extern "C" LLVMAttributeRef LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C, } } -// Enable a fast-math flag +// Enable all fast-math flags, including those which will cause floating-point operations +// to return poison for some well-defined inputs. This function can only be used to build +// unsafe Rust intrinsics. That unsafety does permit additional optimizations, but at the +// time of writing, their value is not well-understood relative to those enabled by +// LLVMRustSetAlgebraicMath. // // https://llvm.org/docs/LangRef.html#fast-math-flags extern "C" void LLVMRustSetFastMath(LLVMValueRef V) { @@ -427,6 +431,25 @@ extern "C" void LLVMRustSetFastMath(LLVMValueRef V) { } } +// Enable fast-math flags which permit algebraic transformations that are not allowed by +// IEEE floating point. For example: +// a + (b + c) = (a + b) + c +// and +// a / b = a * (1 / b) +// Note that this does NOT enable any flags which can cause a floating-point operation on +// well-defined inputs to return poison, and therefore this function can be used to build +// safe Rust intrinsics (such as fadd_algebraic). +// +// https://llvm.org/docs/LangRef.html#fast-math-flags +extern "C" void LLVMRustSetAlgebraicMath(LLVMValueRef V) { + if (auto I = dyn_cast(unwrap(V))) { + I->setHasAllowReassoc(true); + I->setHasAllowContract(true); + I->setHasAllowReciprocal(true); + I->setHasNoSignedZeros(true); + } +} + extern "C" LLVMValueRef LLVMRustBuildAtomicLoad(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Source, const char *Name, LLVMAtomicOrdering Order) { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 29c88783357..181ab0d4d56 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -764,8 +764,10 @@ symbols! { f64_nan, fabsf32, fabsf64, + fadd_algebraic, fadd_fast, fake_variadic, + fdiv_algebraic, fdiv_fast, feature, fence, @@ -785,6 +787,7 @@ symbols! { fmaf32, fmaf64, fmt, + fmul_algebraic, fmul_fast, fn_align, fn_delegation, @@ -810,6 +813,7 @@ symbols! { format_unsafe_arg, freeze, freg, + frem_algebraic, frem_fast, from, from_desugaring, @@ -823,6 +827,7 @@ symbols! { from_usize, from_yeet, fs_create_dir, + fsub_algebraic, fsub_fast, fundamental, future, diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index fc6c1eab803..f19d169ae68 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1882,6 +1882,46 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn frem_fast(a: T, b: T) -> T; + /// Float addition that allows optimizations based on algebraic rules. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + #[rustc_safe_intrinsic] + #[cfg(not(bootstrap))] + pub fn fadd_algebraic(a: T, b: T) -> T; + + /// Float subtraction that allows optimizations based on algebraic rules. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + #[rustc_safe_intrinsic] + #[cfg(not(bootstrap))] + pub fn fsub_algebraic(a: T, b: T) -> T; + + /// Float multiplication that allows optimizations based on algebraic rules. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + #[rustc_safe_intrinsic] + #[cfg(not(bootstrap))] + pub fn fmul_algebraic(a: T, b: T) -> T; + + /// Float division that allows optimizations based on algebraic rules. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + #[rustc_safe_intrinsic] + #[cfg(not(bootstrap))] + pub fn fdiv_algebraic(a: T, b: T) -> T; + + /// Float remainder that allows optimizations based on algebraic rules. + /// + /// This intrinsic does not have a stable counterpart. + #[rustc_nounwind] + #[rustc_safe_intrinsic] + #[cfg(not(bootstrap))] + pub fn frem_algebraic(a: T, b: T) -> T; + /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range /// () /// diff --git a/tests/codegen/simd/issue-120720-reduce-nan.rs b/tests/codegen/simd/issue-120720-reduce-nan.rs new file mode 100644 index 00000000000..233131aa01c --- /dev/null +++ b/tests/codegen/simd/issue-120720-reduce-nan.rs @@ -0,0 +1,22 @@ +// compile-flags: -C opt-level=3 -C target-cpu=cannonlake +// only-x86_64 + +// In a previous implementation, _mm512_reduce_add_pd did the reduction with all fast-math flags +// enabled, making it UB to reduce a vector containing a NaN. + +#![crate_type = "lib"] +#![feature(stdarch_x86_avx512, avx512_target_feature)] +use std::arch::x86_64::*; + +// CHECK-label: @demo( +#[no_mangle] +#[target_feature(enable = "avx512f")] // Function-level target feature mismatches inhibit inlining +pub unsafe fn demo() -> bool { + // CHECK: %0 = tail call reassoc nsz arcp contract double @llvm.vector.reduce.fadd.v8f64( + // CHECK: %_0.i = fcmp uno double %0, 0.000000e+00 + // CHECK: ret i1 %_0.i + let res = unsafe { + _mm512_reduce_add_pd(_mm512_set_pd(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, f64::NAN)) + }; + res.is_nan() +} -- cgit 1.4.1-3-g733a5 From 5fb67e2ad40d656ba53fbfd233afea47aceebf83 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 20 Feb 2024 20:36:56 +0100 Subject: some type system cleanup --- compiler/rustc_infer/src/infer/relate/combine.rs | 24 ++-- .../rustc_infer/src/infer/relate/generalize.rs | 123 ++++++++++++--------- .../rustc_trait_selection/src/solve/normalize.rs | 29 ++--- .../src/solve/normalizes_to/anon_const.rs | 25 +++++ .../src/solve/normalizes_to/mod.rs | 71 +++++------- .../src/solve/normalizes_to/opaque_types.rs | 96 ++++++++++++++++ .../src/solve/normalizes_to/opaques.rs | 96 ---------------- .../occurs-check/associated-type.next.stderr | 16 +-- .../occurs-check/associated-type.old.stderr | 16 +-- .../next-solver/issue-118950-root-region.stderr | 16 +-- 10 files changed, 265 insertions(+), 247 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs create mode 100644 compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs delete mode 100644 compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs (limited to 'compiler') diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 454de4f9785..f7690831c2a 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -194,7 +194,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::ConstKind::Infer(InferConst::Var(b_vid)), ) => { self.inner.borrow_mut().const_unification_table().union(a_vid, b_vid); - return Ok(a); + Ok(a) } ( @@ -202,7 +202,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::ConstKind::Infer(InferConst::EffectVar(b_vid)), ) => { self.inner.borrow_mut().effect_unification_table().union(a_vid, b_vid); - return Ok(a); + Ok(a) } // All other cases of inference with other variables are errors. @@ -220,19 +220,21 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.instantiate_const_var(vid, b); + self.instantiate_const_var(relation, relation.a_is_expected(), vid, b)?; + Ok(b) } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.instantiate_const_var(vid, a); + self.instantiate_const_var(relation, !relation.a_is_expected(), vid, a)?; + Ok(a) } (ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => { - return Ok(self.unify_effect_variable(vid, b)); + Ok(self.unify_effect_variable(vid, b)) } (_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => { - return Ok(self.unify_effect_variable(vid, a)); + Ok(self.unify_effect_variable(vid, a)) } (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) @@ -240,7 +242,7 @@ impl<'tcx> InferCtxt<'tcx> { { let (a, b) = if relation.a_is_expected() { (a, b) } else { (b, a) }; - relation.register_predicates([ty::Binder::dummy(if self.next_trait_solver() { + relation.register_predicates([if self.next_trait_solver() { ty::PredicateKind::AliasRelate( a.into(), b.into(), @@ -248,14 +250,12 @@ impl<'tcx> InferCtxt<'tcx> { ) } else { ty::PredicateKind::ConstEquate(a, b) - })]); + }]); - return Ok(b); + Ok(b) } - _ => {} + _ => ty::relate::structurally_relate_consts(relation, a, b), } - - ty::relate::structurally_relate_consts(relation, a, b) } fn unify_integral_variable( diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index c0cb02916fe..371340c5bbf 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -22,7 +22,7 @@ impl<'tcx> InferCtxt<'tcx> { /// subtyping could occur. This also does the occurs checks, detecting whether /// instantiating `target_vid` would result in a cyclic type. We eagerly error /// in this case. - #[instrument(skip(self, relation, target_is_expected), level = "debug")] + #[instrument(level = "debug", skip(self, relation, target_is_expected))] pub(super) fn instantiate_ty_var>( &self, relation: &mut R, @@ -158,26 +158,22 @@ impl<'tcx> InferCtxt<'tcx> { /// As `3 + 4` contains `N` in its args, this must not succeed. /// /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. - #[instrument(level = "debug", skip(self))] - pub(super) fn instantiate_const_var( + #[instrument(level = "debug", skip(self, relation))] + pub(super) fn instantiate_const_var>( &self, + relation: &mut R, + target_is_expected: bool, target_vid: ty::ConstVid, source_ct: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - let span = match self.inner.borrow_mut().const_unification_table().probe_value(target_vid) { - ConstVariableValue::Known { value } => { - bug!("instantiating a known const var: {target_vid:?} {value} {source_ct}") - } - ConstVariableValue::Unknown { origin, universe: _ } => origin.span, - }; + ) -> RelateResult<'tcx, ()> { // FIXME(generic_const_exprs): Occurs check failures for unevaluated // constants and generic expressions are not yet handled correctly. let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = - self.generalize(span, target_vid, ty::Variance::Invariant, source_ct)?; + self.generalize(relation.span(), target_vid, ty::Variance::Invariant, source_ct)?; debug_assert!(!generalized_ct.is_ct_infer()); if has_unconstrained_ty_var { - span_bug!(span, "unconstrained ty var when generalizing `{source_ct:?}`"); + bug!("unconstrained ty var when generalizing `{source_ct:?}`"); } self.inner @@ -185,9 +181,25 @@ impl<'tcx> InferCtxt<'tcx> { .const_unification_table() .union_value(target_vid, ConstVariableValue::Known { value: generalized_ct }); - // FIXME(generic_const_exprs): We have to make sure we actually equate - // `generalized_ct` and `source_ct` here. - Ok(generalized_ct) + // HACK: make sure that we `a_is_expected` continues to be + // correct when relating the generalized type with the source. + if target_is_expected == relation.a_is_expected() { + relation.relate_with_variance( + ty::Variance::Invariant, + ty::VarianceDiagInfo::default(), + generalized_ct, + source_ct, + )?; + } else { + relation.relate_with_variance( + ty::Variance::Invariant, + ty::VarianceDiagInfo::default(), + source_ct, + generalized_ct, + )?; + } + + Ok(()) } /// Attempts to generalize `source_term` for the type variable `target_vid`. @@ -287,6 +299,49 @@ impl<'tcx> Generalizer<'_, 'tcx> { ty::TermKind::Const(ct) => TypeError::CyclicConst(ct), } } + + /// An occurs check failure inside of an alias does not mean + /// that the types definitely don't unify. We may be able + /// to normalize the alias after all. + /// + /// We handle this by lazily equating the alias and generalizing + /// it to an inference variable. + /// + /// This is incomplete and will hopefully soon get fixed by #119106. + fn generalize_alias_ty( + &mut self, + alias: ty::AliasTy<'tcx>, + ) -> Result, TypeError<'tcx>> { + let is_nested_alias = mem::replace(&mut self.in_alias, true); + let result = match self.relate(alias, alias) { + Ok(alias) => Ok(alias.to_ty(self.tcx())), + Err(e) => { + if is_nested_alias { + return Err(e); + } else { + let mut visitor = MaxUniverse::new(); + alias.visit_with(&mut visitor); + let infer_replacement_is_complete = + self.for_universe.can_name(visitor.max_universe()) + && !alias.has_escaping_bound_vars(); + if !infer_replacement_is_complete { + warn!("may incompletely handle alias type: {alias:?}"); + } + + debug!("generalization failure in alias"); + Ok(self.infcx.next_ty_var_in_universe( + TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: self.span, + }, + self.for_universe, + )) + } + } + }; + self.in_alias = is_nested_alias; + result + } } impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { @@ -433,43 +488,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } - ty::Alias(kind, data) => { - // An occurs check failure inside of an alias does not mean - // that the types definitely don't unify. We may be able - // to normalize the alias after all. - // - // We handle this by lazily equating the alias and generalizing - // it to an inference variable. - let is_nested_alias = mem::replace(&mut self.in_alias, true); - let result = match self.relate(data, data) { - Ok(data) => Ok(Ty::new_alias(self.tcx(), kind, data)), - Err(e) => { - if is_nested_alias { - return Err(e); - } else { - let mut visitor = MaxUniverse::new(); - t.visit_with(&mut visitor); - let infer_replacement_is_complete = - self.for_universe.can_name(visitor.max_universe()) - && !t.has_escaping_bound_vars(); - if !infer_replacement_is_complete { - warn!("may incompletely handle alias type: {t:?}"); - } - - debug!("generalization failure in alias"); - Ok(self.infcx.next_ty_var_in_universe( - TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: self.span, - }, - self.for_universe, - )) - } - } - }; - self.in_alias = is_nested_alias; - result - } + ty::Alias(_, data) => self.generalize_alias_ty(data), _ => relate::structurally_relate_tys(self, t, t), }?; diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index b07702e8421..91312c9fdd6 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -85,25 +85,16 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { ), ); - // Do not emit an error if normalization is known to fail but instead - // keep the projection unnormalized. This is the case for projections - // with a `T: Trait` where-clause and opaque types outside of the defining - // scope. - let result = if infcx.predicate_may_hold(&obligation) { - self.fulfill_cx.register_predicate_obligation(infcx, obligation); - let errors = self.fulfill_cx.select_all_or_error(infcx); - if !errors.is_empty() { - return Err(errors); - } - let ty = infcx.resolve_vars_if_possible(new_infer_ty); - - // Alias is guaranteed to be fully structurally resolved, - // so we can super fold here. - ty.try_super_fold_with(self)? - } else { - alias_ty.try_super_fold_with(self)? - }; + self.fulfill_cx.register_predicate_obligation(infcx, obligation); + let errors = self.fulfill_cx.select_all_or_error(infcx); + if !errors.is_empty() { + return Err(errors); + } + // Alias is guaranteed to be fully structurally resolved, + // so we can super fold here. + let ty = infcx.resolve_vars_if_possible(new_infer_ty); + let result = ty.try_super_fold_with(self)?; self.depth -= 1; Ok(result) } @@ -178,6 +169,7 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { Ok(t) } + #[instrument(level = "debug", skip(self), ret)] fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { let infcx = self.at.infcx; debug_assert_eq!(ty, infcx.shallow_resolve(ty)); @@ -204,6 +196,7 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { } } + #[instrument(level = "debug", skip(self), ret)] fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result, Self::Error> { let infcx = self.at.infcx; debug_assert_eq!(ct, infcx.shallow_resolve(ct)); diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs new file mode 100644 index 00000000000..911462f4b9a --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs @@ -0,0 +1,25 @@ +use crate::solve::EvalCtxt; +use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; +use rustc_middle::ty; + +impl<'tcx> EvalCtxt<'_, 'tcx> { + #[instrument(level = "debug", skip(self), ret)] + pub(super) fn normalize_anon_const( + &mut self, + goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, + ) -> QueryResult<'tcx> { + if let Some(normalized_const) = self.try_const_eval_resolve( + goal.param_env, + ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args), + self.tcx() + .type_of(goal.predicate.alias.def_id) + .no_bound_vars() + .expect("const ty should not rely on other generics"), + ) { + self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index d177109c420..5f625831156 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -18,8 +18,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; +mod anon_const; mod inherent; -mod opaques; +mod opaque_types; mod weak_types; impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -31,34 +32,34 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let def_id = goal.predicate.def_id(); match self.tcx().def_kind(def_id) { DefKind::AssocTy | DefKind::AssocConst => { - // To only compute normalization once for each projection we only - // assemble normalization candidates if the expected term is an - // unconstrained inference variable. - // - // Why: For better cache hits, since if we have an unconstrained RHS then - // there are only as many cache keys as there are (canonicalized) alias - // types in each normalizes-to goal. This also weakens inference in a - // forwards-compatible way so we don't use the value of the RHS term to - // affect candidate assembly for projections. - // - // E.g. for `::Assoc == u32` we recursively compute the goal - // `exists ::Assoc == U` and then take the resulting type for - // `U` and equate it with `u32`. This means that we don't need a separate - // projection cache in the solver, since we're piggybacking off of regular - // goal caching. - if self.term_is_fully_unconstrained(goal) { - match self.tcx().associated_item(def_id).container { - ty::AssocItemContainer::TraitContainer => { + match self.tcx().associated_item(def_id).container { + ty::AssocItemContainer::TraitContainer => { + // To only compute normalization once for each projection we only + // assemble normalization candidates if the expected term is an + // unconstrained inference variable. + // + // Why: For better cache hits, since if we have an unconstrained RHS then + // there are only as many cache keys as there are (canonicalized) alias + // types in each normalizes-to goal. This also weakens inference in a + // forwards-compatible way so we don't use the value of the RHS term to + // affect candidate assembly for projections. + // + // E.g. for `::Assoc == u32` we recursively compute the goal + // `exists ::Assoc == U` and then take the resulting type for + // `U` and equate it with `u32`. This means that we don't need a separate + // projection cache in the solver, since we're piggybacking off of regular + // goal caching. + if self.term_is_fully_unconstrained(goal) { let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_candidates(candidates) + } else { + self.set_normalizes_to_hack_goal(goal); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - ty::AssocItemContainer::ImplContainer => { - self.normalize_inherent_associated_type(goal) - } } - } else { - self.set_normalizes_to_hack_goal(goal); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ty::AssocItemContainer::ImplContainer => { + self.normalize_inherent_associated_type(goal) + } } } DefKind::AnonConst => self.normalize_anon_const(goal), @@ -67,26 +68,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)), } } - - #[instrument(level = "debug", skip(self), ret)] - fn normalize_anon_const( - &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { - if let Some(normalized_const) = self.try_const_eval_resolve( - goal.param_env, - ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args), - self.tcx() - .type_of(goal.predicate.alias.def_id) - .no_bound_vars() - .expect("const ty should not rely on other generics"), - ) { - self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?; - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } else { - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } - } } impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs new file mode 100644 index 00000000000..356c3776c04 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs @@ -0,0 +1,96 @@ +//! Computes a normalizes-to (projection) goal for opaque types. This goal +//! behaves differently depending on the param-env's reveal mode and whether +//! the opaque is in a defining scope. +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; +use rustc_middle::traits::Reveal; +use rustc_middle::ty; +use rustc_middle::ty::util::NotUniqueParam; + +use crate::solve::{EvalCtxt, SolverMode}; + +impl<'tcx> EvalCtxt<'_, 'tcx> { + pub(super) fn normalize_opaque_type( + &mut self, + goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, + ) -> QueryResult<'tcx> { + let tcx = self.tcx(); + let opaque_ty = goal.predicate.alias; + let expected = goal.predicate.term.ty().expect("no such thing as an opaque const"); + + match (goal.param_env.reveal(), self.solver_mode()) { + (Reveal::UserFacing, SolverMode::Normal) => { + let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { + return Err(NoSolution); + }; + // FIXME: at some point we should call queries without defining + // new opaque types but having the existing opaque type definitions. + // This will require moving this below "Prefer opaques registered already". + if !self.can_define_opaque_ty(opaque_ty_def_id) { + return Err(NoSolution); + } + // FIXME: This may have issues when the args contain aliases... + match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.args) { + Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { + return self.evaluate_added_goals_and_make_canonical_response( + Certainty::AMBIGUOUS, + ); + } + Err(_) => { + return Err(NoSolution); + } + Ok(()) => {} + } + // Prefer opaques registered already. + let opaque_type_key = + ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args }; + // FIXME: This also unifies the previous hidden type with the expected. + // + // If that fails, we insert `expected` as a new hidden type instead of + // eagerly emitting an error. + let matches = + self.unify_existing_opaque_tys(goal.param_env, opaque_type_key, expected); + if !matches.is_empty() { + if let Some(response) = self.try_merge_responses(&matches) { + return Ok(response); + } else { + return self.flounder(&matches); + } + } + + let expected = self.structurally_normalize_ty(goal.param_env, expected)?; + if expected.is_ty_var() { + return self + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + + // Otherwise, define a new opaque type + self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; + self.add_item_bounds_for_hidden_type( + opaque_ty.def_id, + opaque_ty.args, + goal.param_env, + expected, + ); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + (Reveal::UserFacing, SolverMode::Coherence) => { + // An impossible opaque type bound is the only way this goal will fail + // e.g. assigning `impl Copy := NotCopy` + self.add_item_bounds_for_hidden_type( + opaque_ty.def_id, + opaque_ty.args, + goal.param_env, + expected, + ); + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + (Reveal::All, _) => { + // FIXME: Add an assertion that opaque type storage is empty. + let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, opaque_ty.args); + self.eq(goal.param_env, expected, actual)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs deleted file mode 100644 index 356c3776c04..00000000000 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaques.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! Computes a normalizes-to (projection) goal for opaque types. This goal -//! behaves differently depending on the param-env's reveal mode and whether -//! the opaque is in a defining scope. -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::traits::Reveal; -use rustc_middle::ty; -use rustc_middle::ty::util::NotUniqueParam; - -use crate::solve::{EvalCtxt, SolverMode}; - -impl<'tcx> EvalCtxt<'_, 'tcx> { - pub(super) fn normalize_opaque_type( - &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { - let tcx = self.tcx(); - let opaque_ty = goal.predicate.alias; - let expected = goal.predicate.term.ty().expect("no such thing as an opaque const"); - - match (goal.param_env.reveal(), self.solver_mode()) { - (Reveal::UserFacing, SolverMode::Normal) => { - let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { - return Err(NoSolution); - }; - // FIXME: at some point we should call queries without defining - // new opaque types but having the existing opaque type definitions. - // This will require moving this below "Prefer opaques registered already". - if !self.can_define_opaque_ty(opaque_ty_def_id) { - return Err(NoSolution); - } - // FIXME: This may have issues when the args contain aliases... - match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.args) { - Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { - return self.evaluate_added_goals_and_make_canonical_response( - Certainty::AMBIGUOUS, - ); - } - Err(_) => { - return Err(NoSolution); - } - Ok(()) => {} - } - // Prefer opaques registered already. - let opaque_type_key = - ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args }; - // FIXME: This also unifies the previous hidden type with the expected. - // - // If that fails, we insert `expected` as a new hidden type instead of - // eagerly emitting an error. - let matches = - self.unify_existing_opaque_tys(goal.param_env, opaque_type_key, expected); - if !matches.is_empty() { - if let Some(response) = self.try_merge_responses(&matches) { - return Ok(response); - } else { - return self.flounder(&matches); - } - } - - let expected = self.structurally_normalize_ty(goal.param_env, expected)?; - if expected.is_ty_var() { - return self - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); - } - - // Otherwise, define a new opaque type - self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; - self.add_item_bounds_for_hidden_type( - opaque_ty.def_id, - opaque_ty.args, - goal.param_env, - expected, - ); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - (Reveal::UserFacing, SolverMode::Coherence) => { - // An impossible opaque type bound is the only way this goal will fail - // e.g. assigning `impl Copy := NotCopy` - self.add_item_bounds_for_hidden_type( - opaque_ty.def_id, - opaque_ty.args, - goal.param_env, - expected, - ); - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } - (Reveal::All, _) => { - // FIXME: Add an assertion that opaque type storage is empty. - let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, opaque_ty.args); - self.eq(goal.param_env, expected, actual)?; - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } - } - } -} diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index e405f389f5e..6119e6149a7 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -1,11 +1,11 @@ -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index 4a67a777f10..655809b827e 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -1,11 +1,11 @@ -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index f4638348358..e33320ed9e6 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -13,14 +13,14 @@ LL | #![feature(lazy_type_alias)] = note: see issue #112792 for more information = note: `#[warn(incomplete_features)]` on by default -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } error[E0119]: conflicting implementations of trait `Overlap` for type `fn(_)` --> $DIR/issue-118950-root-region.rs:19:1 | -- cgit 1.4.1-3-g733a5 From e35481f90bcd7e4a646aabab1183a33bebae8c94 Mon Sep 17 00:00:00 2001 From: Fernando Fernandez Mancera Date: Tue, 20 Feb 2024 09:31:01 +0100 Subject: Suggest using --verbose when writing type to a file --- compiler/rustc_hir_typeck/src/method/suggest.rs | 6 ++++++ compiler/rustc_infer/src/infer/error_reporting/mod.rs | 1 + .../src/traits/error_reporting/suggestions.rs | 12 ++++++++++++ tests/ui/diagnostic-width/long-E0308.stderr | 4 ++++ 4 files changed, 23 insertions(+) (limited to 'compiler') diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index f39b496154b..5a3b0e6b101 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -369,6 +369,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(file) = file { err.note(format!("the full type name has been written to '{}'", file.display())); + err.note(format!( + "consider using `--verbose` to print the full type name to the console" + )); } err @@ -493,6 +496,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(file) = ty_file { err.note(format!("the full type name has been written to '{}'", file.display(),)); + err.note(format!( + "consider using `--verbose` to print the full type name to the console" + )); } if rcvr_ty.references_error() { err.downgrade_to_delayed_bug(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 104bf4a5be8..b72d804ce3c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1931,6 +1931,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { "the full type name has been written to '{}'", path.display(), )); + diag.note(format!("consider using `--verbose` to print the full type name to the console")); } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 335e6ff2822..8f64065dadd 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1554,6 +1554,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "the full type name has been written to '{}'", file.display() )); + err.note(format!( + "consider using `--verbose` to print full type name to the console" + )); } if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred { @@ -3133,6 +3136,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "the full name for the type has been written to '{}'", file.display(), )); + err.note(format!( + "consider using `--verbose` to print the full type name to the console" + )); } } ObligationCauseCode::RepeatElementCopy { @@ -3600,6 +3606,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "the full type name has been written to '{}'", file.display(), )); + err.note(format!( + "consider using `--verbose` to print the full type name to the console" + )); } let mut parent_predicate = parent_trait_pred; let mut data = &data.derived; @@ -3653,6 +3662,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "the full type name has been written to '{}'", file.display(), )); + err.note(format!( + "consider using `--verbose` to print the full type name to the console" + )); } } // #74711: avoid a stack overflow diff --git a/tests/ui/diagnostic-width/long-E0308.stderr b/tests/ui/diagnostic-width/long-E0308.stderr index 1e5966a1c5d..eb37da037e9 100644 --- a/tests/ui/diagnostic-width/long-E0308.stderr +++ b/tests/ui/diagnostic-width/long-E0308.stderr @@ -21,6 +21,7 @@ LL | | )))))))))))))))))))))))))))))); = note: expected struct `Atype, ...>` found enum `Result, ...>` = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types --> $DIR/long-E0308.rs:57:26 @@ -36,6 +37,7 @@ LL | | )))))))))))))))))))))))); = note: expected enum `Option>` found enum `Result, ...>` = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types --> $DIR/long-E0308.rs:88:9 @@ -55,6 +57,7 @@ LL | | > = (); = note: expected struct `Atype, ...>` found unit type `()` = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types --> $DIR/long-E0308.rs:91:17 @@ -72,6 +75,7 @@ LL | | )))))))))))))))))))))))); = note: expected unit type `()` found enum `Result, ...>` = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308/long-E0308.long-type-hash.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 4 previous errors -- cgit 1.4.1-3-g733a5 From 010f3944e0f0baac8d738da49772fd06acd3701b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 17 Feb 2024 01:23:40 +1100 Subject: Convert `delayed_bug`s to `bug`s. I have a suspicion that quite a few delayed bug paths are impossible to reach, so I did an experiment. I converted every `delayed_bug` to a `bug`, ran the full test suite, then converted back every `bug` that was hit. A surprising number were never hit. The next commit will convert some more back, based on human judgment. --- compiler/rustc_ast_lowering/src/lib.rs | 4 +-- .../rustc_borrowck/src/diagnostics/region_name.rs | 2 +- .../src/type_check/free_region_relations.rs | 3 +-- .../rustc_borrowck/src/type_check/input_output.rs | 3 +-- compiler/rustc_borrowck/src/type_check/mod.rs | 12 ++++----- .../rustc_const_eval/src/const_eval/machine.rs | 8 ++---- .../src/transform/check_consts/check.rs | 4 +-- .../rustc_const_eval/src/transform/validate.rs | 2 +- compiler/rustc_hir_analysis/src/astconv/mod.rs | 3 +-- compiler/rustc_hir_analysis/src/check/check.rs | 7 +++--- .../src/check/compare_impl_item.rs | 14 ++++------- .../src/check/compare_impl_item/refine.rs | 9 +++---- compiler/rustc_hir_analysis/src/check/dropck.rs | 3 +-- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 6 ++--- .../rustc_hir_analysis/src/collect/generics_of.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 9 +++---- compiler/rustc_hir_typeck/src/cast.rs | 5 +--- compiler/rustc_hir_typeck/src/expr.rs | 15 +++-------- compiler/rustc_hir_typeck/src/intrinsicck.rs | 3 +-- .../rustc_hir_typeck/src/mem_categorization.rs | 6 ++--- compiler/rustc_hir_typeck/src/method/probe.rs | 3 +-- compiler/rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 5 +--- .../rustc_infer/src/infer/outlives/obligations.rs | 2 +- compiler/rustc_infer/src/infer/outlives/verify.rs | 6 +---- compiler/rustc_infer/src/infer/relate/nll.rs | 8 +++--- compiler/rustc_middle/src/ty/typeck_results.rs | 3 +-- compiler/rustc_middle/src/ty/util.rs | 4 +-- compiler/rustc_middle/src/util/bug.rs | 2 +- .../rustc_mir_build/src/build/expr/as_constant.rs | 15 +++++------ compiler/rustc_mir_build/src/thir/constant.rs | 29 ++++++++-------------- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 2 +- compiler/rustc_mir_transform/src/coroutine.rs | 6 +---- .../rustc_mir_transform/src/elaborate_drops.rs | 2 +- compiler/rustc_resolve/src/late.rs | 4 +-- .../src/traits/const_evaluatable.rs | 6 ++--- .../traits/error_reporting/type_err_ctxt_ext.rs | 2 +- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- .../src/traits/outlives_bounds.rs | 2 +- .../rustc_trait_selection/src/traits/project.rs | 5 ++-- .../src/traits/query/type_op/custom.rs | 2 +- .../src/traits/query/type_op/mod.rs | 7 +++--- compiler/rustc_ty_utils/src/layout.rs | 3 +-- compiler/rustc_ty_utils/src/opaque_types.rs | 2 +- 44 files changed, 87 insertions(+), 157 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a5be91bb872..ef843da7307 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1636,9 +1636,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if let Some(old_def_id) = self.orig_opt_local_def_id(param) { old_def_id } else { - self.dcx() - .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime"); - continue; + self.dcx().span_bug(lifetime.ident.span, "no def-id for fresh lifetime"); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 5b235066ea6..fea8c5a6de6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -628,7 +628,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ) => { // HIR lowering sometimes doesn't catch this in erroneous // programs, so we need to use span_delayed_bug here. See #82126. - self.dcx().span_delayed_bug( + self.dcx().span_bug( hir_arg.span(), format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"), ); diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 356f0024c07..0fc04175705 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -316,8 +316,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { .and(type_op::normalize::Normalize::new(ty)) .fully_perform(self.infcx, span) else { - tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}")); - continue; + tcx.dcx().span_bug(span, format!("failed to normalize {ty:?}")); }; constraints.extend(c); diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index af5b635ae66..8af78b08f69 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -154,8 +154,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if argument_index + 1 >= body.local_decls.len() { self.tcx() .dcx() - .span_delayed_bug(body.span, "found more normalized_input_ty than local_decls"); - break; + .span_bug(body.span, "found more normalized_input_ty than local_decls"); } // In MIR, argument N is stored in local N+1. diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index f96c2cbd8c0..81193902f9b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -220,14 +220,13 @@ pub(crate) fn type_check<'mir, 'tcx>( "opaque_type_map", ), ); - let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); + let hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type); trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind()); if hidden_type.has_non_region_infer() { - let reported = infcx.dcx().span_delayed_bug( + infcx.dcx().span_bug( decl.hidden_type.span, format!("could not resolve {:#?}", hidden_type.ty.kind()), ); - hidden_type.ty = Ty::new_error(infcx.tcx, reported); } (opaque_type_key, hidden_type) @@ -1089,10 +1088,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); if result.is_err() { - self.infcx.dcx().span_delayed_bug( - self.body.span, - "failed re-defining predefined opaques in mir typeck", - ); + self.infcx + .dcx() + .span_bug(self.body.span, "failed re-defining predefined opaques in mir typeck"); } } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 2c60ede7975..77744945b12 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -393,11 +393,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, if ecx.tcx.is_ctfe_mir_available(def) { Ok(ecx.tcx.mir_for_ctfe(def)) } else if ecx.tcx.def_kind(def) == DefKind::AssocConst { - let guar = ecx - .tcx - .dcx() - .delayed_bug("This is likely a const item that is missing from its impl"); - throw_inval!(AlreadyReported(guar.into())); + ecx.tcx.dcx().bug("This is likely a const item that is missing from its impl"); } else { // `find_mir_or_eval_fn` checks that this is a const fn before even calling us, // so this should be unreachable. @@ -626,7 +622,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ); // If this was a hard error, don't bother continuing evaluation. if is_error { - let guard = ecx + let guard: rustc_errors::ErrorGuaranteed = ecx .tcx .dcx() .span_delayed_bug(span, "The deny lint should have already errored"); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 26ef083219f..effaedd0820 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -329,9 +329,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { fn check_static(&mut self, def_id: DefId, span: Span) { if self.tcx.is_thread_local_static(def_id) { - self.tcx - .dcx() - .span_delayed_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`"); + self.tcx.dcx().span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`"); } self.check_op_spanned(ops::StaticAccess, span) } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 1ff72516324..cc49e8ea247 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -517,7 +517,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { fn visit_source_scope(&mut self, scope: SourceScope) { if self.body.source_scopes.get(scope).is_none() { - self.tcx.dcx().span_delayed_bug( + self.tcx.dcx().span_bug( self.body.span, format!( "broken MIR in {:?} ({}):\ninvalid source scope {:?}", diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 502e83db654..385b1f2a3e3 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1237,8 +1237,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // trait reference. let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else { // A cycle error occurred, most likely. - let guar = tcx.dcx().span_delayed_bug(span, "expected cycle error"); - return Err(guar); + tcx.dcx().span_bug(span, "expected cycle error"); }; self.one_bound_for_assoc_item( diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index b3700013f9c..b945eed54d0 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -257,8 +257,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { let item = tcx.hir().expect_item(def_id); let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else { - tcx.dcx().span_delayed_bug(item.span, "expected opaque item"); - return; + tcx.dcx().span_bug(item.span, "expected opaque item"); }; // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting @@ -382,10 +381,10 @@ fn check_opaque_meets_bounds<'tcx>( Ok(()) => {} Err(ty_err) => { let ty_err = ty_err.to_string(tcx); - return Err(tcx.dcx().span_delayed_bug( + tcx.dcx().span_bug( span, format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"), - )); + ); } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 1dd27f0cc53..42a64d8670d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -734,11 +734,8 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( remapped_types.insert(def_id, ty::EarlyBinder::bind(ty)); } Err(err) => { - let reported = tcx.dcx().span_delayed_bug( - return_span, - format!("could not fully resolve: {ty} => {err:?}"), - ); - remapped_types.insert(def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, reported))); + tcx.dcx() + .span_bug(return_span, format!("could not fully resolve: {ty} => {err:?}")); } } } @@ -917,7 +914,7 @@ impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { .with_note(format!("hidden type inferred to be `{}`", self.ty)) .emit() } - _ => self.tcx.dcx().delayed_bug("should've been able to remap region"), + _ => self.tcx.dcx().bug("should've been able to remap region"), }; return Err(guar); }; @@ -1276,9 +1273,8 @@ fn compare_number_of_generics<'tcx>( // inheriting the generics from will also have mismatched arguments, and // we'll report an error for that instead. Delay a bug for safety, though. if trait_.is_impl_trait_in_trait() { - return Err(tcx.dcx().delayed_bug( - "errors comparing numbers of generics of trait/impl functions were not emitted", - )); + tcx.dcx() + .bug("errors comparing numbers of generics of trait/impl functions were not emitted"); } let matchings = [ diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 3d3b21eabb3..da40d6a860e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -154,8 +154,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( trait_m_sig.inputs_and_output, )); if !ocx.select_all_or_error().is_empty() { - tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (selection)"); - return; + tcx.dcx().bug("encountered errors when checking RPITIT refinement (selection)"); } let outlives_env = OutlivesEnvironment::with_bounds( param_env, @@ -163,13 +162,11 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( ); let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { - tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (regions)"); - return; + tcx.dcx().bug("encountered errors when checking RPITIT refinement (regions)"); } // Resolve any lifetime variables that may have been introduced during normalization. let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else { - tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (resolution)"); - return; + tcx.dcx().bug("encountered errors when checking RPITIT refinement (resolution)"); }; // For quicker lookup, use an `IndexSet` (we don't use one earlier because diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 82a6b6b6f2c..9b46b415491 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -67,11 +67,10 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro // already checked by coherence, but compilation may // not have been terminated. let span = tcx.def_span(drop_impl_did); - let reported = tcx.dcx().span_delayed_bug( + tcx.dcx().span_bug( span, format!("should have been rejected by coherence check: {dtor_self_type}"), ); - Err(reported) } } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e7506cee60e..81d8a51485f 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1088,10 +1088,8 @@ fn check_type_defn<'tcx>( let ty = tcx.type_of(variant.tail().did).instantiate_identity(); let ty = tcx.erase_regions(ty); if ty.has_infer() { - tcx.dcx() - .span_delayed_bug(item.span, format!("inference variables in {ty:?}")); - // Just treat unresolved type expression as if it needs drop. - true + // Unresolved type expression. + tcx.dcx().span_bug(item.span, format!("inference variables in {ty:?}")); } else { ty.needs_drop(tcx, tcx.param_env(item.owner_id)) } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 9cc6c16c126..410a069f956 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -315,7 +315,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { if is_host_effect { if let Some(idx) = host_effect_index { - tcx.dcx().span_delayed_bug( + tcx.dcx().span_bug( param.span, format!("parent also has host effect param? index: {idx}, def: {def_id:?}"), ); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 325a0ee9a18..efde4e11c79 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1331,7 +1331,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } - self.tcx.dcx().span_delayed_bug( + self.tcx.dcx().span_bug( lifetime_ref.ident.span, format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,), ); @@ -1465,10 +1465,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } - self.tcx.dcx().span_delayed_bug( - self.tcx.hir().span(hir_id), - format!("could not resolve {param_def_id:?}"), - ); + self.tcx + .dcx() + .span_bug(self.tcx.hir().span(hir_id), format!("could not resolve {param_def_id:?}")); } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 48fc2900b0d..b662d23c271 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -139,10 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Never | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { - let guar = self - .dcx() - .span_delayed_bug(span, format!("`{t:?}` should be sized but is not?")); - return Err(guar); + self.dcx().span_bug(span, format!("`{t:?}` should be sized but is not?")); } }) } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 0f6544c3e1f..0a636fa9eac 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -76,16 +76,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from ! to `expected`. if ty.is_never() { - if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) { - let reported = self.dcx().span_delayed_bug( - expr.span, - "expression with never type wound up being adjusted", - ); - return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] { - target.to_owned() - } else { - Ty::new_error(self.tcx(), reported) - }; + if let Some(_) = self.typeck_results.borrow().adjustments().get(expr.hir_id) { + self.dcx() + .span_bug(expr.span, "expression with never type wound up being adjusted"); } let adj_ty = self.next_ty_var(TypeVariableOrigin { @@ -1325,7 +1318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // permit break with a value [1]. if ctxt.coerce.is_none() && !ctxt.may_break { // [1] - self.dcx().span_delayed_bug(body.span, "no coercion, but loop may not break"); + self.dcx().span_bug(body.span, "no coercion, but loop may not break"); } ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| Ty::new_unit(self.tcx)) } diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 2dee5093e87..fd62afbae96 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -48,8 +48,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let to = normalize(to); trace!(?from, ?to); if from.has_non_region_infer() || to.has_non_region_infer() { - tcx.dcx().span_delayed_bug(span, "argument to transmute has inference variables"); - return; + tcx.dcx().span_bug(span, "argument to transmute has inference variables"); } // Transmutes that are only changing lifetimes are always ok. if from == to { diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index fefaf996725..c300ec7444b 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -570,8 +570,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { _ => { self.tcx() .dcx() - .span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT"); - Err(()) + .span_bug(span, "struct or tuple struct pattern not applied to an ADT"); } } } @@ -583,8 +582,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { match ty.kind() { ty::Tuple(args) => Ok(args.len()), _ => { - self.tcx().dcx().span_delayed_bug(span, "tuple pattern not applied to a tuple"); - Err(()) + self.tcx().dcx().span_bug(span, "tuple pattern not applied to a tuple"); } } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index d7edc70bce8..a58e194e20a 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -804,11 +804,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { if new_trait_ref.has_non_region_bound_vars() { - this.dcx().span_delayed_bug( + this.dcx().span_bug( this.span, "tried to select method from HRTB with non-lifetime bound vars", ); - return; } let new_trait_ref = this.instantiate_bound_regions_with_erased(new_trait_ref); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 005d217fdc4..13f33abaa64 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -924,7 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: item_span, .. })) => { - tcx.dcx().span_delayed_bug( + tcx.dcx().span_bug( *item_span, "auto trait is invoked with no method error, but no error reported?", ); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 73689b45b95..b15c9ef9018 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1085,10 +1085,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let variant = match res { Res::Err => { - let e = tcx.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); - self.set_tainted_by_errors(e); - on_error(e); - return Ty::new_error(tcx, e); + tcx.dcx().span_bug(pat.span, "`Res::Err` but no error emitted"); } Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => { let e = report_unexpected_res(res); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index c0a99e5cc41..643fe83e898 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -303,7 +303,7 @@ where // Ignore this, we presume it will yield an error later, // since if a type variable is not resolved by this point // it never will be. - self.tcx.dcx().span_delayed_bug( + self.tcx.dcx().span_bug( origin.span(), format!("unresolved inference variable in outlives: {v:?}"), ); diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 3ef37bf3466..515f44c914d 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -175,11 +175,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // Ignore this, we presume it will yield an error later, since // if a type variable is not resolved by this point it never // will be. - self.tcx - .dcx() - .delayed_bug(format!("unresolved inference variable in outlives: {v:?}")); - // Add a bound that never holds. - VerifyBound::AnyBound(vec![]) + self.tcx.dcx().bug(format!("unresolved inference variable in outlives: {v:?}")); } } } diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs index 4ba4bd38e9f..4cc6457df7a 100644 --- a/compiler/rustc_infer/src/infer/relate/nll.rs +++ b/compiler/rustc_infer/src/infer/relate/nll.rs @@ -420,11 +420,9 @@ where match b.kind() { ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { // Forbid inference variables in the RHS. - self.infcx.dcx().span_delayed_bug( - self.delegate.span(), - format!("unexpected inference var {b:?}",), - ); - Ok(a) + self.infcx + .dcx() + .span_bug(self.delegate.span(), format!("unexpected inference var {b:?}",)); } // FIXME(invariance): see the related FIXME above. _ => self.infcx.super_combine_consts(self, a, b), diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index a03ee78a29a..4287b382604 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -410,8 +410,7 @@ impl<'tcx> TypeckResults<'tcx> { pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option { self.pat_binding_modes().get(id).copied().or_else(|| { - s.dcx().span_delayed_bug(sp, "missing binding mode"); - None + s.dcx().span_bug(sp, "missing binding mode"); }) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 3f539945841..95d55a7081d 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -356,9 +356,7 @@ impl<'tcx> TyCtxt<'tcx> { } let Some(item_id) = self.associated_item_def_ids(impl_did).first() else { - self.dcx() - .span_delayed_bug(self.def_span(impl_did), "Drop impl without drop function"); - return; + self.dcx().span_bug(self.def_span(impl_did), "Drop impl without drop function"); }; if let Some((old_item_id, _)) = dtor_candidate { diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index a67ec991582..dae6c0b9d68 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -42,7 +42,7 @@ fn opt_span_bug_fmt>( /// delayed bug, so what is the point of this? It exists to help us test the interaction of delayed /// bugs with the query system and incremental. pub fn trigger_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) { - tcx.dcx().span_delayed_bug( + tcx.dcx().span_bug( tcx.def_span(key), "delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]", ); diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 7c3d2671d59..d66540d8e79 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -110,15 +110,12 @@ fn lit_to_mir_constant<'tcx>( let LitToConstInput { lit, ty, neg } = lit_input; let trunc = |n| { let param_ty = ty::ParamEnv::reveal_all().and(ty); - let width = - tcx.layout_of(param_ty) - .map_err(|_| { - LitToConstError::Reported(tcx.dcx().delayed_bug(format!( - "couldn't compute width of literal: {:?}", - lit_input.lit - ))) - })? - .size; + let width = tcx + .layout_of(param_ty) + .map_err(|_| { + tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit)) + })? + .size; trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = width.truncate(n); trace!("trunc result: {}", result); diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index d444de8b28e..46580432f13 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -12,15 +12,12 @@ pub(crate) fn lit_to_const<'tcx>( let trunc = |n| { let param_ty = ParamEnv::reveal_all().and(ty); - let width = - tcx.layout_of(param_ty) - .map_err(|_| { - LitToConstError::Reported(tcx.dcx().delayed_bug(format!( - "couldn't compute width of literal: {:?}", - lit_input.lit - ))) - })? - .size; + let width = tcx + .layout_of(param_ty) + .map_err(|_| { + tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit)) + })? + .size; trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = width.truncate(n); trace!("trunc result: {}", result); @@ -59,15 +56,11 @@ pub(crate) fn lit_to_const<'tcx>( } (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()), (ast::LitKind::Float(n, _), ty::Float(fty)) => { - let bits = - parse_float_into_scalar(*n, *fty, neg) - .ok_or_else(|| { - LitToConstError::Reported(tcx.dcx().delayed_bug(format!( - "couldn't parse float literal: {:?}", - lit_input.lit - ))) - })? - .assert_int(); + let bits = parse_float_into_scalar(*n, *fty, neg) + .ok_or_else(|| { + tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit)) + })? + .assert_int(); ty::ValTree::from_scalar_int(bits) } (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 1a5cf13e289..0329e1d3096 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -175,7 +175,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ) -> Result, ErrorGuaranteed> { if lo_expr.is_none() && hi_expr.is_none() { let msg = "found twice-open range pattern (`..`) outside of error recovery"; - return Err(self.tcx.dcx().span_delayed_bug(span, msg)); + self.tcx.dcx().span_bug(span, msg); } let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?; diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index a0851aa557b..54b13a40e92 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1615,11 +1615,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { (args.discr_ty(tcx), coroutine_kind.movability() == hir::Movability::Movable) } _ => { - tcx.dcx().span_delayed_bug( - body.span, - format!("unexpected coroutine type {coroutine_ty}"), - ); - return; + tcx.dcx().span_bug(body.span, format!("unexpected coroutine type {coroutine_ty}")); } }; diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 8575f552f0a..03d952abad1 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -380,7 +380,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { LookupResult::Parent(None) => {} LookupResult::Parent(Some(_)) => { if !replace { - self.tcx.dcx().span_delayed_bug( + self.tcx.dcx().span_bug( terminator.source_info.span, format!("drop of untracked value {bb:?}"), ); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6aacb0e17d5..676bc9db4a9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3681,13 +3681,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { None } Res::SelfCtor(_) => { + // njn: remove comment? // We resolve `Self` in pattern position as an ident sometimes during recovery, // so delay a bug instead of ICEing. - self.r.dcx().span_delayed_bug( + self.r.dcx().span_bug( ident.span, "unexpected `SelfCtor` in pattern, expected identifier" ); - None } _ => span_bug!( ident.span, diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 1edf6b11fc3..79f423756fd 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -62,14 +62,12 @@ pub fn is_const_evaluatable<'tcx>( match unexpanded_ct.kind() { ty::ConstKind::Expr(_) => { + // njn: ? // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, // but currently it is not possible to evaluate `ConstKind::Expr` so we are unable // to tell if it is evaluatable or not. For now we just ICE until this is // implemented. - Err(NotConstEvaluatable::Error(tcx.dcx().span_delayed_bug( - span, - "evaluating `ConstKind::Expr` is not currently supported", - ))) + tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported"); } ty::ConstKind::Unevaluated(uv) => { let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 4f674ac7583..aa8bd5fdc86 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -3313,7 +3313,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { expected_trait_ref.self_ty().error_reported()?; let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else { - return Err(self.dcx().delayed_bug("bound vars outside binder")); + self.dcx().bug("bound vars outside binder"); }; let found_did = match *found_trait_ty.kind() { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 9eec60ea06c..43f709352a2 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -172,7 +172,7 @@ fn do_normalize_predicates<'tcx>( // the normalized predicates. let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { - tcx.dcx().span_delayed_bug( + tcx.dcx().span_bug( span, format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"), ); diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 8b2e8b54aee..c4110df45db 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -100,7 +100,7 @@ fn implied_outlives_bounds<'a, 'tcx>( let errors = ocx.select_all_or_error(); if !errors.is_empty() { - infcx.dcx().span_delayed_bug( + infcx.dcx().span_bug( span, "implied_outlives_bounds failed to solve obligations from instantiation", ); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 9c532ea4d8d..dc5b62fbd1c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -645,7 +645,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) { Ok(mut ok) => obligations.append(&mut ok.obligations), Err(_) => { - tcx.dcx().span_delayed_bug( + tcx.dcx().span_bug( cause.span, format!( "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not" @@ -1190,11 +1190,10 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { // These traits have no associated types. - selcx.tcx().dcx().span_delayed_bug( + selcx.tcx().dcx().span_bug( obligation.cause.span, format!("Cannot project an associated type from `{impl_source:?}`"), ); - return Err(()); } }; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index d533e69a4fa..a8d9b0f42d9 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -82,7 +82,7 @@ where let value = infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(infcx); let value = op(&ocx).map_err(|_| { - infcx.dcx().span_delayed_bug(span, format!("error performing operation: {name}")) + infcx.dcx().span_bug(span, format!("error performing operation: {name}")) })?; let errors = ocx.select_all_or_error(); if errors.is_empty() { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index fb09f094d37..12ee778ee05 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -190,10 +190,9 @@ where } } if !progress { - return Err(infcx.dcx().span_delayed_bug( - span, - format!("ambiguity processing {obligations:?} from {self:?}"), - )); + infcx + .dcx() + .span_bug(span, format!("ambiguity processing {obligations:?} from {self:?}")); } } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 96f8148bf72..b00330d335e 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -90,8 +90,7 @@ fn univariant_uninterned<'tcx>( let dl = cx.data_layout(); let pack = repr.pack; if pack.is_some() && repr.align.is_some() { - cx.tcx.dcx().delayed_bug("struct cannot be packed and aligned"); - return Err(cx.tcx.arena.alloc(LayoutError::Unknown(ty))); + cx.tcx.dcx().bug("struct cannot be packed and aligned"); } cx.univariant(dl, fields, repr, kind).ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty))) diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 329cf32cad5..86c7551882a 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -337,7 +337,7 @@ impl<'tcx> TypeVisitor> for ImplTraitInAssocTypeCollector<'tcx> { .instantiate(self.0.tcx, impl_args) .visit_with(self); } else { - self.0.tcx.dcx().span_delayed_bug( + self.0.tcx.dcx().span_bug( self.0.tcx.def_span(assoc.def_id), "item had incorrect args", ); -- cgit 1.4.1-3-g733a5 From 2903bbbc156fb9707b43038af6723844fd4ccf29 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 Feb 2024 09:36:28 +1100 Subject: Convert `bug`s back to `delayed_bug`s. This commit undoes some of the previous commit's mechanical changes, based on human judgment. --- compiler/rustc_borrowck/src/diagnostics/region_name.rs | 4 ++-- .../rustc_borrowck/src/type_check/free_region_relations.rs | 6 +++++- compiler/rustc_const_eval/src/const_eval/machine.rs | 2 +- compiler/rustc_hir_analysis/src/check/compare_impl_item.rs | 14 +++++++++++++- .../src/check/compare_impl_item/refine.rs | 9 +++++++++ compiler/rustc_hir_analysis/src/check/dropck.rs | 3 ++- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 8 ++------ compiler/rustc_hir_typeck/src/expr.rs | 3 +-- compiler/rustc_hir_typeck/src/intrinsicck.rs | 3 +++ compiler/rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_infer/src/infer/outlives/obligations.rs | 2 +- compiler/rustc_infer/src/infer/outlives/verify.rs | 6 +++++- compiler/rustc_infer/src/infer/relate/nll.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 4 +++- compiler/rustc_middle/src/util/bug.rs | 2 +- compiler/rustc_mir_build/src/build/expr/as_constant.rs | 10 +++++----- compiler/rustc_mir_build/src/thir/constant.rs | 10 +++++----- compiler/rustc_resolve/src/late.rs | 4 ++-- .../rustc_trait_selection/src/traits/const_evaluatable.rs | 9 ++++----- compiler/rustc_trait_selection/src/traits/mod.rs | 2 ++ compiler/rustc_trait_selection/src/traits/project.rs | 7 +++---- .../src/traits/query/type_op/custom.rs | 2 +- tests/ui/drop/missing-drop-method.rs | 4 ++++ tests/ui/drop/missing-drop-method.stderr | 11 +++++++++++ 24 files changed, 87 insertions(+), 42 deletions(-) create mode 100644 tests/ui/drop/missing-drop-method.rs create mode 100644 tests/ui/drop/missing-drop-method.stderr (limited to 'compiler') diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index fea8c5a6de6..e228bef1139 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -626,8 +626,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { | GenericArgKind::Const(_), _, ) => { - // HIR lowering sometimes doesn't catch this in erroneous - // programs, so we need to use span_delayed_bug here. See #82126. + // This was previously a `span_delayed_bug` and could be + // reached by the test for #82126, but no longer. self.dcx().span_bug( hir_arg.span(), format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"), diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 0fc04175705..897918fb0a4 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -316,7 +316,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { .and(type_op::normalize::Normalize::new(ty)) .fully_perform(self.infcx, span) else { - tcx.dcx().span_bug(span, format!("failed to normalize {ty:?}")); + // Note: this path is currently not reached in any test, so + // any example that triggers this would be worth minimizing + // and converting into a test. + tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}")); + continue; }; constraints.extend(c); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 77744945b12..946ffc05cc1 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -622,7 +622,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ); // If this was a hard error, don't bother continuing evaluation. if is_error { - let guard: rustc_errors::ErrorGuaranteed = ecx + let guard = ecx .tcx .dcx() .span_delayed_bug(span, "The deny lint should have already errored"); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 42a64d8670d..435e251b130 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -734,6 +734,10 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( remapped_types.insert(def_id, ty::EarlyBinder::bind(ty)); } Err(err) => { + // This code path is not reached in any tests, but may be + // reachable. If this is triggered, it should be converted to + // `span_delayed_bug` and the triggering case turned into a + // test. tcx.dcx() .span_bug(return_span, format!("could not fully resolve: {ty} => {err:?}")); } @@ -914,7 +918,13 @@ impl<'tcx> ty::FallibleTypeFolder> for RemapHiddenTyRegions<'tcx> { .with_note(format!("hidden type inferred to be `{}`", self.ty)) .emit() } - _ => self.tcx.dcx().bug("should've been able to remap region"), + _ => { + // This code path is not reached in any tests, but may be + // reachable. If this is triggered, it should be converted + // to `delayed_bug` and the triggering case turned into a + // test. + self.tcx.dcx().bug("should've been able to remap region"); + } }; return Err(guar); }; @@ -1273,6 +1283,8 @@ fn compare_number_of_generics<'tcx>( // inheriting the generics from will also have mismatched arguments, and // we'll report an error for that instead. Delay a bug for safety, though. if trait_.is_impl_trait_in_trait() { + // FIXME: no tests trigger this. If you find example code that does + // trigger this, please add it to the test suite. tcx.dcx() .bug("errors comparing numbers of generics of trait/impl functions were not emitted"); } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index da40d6a860e..7bdbab4325c 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -154,6 +154,9 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( trait_m_sig.inputs_and_output, )); if !ocx.select_all_or_error().is_empty() { + // This code path is not reached in any tests, but may be reachable. If + // this is triggered, it should be converted to `delayed_bug` and the + // triggering case turned into a test. tcx.dcx().bug("encountered errors when checking RPITIT refinement (selection)"); } let outlives_env = OutlivesEnvironment::with_bounds( @@ -162,10 +165,16 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( ); let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { + // This code path is not reached in any tests, but may be reachable. If + // this is triggered, it should be converted to `delayed_bug` and the + // triggering case turned into a test. tcx.dcx().bug("encountered errors when checking RPITIT refinement (regions)"); } // Resolve any lifetime variables that may have been introduced during normalization. let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else { + // This code path is not reached in any tests, but may be reachable. If + // this is triggered, it should be converted to `delayed_bug` and the + // triggering case turned into a test. tcx.dcx().bug("encountered errors when checking RPITIT refinement (resolution)"); }; diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 9b46b415491..82a6b6b6f2c 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -67,10 +67,11 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro // already checked by coherence, but compilation may // not have been terminated. let span = tcx.def_span(drop_impl_did); - tcx.dcx().span_bug( + let reported = tcx.dcx().span_delayed_bug( span, format!("should have been rejected by coherence check: {dtor_self_type}"), ); + Err(reported) } } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 81d8a51485f..f03d0f8a885 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1087,12 +1087,8 @@ fn check_type_defn<'tcx>( packed && { let ty = tcx.type_of(variant.tail().did).instantiate_identity(); let ty = tcx.erase_regions(ty); - if ty.has_infer() { - // Unresolved type expression. - tcx.dcx().span_bug(item.span, format!("inference variables in {ty:?}")); - } else { - ty.needs_drop(tcx, tcx.param_env(item.owner_id)) - } + assert!(!ty.has_infer()); + ty.needs_drop(tcx, tcx.param_env(item.owner_id)) } }; // All fields (except for possibly the last) should be sized. diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 0a636fa9eac..89cc46dc5ab 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1315,9 +1315,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the LUB of the breaks (possibly ! if none); else, it // is nil. This makes sense because infinite loops // (which would have type !) are only possible iff we - // permit break with a value [1]. + // permit break with a value. if ctxt.coerce.is_none() && !ctxt.may_break { - // [1] self.dcx().span_bug(body.span, "no coercion, but loop may not break"); } ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| Ty::new_unit(self.tcx)) diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index fd62afbae96..9e3867e630d 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -48,6 +48,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let to = normalize(to); trace!(?from, ?to); if from.has_non_region_infer() || to.has_non_region_infer() { + // Note: this path is currently not reached in any test, so any + // example that triggers this would be worth minimizing and + // converting into a test. tcx.dcx().span_bug(span, "argument to transmute has inference variables"); } // Transmutes that are only changing lifetimes are always ok. diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 13f33abaa64..005d217fdc4 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -924,7 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: item_span, .. })) => { - tcx.dcx().span_bug( + tcx.dcx().span_delayed_bug( *item_span, "auto trait is invoked with no method error, but no error reported?", ); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 643fe83e898..c0a99e5cc41 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -303,7 +303,7 @@ where // Ignore this, we presume it will yield an error later, // since if a type variable is not resolved by this point // it never will be. - self.tcx.dcx().span_bug( + self.tcx.dcx().span_delayed_bug( origin.span(), format!("unresolved inference variable in outlives: {v:?}"), ); diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 515f44c914d..3ef37bf3466 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -175,7 +175,11 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // Ignore this, we presume it will yield an error later, since // if a type variable is not resolved by this point it never // will be. - self.tcx.dcx().bug(format!("unresolved inference variable in outlives: {v:?}")); + self.tcx + .dcx() + .delayed_bug(format!("unresolved inference variable in outlives: {v:?}")); + // Add a bound that never holds. + VerifyBound::AnyBound(vec![]) } } } diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs index 4cc6457df7a..87a1ae7bbac 100644 --- a/compiler/rustc_infer/src/infer/relate/nll.rs +++ b/compiler/rustc_infer/src/infer/relate/nll.rs @@ -422,7 +422,7 @@ where // Forbid inference variables in the RHS. self.infcx .dcx() - .span_bug(self.delegate.span(), format!("unexpected inference var {b:?}",)); + .span_bug(self.delegate.span(), format!("unexpected inference var {b:?}")); } // FIXME(invariance): see the related FIXME above. _ => self.infcx.super_combine_consts(self, a, b), diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 95d55a7081d..3f539945841 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -356,7 +356,9 @@ impl<'tcx> TyCtxt<'tcx> { } let Some(item_id) = self.associated_item_def_ids(impl_did).first() else { - self.dcx().span_bug(self.def_span(impl_did), "Drop impl without drop function"); + self.dcx() + .span_delayed_bug(self.def_span(impl_did), "Drop impl without drop function"); + return; }; if let Some((old_item_id, _)) = dtor_candidate { diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index dae6c0b9d68..a67ec991582 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -42,7 +42,7 @@ fn opt_span_bug_fmt>( /// delayed bug, so what is the point of this? It exists to help us test the interaction of delayed /// bugs with the query system and incremental. pub fn trigger_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) { - tcx.dcx().span_bug( + tcx.dcx().span_delayed_bug( tcx.def_span(key), "delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]", ); diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index d66540d8e79..a557f61b016 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -110,12 +110,12 @@ fn lit_to_mir_constant<'tcx>( let LitToConstInput { lit, ty, neg } = lit_input; let trunc = |n| { let param_ty = ty::ParamEnv::reveal_all().and(ty); - let width = tcx - .layout_of(param_ty) - .map_err(|_| { + let width = match tcx.layout_of(param_ty) { + Ok(layout) => layout.size, + Err(_) => { tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit)) - })? - .size; + } + }; trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = width.truncate(n); trace!("trunc result: {}", result); diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 46580432f13..65cc13286af 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -12,12 +12,12 @@ pub(crate) fn lit_to_const<'tcx>( let trunc = |n| { let param_ty = ParamEnv::reveal_all().and(ty); - let width = tcx - .layout_of(param_ty) - .map_err(|_| { + let width = match tcx.layout_of(param_ty) { + Ok(layout) => layout.size, + Err(_) => { tcx.dcx().bug(format!("couldn't compute width of literal: {:?}", lit_input.lit)) - })? - .size; + } + }; trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = width.truncate(n); trace!("trunc result: {}", result); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 676bc9db4a9..2f4da29133f 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3681,9 +3681,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { None } Res::SelfCtor(_) => { - // njn: remove comment? // We resolve `Self` in pattern position as an ident sometimes during recovery, - // so delay a bug instead of ICEing. + // so delay a bug instead of ICEing. (Note: is this no longer true? We now ICE. If + // this triggers, please convert to a delayed bug and add a test.) self.r.dcx().span_bug( ident.span, "unexpected `SelfCtor` in pattern, expected identifier" diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 79f423756fd..189e1ba54bc 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -62,11 +62,10 @@ pub fn is_const_evaluatable<'tcx>( match unexpanded_ct.kind() { ty::ConstKind::Expr(_) => { - // njn: ? - // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, - // but currently it is not possible to evaluate `ConstKind::Expr` so we are unable - // to tell if it is evaluatable or not. For now we just ICE until this is - // implemented. + // FIXME(generic_const_exprs): we have a fully concrete `ConstKind::Expr`, but + // haven't implemented evaluating `ConstKind::Expr` yet, so we are unable to tell + // if it is evaluatable or not. As this is unreachable for now, we can simple ICE + // here. tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported"); } ty::ConstKind::Unevaluated(uv) => { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 43f709352a2..cac53796747 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -172,6 +172,8 @@ fn do_normalize_predicates<'tcx>( // the normalized predicates. let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { + // @lcnr: Let's still ICE here for now. I want a test case + // for that. tcx.dcx().span_bug( span, format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"), diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index dc5b62fbd1c..f8de19043e1 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -647,9 +647,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( Err(_) => { tcx.dcx().span_bug( cause.span, - format!( - "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not" - ), + format!("{self_ty:?} was equal to {impl_ty:?} during selection but now it is not"), ); } } @@ -1190,10 +1188,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { // These traits have no associated types. - selcx.tcx().dcx().span_bug( + selcx.tcx().dcx().span_delayed_bug( obligation.cause.span, format!("Cannot project an associated type from `{impl_source:?}`"), ); + return Err(()) } }; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index a8d9b0f42d9..d533e69a4fa 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -82,7 +82,7 @@ where let value = infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(infcx); let value = op(&ocx).map_err(|_| { - infcx.dcx().span_bug(span, format!("error performing operation: {name}")) + infcx.dcx().span_delayed_bug(span, format!("error performing operation: {name}")) })?; let errors = ocx.select_all_or_error(); if errors.is_empty() { diff --git a/tests/ui/drop/missing-drop-method.rs b/tests/ui/drop/missing-drop-method.rs new file mode 100644 index 00000000000..5828fd6c063 --- /dev/null +++ b/tests/ui/drop/missing-drop-method.rs @@ -0,0 +1,4 @@ +struct DropNoMethod; +impl Drop for DropNoMethod {} //~ ERROR not all trait items implemented, missing: `drop` + +fn main() {} diff --git a/tests/ui/drop/missing-drop-method.stderr b/tests/ui/drop/missing-drop-method.stderr new file mode 100644 index 00000000000..1128f33e627 --- /dev/null +++ b/tests/ui/drop/missing-drop-method.stderr @@ -0,0 +1,11 @@ +error[E0046]: not all trait items implemented, missing: `drop` + --> $DIR/missing-drop-method.rs:2:1 + | +LL | impl Drop for DropNoMethod {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation + | + = help: implement the missing item: `fn drop(&mut self) { todo!() }` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0046`. -- cgit 1.4.1-3-g733a5 From 8f20a54c6d4440ec58f78549878b9baabbf7f218 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 21 Feb 2024 09:37:30 +1100 Subject: Merge `diagnostic_builder.rs` into `diagnostic.rs`. Because: - `diagnostic_builder.rs` is small (282 lines), - `Diagnostic` and `DiagnosticBuilder` are closely related types, and - there's already an `impl DiagnosticBuilder` block in `diagnostic.rs`. At the same time, reorder a few of things already in `diagnostic.rs`, e.g. move `struct Diagnostic` just before `impl Diagnostic`. This commit only moves code around. There are no functional changes. --- compiler/rustc_errors/src/diagnostic.rs | 429 +++++++++++++++++---- compiler/rustc_errors/src/diagnostic_builder.rs | 282 -------------- compiler/rustc_errors/src/lib.rs | 10 +- .../diagnostic-derive-doc-comment-field.stderr | 4 +- .../session-diagnostic/diagnostic-derive.stderr | 2 +- 5 files changed, 355 insertions(+), 372 deletions(-) delete mode 100644 compiler/rustc_errors/src/diagnostic_builder.rs (limited to 'compiler') diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 57610635ee6..686a3dc66a1 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,19 +1,22 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, ErrCode, Level, - MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, + CodeSuggestion, DiagCtxt, DiagnosticMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level, + MultiSpan, StashKey, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::fx::FxIndexMap; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; use rustc_error_messages::FluentValue; use rustc_lint_defs::{Applicability, LintExpectationId}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt::{self, Debug}; use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; -use std::panic::Location; +use std::panic; +use std::thread::panicking; /// Error type for `Diagnostic`'s `suggestions` field, indicating that /// `.disable_suggestions()` was called on the `Diagnostic`. @@ -40,6 +43,86 @@ pub enum DiagnosticArgValue { StrListSepByAnd(Vec>), } +/// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee" +/// (or "proof") token that the emission happened. +pub trait EmissionGuarantee: Sized { + /// This exists so that bugs and fatal errors can both result in `!` (an + /// abort) when emitted, but have different aborting behaviour. + type EmitResult = Self; + + /// Implementation of `DiagnosticBuilder::emit`, fully controlled by each + /// `impl` of `EmissionGuarantee`, to make it impossible to create a value + /// of `Self::EmitResult` without actually performing the emission. + #[track_caller] + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult; +} + +impl EmissionGuarantee for ErrorGuaranteed { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + db.emit_producing_error_guaranteed() + } +} + +impl EmissionGuarantee for () { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + db.emit_producing_nothing(); + } +} + +/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for +/// bug diagnostics. +#[derive(Copy, Clone)] +pub struct BugAbort; + +impl EmissionGuarantee for BugAbort { + type EmitResult = !; + + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + db.emit_producing_nothing(); + panic::panic_any(ExplicitBug); + } +} + +/// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for +/// fatal diagnostics. +#[derive(Copy, Clone)] +pub struct FatalAbort; + +impl EmissionGuarantee for FatalAbort { + type EmitResult = !; + + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + db.emit_producing_nothing(); + crate::FatalError.raise() + } +} + +impl EmissionGuarantee for rustc_span::fatal_error::FatalError { + fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { + db.emit_producing_nothing(); + rustc_span::fatal_error::FatalError + } +} + +/// Trait implemented by error types. This is rarely implemented manually. Instead, use +/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. +#[rustc_diagnostic_item = "IntoDiagnostic"] +pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { + /// Write out as a diagnostic out of `DiagCtxt`. + #[must_use] + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G>; +} + +impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned +where + T: IntoDiagnostic<'a, G>, + G: EmissionGuarantee, +{ + fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { + self.node.into_diagnostic(dcx, level).with_span(self.span) + } +} + /// Converts a value of a type into a `DiagnosticArg` (typically a field of an `IntoDiagnostic` /// struct). Implemented as a custom trait rather than `From` so that it is implemented on the type /// being converted rather than on `DiagnosticArgValue`, which enables types from other `rustc_*` @@ -98,36 +181,6 @@ pub trait DecorateLint<'a, G: EmissionGuarantee> { fn msg(&self) -> DiagnosticMessage; } -/// The main part of a diagnostic. Note that `DiagnosticBuilder`, which wraps -/// this type, is used for most operations, and should be used instead whenever -/// possible. This type should only be used when `DiagnosticBuilder`'s lifetime -/// causes difficulties, e.g. when storing diagnostics within `DiagCtxt`. -#[must_use] -#[derive(Clone, Debug, Encodable, Decodable)] -pub struct Diagnostic { - // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes, - // outside of what methods in this crate themselves allow. - pub(crate) level: Level, - - pub messages: Vec<(DiagnosticMessage, Style)>, - pub code: Option, - pub span: MultiSpan, - pub children: Vec, - pub suggestions: Result, SuggestionsDisabled>, - args: FxIndexMap, - - /// This is not used for highlighting or rendering any error message. Rather, it can be used - /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of - /// `span` if there is one. Otherwise, it is `DUMMY_SP`. - pub sort_span: Span, - - pub is_lint: Option, - - /// With `-Ztrack_diagnostics` enabled, - /// we print where in rustc this error was emitted. - pub(crate) emitted_at: DiagnosticLocation, -} - #[derive(Clone, Debug, Encodable, Decodable)] pub struct DiagnosticLocation { file: Cow<'static, str>, @@ -138,7 +191,7 @@ pub struct DiagnosticLocation { impl DiagnosticLocation { #[track_caller] fn caller() -> Self { - let loc = Location::caller(); + let loc = panic::Location::caller(); DiagnosticLocation { file: loc.file().into(), line: loc.line(), col: loc.column() } } } @@ -157,15 +210,6 @@ pub struct IsLint { has_future_breakage: bool, } -/// A "sub"-diagnostic attached to a parent diagnostic. -/// For example, a note attached to an error. -#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] -pub struct SubDiagnostic { - pub level: Level, - pub messages: Vec<(DiagnosticMessage, Style)>, - pub span: MultiSpan, -} - #[derive(Debug, PartialEq, Eq)] pub struct DiagnosticStyledString(pub Vec); @@ -215,6 +259,36 @@ impl StringPart { } } +/// The main part of a diagnostic. Note that `DiagnosticBuilder`, which wraps +/// this type, is used for most operations, and should be used instead whenever +/// possible. This type should only be used when `DiagnosticBuilder`'s lifetime +/// causes difficulties, e.g. when storing diagnostics within `DiagCtxt`. +#[must_use] +#[derive(Clone, Debug, Encodable, Decodable)] +pub struct Diagnostic { + // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes, + // outside of what methods in this crate themselves allow. + pub(crate) level: Level, + + pub messages: Vec<(DiagnosticMessage, Style)>, + pub code: Option, + pub span: MultiSpan, + pub children: Vec, + pub suggestions: Result, SuggestionsDisabled>, + args: FxIndexMap, + + /// This is not used for highlighting or rendering any error message. Rather, it can be used + /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of + /// `span` if there is one. Otherwise, it is `DUMMY_SP`. + pub sort_span: Span, + + pub is_lint: Option, + + /// With `-Ztrack_diagnostics` enabled, + /// we print where in rustc this error was emitted. + pub(crate) emitted_at: DiagnosticLocation, +} + impl Diagnostic { #[track_caller] pub fn new>(level: Level, message: M) -> Self { @@ -336,6 +410,120 @@ impl Diagnostic { pub fn replace_args(&mut self, args: FxIndexMap) { self.args = args; } + + /// Fields used for Hash, and PartialEq trait. + fn keys( + &self, + ) -> ( + &Level, + &[(DiagnosticMessage, Style)], + &Option, + &MultiSpan, + &[SubDiagnostic], + &Result, SuggestionsDisabled>, + Vec<(&DiagnosticArgName, &DiagnosticArgValue)>, + &Option, + ) { + ( + &self.level, + &self.messages, + &self.code, + &self.span, + &self.children, + &self.suggestions, + self.args().collect(), + // omit self.sort_span + &self.is_lint, + // omit self.emitted_at + ) + } +} + +impl Hash for Diagnostic { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.keys().hash(state); + } +} + +impl PartialEq for Diagnostic { + fn eq(&self, other: &Self) -> bool { + self.keys() == other.keys() + } +} + +/// A "sub"-diagnostic attached to a parent diagnostic. +/// For example, a note attached to an error. +#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] +pub struct SubDiagnostic { + pub level: Level, + pub messages: Vec<(DiagnosticMessage, Style)>, + pub span: MultiSpan, +} + +/// Used for emitting structured error messages and other diagnostic information. +/// Wraps a `Diagnostic`, adding some useful things. +/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check +/// that it has been emitted or cancelled. +/// - The `EmissionGuarantee`, which determines the type returned from `emit`. +/// +/// Each constructed `DiagnosticBuilder` must be consumed by a function such as +/// `emit`, `cancel`, `delay_as_bug`, or `into_diagnostic`. A panic occurrs if a +/// `DiagnosticBuilder` is dropped without being consumed by one of these +/// functions. +/// +/// If there is some state in a downstream crate you would like to +/// access in the methods of `DiagnosticBuilder` here, consider +/// extending `DiagCtxtFlags`. +#[must_use] +pub struct DiagnosticBuilder<'a, G: EmissionGuarantee = ErrorGuaranteed> { + pub dcx: &'a DiagCtxt, + + /// Why the `Option`? It is always `Some` until the `DiagnosticBuilder` is + /// consumed via `emit`, `cancel`, etc. At that point it is consumed and + /// replaced with `None`. Then `drop` checks that it is `None`; if not, it + /// panics because a diagnostic was built but not used. + /// + /// Why the Box? `Diagnostic` is a large type, and `DiagnosticBuilder` is + /// often used as a return value, especially within the frequently-used + /// `PResult` type. In theory, return value optimization (RVO) should avoid + /// unnecessary copying. In practice, it does not (at the time of writing). + // FIXME(nnethercote) Make private once this moves to diagnostic.rs. + pub(crate) diag: Option>, + + // FIXME(nnethercote) Make private once this moves to diagnostic.rs. + pub(crate) _marker: PhantomData, +} + +// Cloning a `DiagnosticBuilder` is a recipe for a diagnostic being emitted +// twice, which would be bad. +impl !Clone for DiagnosticBuilder<'_, G> {} + +rustc_data_structures::static_assert_size!( + DiagnosticBuilder<'_, ()>, + 2 * std::mem::size_of::() +); + +impl Deref for DiagnosticBuilder<'_, G> { + type Target = Diagnostic; + + fn deref(&self) -> &Diagnostic { + self.diag.as_ref().unwrap() + } +} + +impl DerefMut for DiagnosticBuilder<'_, G> { + fn deref_mut(&mut self) -> &mut Diagnostic { + self.diag.as_mut().unwrap() + } +} + +impl Debug for DiagnosticBuilder<'_, G> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.diag.fmt(f) + } } /// `DiagnosticBuilder` impls many `&mut self -> &mut Self` methods. Each one @@ -382,6 +570,20 @@ macro_rules! with_fn { } impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { + #[rustc_lint_diagnostics] + #[track_caller] + pub fn new>(dcx: &'a DiagCtxt, level: Level, message: M) -> Self { + Self::new_diagnostic(dcx, Diagnostic::new(level, message)) + } + + /// Creates a new `DiagnosticBuilder` with an already constructed + /// diagnostic. + #[track_caller] + pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diag: Diagnostic) -> Self { + debug!("Created new diagnostic"); + Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData } + } + /// Delay emission of this diagnostic as a bug. /// /// This can be useful in contexts where an error indicates a bug but @@ -1040,48 +1242,115 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { let sub = SubDiagnostic { level, messages, span }; self.children.push(sub); } -} -impl Diagnostic { - /// Fields used for Hash, and PartialEq trait - fn keys( - &self, - ) -> ( - &Level, - &[(DiagnosticMessage, Style)], - &Option, - &MultiSpan, - &[SubDiagnostic], - &Result, SuggestionsDisabled>, - Vec<(&DiagnosticArgName, &DiagnosticArgValue)>, - &Option, - ) { - ( - &self.level, - &self.messages, - &self.code, - &self.span, - &self.children, - &self.suggestions, - self.args().collect(), - // omit self.sort_span - &self.is_lint, - // omit self.emitted_at - ) + /// Takes the diagnostic. For use by methods that consume the + /// DiagnosticBuilder: `emit`, `cancel`, etc. Afterwards, `drop` is the + /// only code that will be run on `self`. + // FIXME(nnethercote) Make private once this moves to diagnostic.rs. + pub(crate) fn take_diag(&mut self) -> Diagnostic { + Box::into_inner(self.diag.take().unwrap()) } -} -impl Hash for Diagnostic { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - self.keys().hash(state); + /// Most `emit_producing_guarantee` functions use this as a starting point. + // FIXME(nnethercote) Make private once this moves to diagnostic.rs. + pub(crate) fn emit_producing_nothing(mut self) { + let diag = self.take_diag(); + self.dcx.emit_diagnostic(diag); + } + + /// `ErrorGuaranteed::emit_producing_guarantee` uses this. + // FIXME(nnethercote) Make private once this moves to diagnostic.rs. + pub(crate) fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { + let diag = self.take_diag(); + + // The only error levels that produce `ErrorGuaranteed` are + // `Error` and `DelayedBug`. But `DelayedBug` should never occur here + // because delayed bugs have their level changed to `Bug` when they are + // actually printed, so they produce an ICE. + // + // (Also, even though `level` isn't `pub`, the whole `Diagnostic` could + // be overwritten with a new one thanks to `DerefMut`. So this assert + // protects against that, too.) + assert!( + matches!(diag.level, Level::Error | Level::DelayedBug), + "invalid diagnostic level ({:?})", + diag.level, + ); + + let guar = self.dcx.emit_diagnostic(diag); + guar.unwrap() + } + + /// Emit and consume the diagnostic. + #[track_caller] + pub fn emit(self) -> G::EmitResult { + G::emit_producing_guarantee(self) + } + + /// Emit the diagnostic unless `delay` is true, + /// in which case the emission will be delayed as a bug. + /// + /// See `emit` and `delay_as_bug` for details. + #[track_caller] + pub fn emit_unless(mut self, delay: bool) -> G::EmitResult { + if delay { + self.downgrade_to_delayed_bug(); + } + self.emit() + } + + /// Cancel and consume the diagnostic. (A diagnostic must either be emitted or + /// cancelled or it will panic when dropped). + pub fn cancel(mut self) { + self.diag = None; + drop(self); + } + + /// Stashes diagnostic for possible later improvement in a different, + /// later stage of the compiler. The diagnostic can be accessed with + /// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`]. + pub fn stash(mut self, span: Span, key: StashKey) { + self.dcx.stash_diagnostic(span, key, self.take_diag()); + } + + /// Delay emission of this diagnostic as a bug. + /// + /// This can be useful in contexts where an error indicates a bug but + /// typically this only happens when other compilation errors have already + /// happened. In those cases this can be used to defer emission of this + /// diagnostic as a bug in the compiler only if no other errors have been + /// emitted. + /// + /// In the meantime, though, callsites are required to deal with the "bug" + /// locally in whichever way makes the most sense. + #[track_caller] + pub fn delay_as_bug(mut self) -> G::EmitResult { + self.downgrade_to_delayed_bug(); + self.emit() } } -impl PartialEq for Diagnostic { - fn eq(&self, other: &Self) -> bool { - self.keys() == other.keys() +/// Destructor bomb: every `DiagnosticBuilder` must be consumed (emitted, +/// cancelled, etc.) or we emit a bug. +impl Drop for DiagnosticBuilder<'_, G> { + fn drop(&mut self) { + match self.diag.take() { + Some(diag) if !panicking() => { + self.dcx.emit_diagnostic(Diagnostic::new( + Level::Bug, + DiagnosticMessage::from("the following error was constructed but not emitted"), + )); + self.dcx.emit_diagnostic(*diag); + panic!("error was constructed but not emitted"); + } + _ => {} + } } } + +#[macro_export] +macro_rules! struct_span_code_err { + ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({ + $dcx.struct_span_err($span, format!($($message)*)).with_code($code) + }) +} diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs deleted file mode 100644 index 3a6a494af95..00000000000 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ /dev/null @@ -1,282 +0,0 @@ -use crate::{ - DiagCtxt, Diagnostic, DiagnosticMessage, ErrorGuaranteed, ExplicitBug, Level, StashKey, -}; -use rustc_span::source_map::Spanned; -use rustc_span::Span; -use std::fmt::{self, Debug}; -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; -use std::panic; -use std::thread::panicking; - -/// Trait implemented by error types. This is rarely implemented manually. Instead, use -/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. -#[rustc_diagnostic_item = "IntoDiagnostic"] -pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { - /// Write out as a diagnostic out of `DiagCtxt`. - #[must_use] - fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G>; -} - -impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned -where - T: IntoDiagnostic<'a, G>, - G: EmissionGuarantee, -{ - fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> { - self.node.into_diagnostic(dcx, level).with_span(self.span) - } -} - -/// Used for emitting structured error messages and other diagnostic information. -/// Wraps a `Diagnostic`, adding some useful things. -/// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check -/// that it has been emitted or cancelled. -/// - The `EmissionGuarantee`, which determines the type returned from `emit`. -/// -/// Each constructed `DiagnosticBuilder` must be consumed by a function such as -/// `emit`, `cancel`, `delay_as_bug`, or `into_diagnostic`. A panic occurrs if a -/// `DiagnosticBuilder` is dropped without being consumed by one of these -/// functions. -/// -/// If there is some state in a downstream crate you would like to -/// access in the methods of `DiagnosticBuilder` here, consider -/// extending `DiagCtxtFlags`. -#[must_use] -pub struct DiagnosticBuilder<'a, G: EmissionGuarantee = ErrorGuaranteed> { - pub dcx: &'a DiagCtxt, - - /// Why the `Option`? It is always `Some` until the `DiagnosticBuilder` is - /// consumed via `emit`, `cancel`, etc. At that point it is consumed and - /// replaced with `None`. Then `drop` checks that it is `None`; if not, it - /// panics because a diagnostic was built but not used. - /// - /// Why the Box? `Diagnostic` is a large type, and `DiagnosticBuilder` is - /// often used as a return value, especially within the frequently-used - /// `PResult` type. In theory, return value optimization (RVO) should avoid - /// unnecessary copying. In practice, it does not (at the time of writing). - // FIXME(nnethercote) Make private once this moves to diagnostic.rs. - pub(crate) diag: Option>, - - // FIXME(nnethercote) Make private once this moves to diagnostic.rs. - pub(crate) _marker: PhantomData, -} - -// Cloning a `DiagnosticBuilder` is a recipe for a diagnostic being emitted -// twice, which would be bad. -impl !Clone for DiagnosticBuilder<'_, G> {} - -rustc_data_structures::static_assert_size!( - DiagnosticBuilder<'_, ()>, - 2 * std::mem::size_of::() -); - -/// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee" -/// (or "proof") token that the emission happened. -pub trait EmissionGuarantee: Sized { - /// This exists so that bugs and fatal errors can both result in `!` (an - /// abort) when emitted, but have different aborting behaviour. - type EmitResult = Self; - - /// Implementation of `DiagnosticBuilder::emit`, fully controlled by each - /// `impl` of `EmissionGuarantee`, to make it impossible to create a value - /// of `Self::EmitResult` without actually performing the emission. - #[track_caller] - fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult; -} - -impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { - /// Takes the diagnostic. For use by methods that consume the - /// DiagnosticBuilder: `emit`, `cancel`, etc. Afterwards, `drop` is the - /// only code that will be run on `self`. - // FIXME(nnethercote) Make private once this moves to diagnostic.rs. - pub(crate) fn take_diag(&mut self) -> Diagnostic { - Box::into_inner(self.diag.take().unwrap()) - } - - /// Most `emit_producing_guarantee` functions use this as a starting point. - // FIXME(nnethercote) Make private once this moves to diagnostic.rs. - pub(crate) fn emit_producing_nothing(mut self) { - let diag = self.take_diag(); - self.dcx.emit_diagnostic(diag); - } - - /// `ErrorGuaranteed::emit_producing_guarantee` uses this. - // FIXME(nnethercote) Make private once this moves to diagnostic.rs. - pub(crate) fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { - let diag = self.take_diag(); - - // The only error levels that produce `ErrorGuaranteed` are - // `Error` and `DelayedBug`. But `DelayedBug` should never occur here - // because delayed bugs have their level changed to `Bug` when they are - // actually printed, so they produce an ICE. - // - // (Also, even though `level` isn't `pub`, the whole `Diagnostic` could - // be overwritten with a new one thanks to `DerefMut`. So this assert - // protects against that, too.) - assert!( - matches!(diag.level, Level::Error | Level::DelayedBug), - "invalid diagnostic level ({:?})", - diag.level, - ); - - let guar = self.dcx.emit_diagnostic(diag); - guar.unwrap() - } -} - -impl EmissionGuarantee for ErrorGuaranteed { - fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - db.emit_producing_error_guaranteed() - } -} - -impl EmissionGuarantee for () { - fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - db.emit_producing_nothing(); - } -} - -/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for -/// bug diagnostics. -#[derive(Copy, Clone)] -pub struct BugAbort; - -impl EmissionGuarantee for BugAbort { - type EmitResult = !; - - fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - db.emit_producing_nothing(); - panic::panic_any(ExplicitBug); - } -} - -/// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for -/// fatal diagnostics. -#[derive(Copy, Clone)] -pub struct FatalAbort; - -impl EmissionGuarantee for FatalAbort { - type EmitResult = !; - - fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - db.emit_producing_nothing(); - crate::FatalError.raise() - } -} - -impl EmissionGuarantee for rustc_span::fatal_error::FatalError { - fn emit_producing_guarantee(db: DiagnosticBuilder<'_, Self>) -> Self::EmitResult { - db.emit_producing_nothing(); - rustc_span::fatal_error::FatalError - } -} - -impl Deref for DiagnosticBuilder<'_, G> { - type Target = Diagnostic; - - fn deref(&self) -> &Diagnostic { - self.diag.as_ref().unwrap() - } -} - -impl DerefMut for DiagnosticBuilder<'_, G> { - fn deref_mut(&mut self) -> &mut Diagnostic { - self.diag.as_mut().unwrap() - } -} - -impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { - #[rustc_lint_diagnostics] - #[track_caller] - pub fn new>(dcx: &'a DiagCtxt, level: Level, message: M) -> Self { - Self::new_diagnostic(dcx, Diagnostic::new(level, message)) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - #[track_caller] - pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diag: Diagnostic) -> Self { - debug!("Created new diagnostic"); - Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData } - } - - /// Emit and consume the diagnostic. - #[track_caller] - pub fn emit(self) -> G::EmitResult { - G::emit_producing_guarantee(self) - } - - /// Emit the diagnostic unless `delay` is true, - /// in which case the emission will be delayed as a bug. - /// - /// See `emit` and `delay_as_bug` for details. - #[track_caller] - pub fn emit_unless(mut self, delay: bool) -> G::EmitResult { - if delay { - self.downgrade_to_delayed_bug(); - } - self.emit() - } - - /// Cancel and consume the diagnostic. (A diagnostic must either be emitted or - /// cancelled or it will panic when dropped). - pub fn cancel(mut self) { - self.diag = None; - drop(self); - } - - /// Stashes diagnostic for possible later improvement in a different, - /// later stage of the compiler. The diagnostic can be accessed with - /// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`]. - pub fn stash(mut self, span: Span, key: StashKey) { - self.dcx.stash_diagnostic(span, key, self.take_diag()); - } - - /// Delay emission of this diagnostic as a bug. - /// - /// This can be useful in contexts where an error indicates a bug but - /// typically this only happens when other compilation errors have already - /// happened. In those cases this can be used to defer emission of this - /// diagnostic as a bug in the compiler only if no other errors have been - /// emitted. - /// - /// In the meantime, though, callsites are required to deal with the "bug" - /// locally in whichever way makes the most sense. - #[track_caller] - pub fn delay_as_bug(mut self) -> G::EmitResult { - self.downgrade_to_delayed_bug(); - self.emit() - } -} - -impl Debug for DiagnosticBuilder<'_, G> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.diag.fmt(f) - } -} - -/// Destructor bomb: every `DiagnosticBuilder` must be consumed (emitted, -/// cancelled, etc.) or we emit a bug. -impl Drop for DiagnosticBuilder<'_, G> { - fn drop(&mut self) { - match self.diag.take() { - Some(diag) if !panicking() => { - self.dcx.emit_diagnostic(Diagnostic::new( - Level::Bug, - DiagnosticMessage::from("the following error was constructed but not emitted"), - )); - self.dcx.emit_diagnostic(*diag); - panic!("error was constructed but not emitted"); - } - _ => {} - } - } -} - -#[macro_export] -macro_rules! struct_span_code_err { - ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) => ({ - $dcx.struct_span_err($span, format!($($message)*)).with_code($code) - }) -} diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 73cda64f1cc..052d9b3a783 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -37,12 +37,9 @@ extern crate self as rustc_errors; pub use codes::*; pub use diagnostic::{ - AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgName, - DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, StringPart, SubDiagnostic, - SubdiagnosticMessageOp, -}; -pub use diagnostic_builder::{ - BugAbort, DiagnosticBuilder, EmissionGuarantee, FatalAbort, IntoDiagnostic, + AddToDiagnostic, BugAbort, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgName, + DiagnosticArgValue, DiagnosticBuilder, DiagnosticStyledString, EmissionGuarantee, FatalAbort, + IntoDiagnostic, IntoDiagnosticArg, StringPart, SubDiagnostic, SubdiagnosticMessageOp, }; pub use diagnostic_impls::{ DiagnosticArgFromDisplay, DiagnosticSymbolList, ExpectedLifetimeParameter, @@ -87,7 +84,6 @@ use Level::*; pub mod annotate_snippet_emitter_writer; pub mod codes; mod diagnostic; -mod diagnostic_builder; mod diagnostic_impls; pub mod emitter; pub mod error; diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index 0d61e15b0f1..7844e60c654 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -8,7 +8,7 @@ LL | arg: NotIntoDiagnosticArg, | ^^^^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg` | = help: normalized in stderr -note: required by a bound in `rustc_errors::diagnostic::>::arg` +note: required by a bound in `DiagnosticBuilder::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -22,7 +22,7 @@ LL | arg: NotIntoDiagnosticArg, | ^^^^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `NotIntoDiagnosticArg` | = help: normalized in stderr -note: required by a bound in `rustc_errors::diagnostic::>::arg` +note: required by a bound in `DiagnosticBuilder::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index ddbb3c6df26..8732629db47 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -628,7 +628,7 @@ LL | other: Hello, | ^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello` | = help: normalized in stderr -note: required by a bound in `rustc_errors::diagnostic::>::arg` +note: required by a bound in `DiagnosticBuilder::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) -- cgit 1.4.1-3-g733a5 From 1407057b167e35c9ff68b66d454f70c98c6f7ac9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 21 Feb 2024 09:57:58 +1100 Subject: Remove some no-longer-needed `pub(crate)` markers. --- compiler/rustc_errors/src/diagnostic.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 686a3dc66a1..f096f015910 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -490,11 +490,9 @@ pub struct DiagnosticBuilder<'a, G: EmissionGuarantee = ErrorGuaranteed> { /// often used as a return value, especially within the frequently-used /// `PResult` type. In theory, return value optimization (RVO) should avoid /// unnecessary copying. In practice, it does not (at the time of writing). - // FIXME(nnethercote) Make private once this moves to diagnostic.rs. - pub(crate) diag: Option>, + diag: Option>, - // FIXME(nnethercote) Make private once this moves to diagnostic.rs. - pub(crate) _marker: PhantomData, + _marker: PhantomData, } // Cloning a `DiagnosticBuilder` is a recipe for a diagnostic being emitted @@ -1246,21 +1244,18 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Takes the diagnostic. For use by methods that consume the /// DiagnosticBuilder: `emit`, `cancel`, etc. Afterwards, `drop` is the /// only code that will be run on `self`. - // FIXME(nnethercote) Make private once this moves to diagnostic.rs. - pub(crate) fn take_diag(&mut self) -> Diagnostic { + fn take_diag(&mut self) -> Diagnostic { Box::into_inner(self.diag.take().unwrap()) } /// Most `emit_producing_guarantee` functions use this as a starting point. - // FIXME(nnethercote) Make private once this moves to diagnostic.rs. - pub(crate) fn emit_producing_nothing(mut self) { + fn emit_producing_nothing(mut self) { let diag = self.take_diag(); self.dcx.emit_diagnostic(diag); } /// `ErrorGuaranteed::emit_producing_guarantee` uses this. - // FIXME(nnethercote) Make private once this moves to diagnostic.rs. - pub(crate) fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { + fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { let diag = self.take_diag(); // The only error levels that produce `ErrorGuaranteed` are -- cgit 1.4.1-3-g733a5 From 62e7414a194fb64715933d720e0505553c0834f7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 19 Feb 2024 16:07:39 +0000 Subject: Docs for extension proc-macro --- compiler/rustc_macros/src/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'compiler') diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 619f93c8a53..14e6a06839e 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -41,6 +41,20 @@ pub fn symbols(input: TokenStream) -> TokenStream { symbols::symbols(input.into()).into() } +/// Derive an extension trait for a given impl block. The trait name +/// goes into the parenthesized args of the macro, for greppability. +/// For example: +/// ``` +/// use rustc_macros::extension; +/// #[extension(pub trait Foo)] +/// impl i32 { fn hello() {} } +/// ``` +/// +/// expands to: +/// ``` +/// pub trait Foo { fn hello(); } +/// impl Foo for i32 { fn hello() {} } +/// ``` #[proc_macro_attribute] pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream { extension::extension(attr, input) -- cgit 1.4.1-3-g733a5 From 09ca866738711331609811da2d8399531bda66c5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 21 Feb 2024 14:23:46 +1100 Subject: Remove an `unchecked_error_guaranteed` call. If we abort immediately after complaining about the obsolete `impl Trait for ..` syntax, then we avoid reaching HIR lowering. This means we can use `TyKind::Dummy` instead of `TyKind::Err`. --- compiler/rustc_ast_passes/src/ast_validation.rs | 7 ++++--- compiler/rustc_parse/src/parser/item.rs | 20 ++++---------------- 2 files changed, 8 insertions(+), 19 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index fa0f5326196..8c9ad836087 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -881,9 +881,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { &item.vis, errors::VisibilityNotPermittedNote::TraitImpl, ); - // njn: use Dummy here - if let TyKind::Err(_) = self_ty.kind { - this.dcx().emit_err(errors::ObsoleteAuto { span: item.span }); + if let TyKind::Dummy = self_ty.kind { + // Abort immediately otherwise the `TyKind::Dummy` will reach HIR lowering, + // which isn't allowed. Not a problem for this obscure, obsolete syntax. + this.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span }); } if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index e7b9076bd3c..755a70667ed 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -592,22 +592,10 @@ impl<'a> Parser<'a> { // We need to report this error after `cfg` expansion for compatibility reasons self.bump(); // `..`, do not add it to expected tokens - // FIXME(nnethercote): AST validation later detects this - // `TyKind::Err` and emits an errors. So why the unchecked - // ErrorGuaranteed? - // - A `span_delayed_bug` doesn't work here, because rustfmt can - // hit this path but then not hit the follow-up path in the AST - // validator that issues the error, which results in ICEs. - // - `TyKind::Dummy` doesn't work, because it ends up reaching HIR - // lowering, which results in ICEs. Changing `TyKind::Dummy` to - // `TyKind::Err` during AST validation might fix that, but that's - // not possible because AST validation doesn't allow mutability. - // - // #121072 will hopefully remove all this special handling of the - // obsolete `impl Trait for ..` and then this can go away. - #[allow(deprecated)] - let guar = rustc_errors::ErrorGuaranteed::unchecked_error_guaranteed(); - Some(self.mk_ty(self.prev_token.span, TyKind::Err(guar))) + // AST validation later detects this `TyKind::Dummy` and emits an + // error. (#121072 will hopefully remove all this special handling + // of the obsolete `impl Trait for ..` and then this can go away.) + Some(self.mk_ty(self.prev_token.span, TyKind::Dummy)) } else if has_for || self.token.can_begin_type() { Some(self.parse_ty()?) } else { -- cgit 1.4.1-3-g733a5 From 780beda83c8b822a91b801050ee543f5f7a271df Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 18 Feb 2024 12:52:40 +0100 Subject: Tweak block management --- compiler/rustc_mir_build/src/build/matches/mod.rs | 24 +++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index ccf299649cf..808b4a130e5 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1408,7 +1408,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: Span, scrutinee_span: Span, candidates: &mut [&mut Candidate<'_, 'tcx>], - block: BasicBlock, + start_block: BasicBlock, otherwise_block: BasicBlock, fake_borrows: &mut Option>>, ) { @@ -1423,7 +1423,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span, scrutinee_span, candidates, - block, + start_block, otherwise_block, fake_borrows, ); @@ -1432,7 +1432,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let match_pairs = mem::take(&mut first_candidate.match_pairs); - first_candidate.pre_binding_block = Some(block); let remainder_start = self.cfg.start_new_block(); for match_pair in match_pairs { @@ -1442,9 +1441,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let or_span = match_pair.pattern.span; first_candidate.visit_leaves(|leaf_candidate| { + let or_start = leaf_candidate.pre_binding_block.unwrap_or(start_block); + let or_otherwise = leaf_candidate.otherwise_block.unwrap_or(remainder_start); self.test_or_pattern( leaf_candidate, - remainder_start, + or_start, + or_otherwise, pats, or_span, &match_pair.place, @@ -1464,13 +1466,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } #[instrument( - skip(self, otherwise, or_span, place, fake_borrows, candidate, pats), + skip(self, start_block, otherwise_block, or_span, place, fake_borrows, candidate, pats), level = "debug" )] fn test_or_pattern<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, - otherwise: BasicBlock, + start_block: BasicBlock, + otherwise_block: BasicBlock, pats: &'pat [Box>], or_span: Span, place: &PlaceBuilder<'tcx>, @@ -1482,16 +1485,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard, self)) .collect(); let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect(); - let otherwise = if let Some(otherwise_block) = candidate.otherwise_block { - otherwise_block - } else { - otherwise - }; self.match_candidates( or_span, or_span, - candidate.pre_binding_block.unwrap(), - otherwise, + start_block, + otherwise_block, &mut or_candidate_refs, fake_borrows, ); -- cgit 1.4.1-3-g733a5 From ec91209f964182655cc1330c0a6f79c3e8bca7df Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 18 Feb 2024 20:38:07 +1100 Subject: coverage: Eagerly deduplicate covspans with the same span --- .../rustc_mir_transform/src/coverage/spans/from_mir.rs | 15 ++++++++++----- tests/coverage/closure_macro.cov-map | 9 ++++----- tests/coverage/closure_macro_async.cov-map | 9 ++++----- 3 files changed, 18 insertions(+), 15 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 2db358379fe..b91ab811918 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -52,14 +52,19 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( // - Span A extends further left, or // - Both have the same start and span A extends further right .then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse()) - // If both spans are equal, sort the BCBs in dominator order, - // so that dominating BCBs come before other BCBs they dominate. - .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)) - // If two spans are otherwise identical, put closure spans first, - // as this seems to be what the refinement step expects. + // If two spans have the same lo & hi, put closure spans first, + // as they take precedence over non-closure spans. .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse()) + // After deduplication, we want to keep only the most-dominated BCB. + .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse()) }); + // Among covspans with the same span, keep only one. Closure spans take + // precedence, otherwise keep the one with the most-dominated BCB. + // (Ideally we should try to preserve _all_ non-dominating BCBs, but that + // requires a lot more complexity in the span refiner, for little benefit.) + initial_spans.dedup_by(|b, a| a.span.source_equal(b.span)); + initial_spans } diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index 571e5564b65..e43ed1f76f3 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -7,18 +7,17 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2) Function name: closure_macro::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 05, 02, 07, 01, 21, 01, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 12, 00, 13, 02, 00, 12, 00, 13, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 02, 01, 05, 05, 02, 06, 01, 21, 01, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) -Number of file 0 mappings: 7 +Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 33, 1) to (start + 1, 33) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 18) = (c0 - c1) -- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) -- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 0, 15) to (start + 0, 84) = (c0 - c1) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 49ec767eab3..212b67a8a3e 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -15,18 +15,17 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 35, 1) to (start + 0, 43) Function name: closure_macro_async::test::{closure#0} -Raw bytes (43): 0x[01, 01, 02, 01, 05, 05, 02, 07, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 12, 00, 13, 02, 00, 12, 00, 13, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 02, 01, 05, 05, 02, 06, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) -Number of file 0 mappings: 7 +Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 35, 43) to (start + 1, 33) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 18) = (c0 - c1) -- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) -- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 0, 15) to (start + 0, 84) = (c0 - c1) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) -- cgit 1.4.1-3-g733a5 From c40261da11a58247822c9297993eb2142d8d53a2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 18 Feb 2024 20:49:47 +1100 Subject: coverage: Remove `pending_dups` from the span refiner --- compiler/rustc_mir_transform/src/coverage/spans.rs | 180 ++------------------- 1 file changed, 16 insertions(+), 164 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 934e77e7deb..c2e348cb713 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -61,7 +61,7 @@ pub(super) fn generate_coverage_spans( hir_info, basic_coverage_blocks, ); - let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans); + let coverage_spans = SpansRefiner::refine_sorted_spans(sorted_spans); mappings.extend(coverage_spans.into_iter().map(|RefinedCovspan { bcb, span, .. }| { // Each span produced by the generator represents an ordinary code region. BcbMapping { kind: BcbMappingKind::Code(bcb), span } @@ -88,8 +88,6 @@ pub(super) fn generate_coverage_spans( #[derive(Debug)] struct CurrCovspan { - /// This is used as the basis for [`PrevCovspan::original_span`], so it must - /// not be modified. span: Span, bcb: BasicCoverageBlock, is_closure: bool, @@ -102,7 +100,7 @@ impl CurrCovspan { fn into_prev(self) -> PrevCovspan { let Self { span, bcb, is_closure } = self; - PrevCovspan { original_span: span, span, bcb, merged_spans: vec![span], is_closure } + PrevCovspan { span, bcb, merged_spans: vec![span], is_closure } } fn into_refined(self) -> RefinedCovspan { @@ -115,7 +113,6 @@ impl CurrCovspan { #[derive(Debug)] struct PrevCovspan { - original_span: Span, span: Span, bcb: BasicCoverageBlock, /// List of all the original spans from MIR that have been merged into this @@ -142,35 +139,8 @@ impl PrevCovspan { } } - fn into_dup(self) -> DuplicateCovspan { - let Self { original_span, span, bcb, merged_spans: _, is_closure } = self; - // Only unmodified spans end up in `pending_dups`. - debug_assert_eq!(original_span, span); - DuplicateCovspan { span, bcb, is_closure } - } - - fn refined_copy(&self) -> RefinedCovspan { - let &Self { original_span: _, span, bcb, merged_spans: _, is_closure } = self; - RefinedCovspan { span, bcb, is_closure } - } - - fn into_refined(self) -> RefinedCovspan { - self.refined_copy() - } -} - -#[derive(Debug)] -struct DuplicateCovspan { - span: Span, - bcb: BasicCoverageBlock, - is_closure: bool, -} - -impl DuplicateCovspan { - /// Returns a copy of this covspan, as a [`RefinedCovspan`]. - /// Should only be called in places that would otherwise clone this covspan. fn refined_copy(&self) -> RefinedCovspan { - let &Self { span, bcb, is_closure } = self; + let &Self { span, bcb, merged_spans: _, is_closure } = self; RefinedCovspan { span, bcb, is_closure } } @@ -205,10 +175,7 @@ impl RefinedCovspan { /// * Merge spans that represent continuous (both in source code and control flow), non-branching /// execution /// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures) -struct SpansRefiner<'a> { - /// The BasicCoverageBlock Control Flow Graph (BCB CFG). - basic_coverage_blocks: &'a CoverageGraph, - +struct SpansRefiner { /// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative /// dominance between the `BasicCoverageBlock`s of equal `Span`s. sorted_spans_iter: std::vec::IntoIter, @@ -223,36 +190,22 @@ struct SpansRefiner<'a> { /// If that `curr` was discarded, `prev` retains its value from the previous iteration. some_prev: Option, - /// One or more coverage spans with the same `Span` but different `BasicCoverageBlock`s, and - /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list. - /// If a new `curr` span also fits this criteria (compared to an existing list of - /// `pending_dups`), that `curr` moves to `prev` before possibly being added to - /// the `pending_dups` list, on the next iteration. As a result, if `prev` and `pending_dups` - /// have the same `Span`, the criteria for `pending_dups` holds for `prev` as well: a `prev` - /// with a matching `Span` does not dominate any `pending_dup` and no `pending_dup` dominates a - /// `prev` with a matching `Span`) - pending_dups: Vec, - /// The final coverage spans to add to the coverage map. A `Counter` or `Expression` /// will also be injected into the MIR for each BCB that has associated spans. refined_spans: Vec, } -impl<'a> SpansRefiner<'a> { +impl SpansRefiner { /// Takes the initial list of (sorted) spans extracted from MIR, and "refines" /// them by merging compatible adjacent spans, removing redundant spans, /// and carving holes in spans when they overlap in unwanted ways. - fn refine_sorted_spans( - basic_coverage_blocks: &'a CoverageGraph, - sorted_spans: Vec, - ) -> Vec { + fn refine_sorted_spans(sorted_spans: Vec) -> Vec { + let sorted_spans_len = sorted_spans.len(); let this = Self { - basic_coverage_blocks, sorted_spans_iter: sorted_spans.into_iter(), some_curr: None, some_prev: None, - pending_dups: Vec::new(), - refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2), + refined_spans: Vec::with_capacity(sorted_spans_len), }; this.to_refined_spans() @@ -292,21 +245,11 @@ impl<'a> SpansRefiner<'a> { self.take_curr(); // Discards curr. } else if curr.is_closure { self.carve_out_span_for_closure(); - } else if prev.original_span == prev.span && prev.span == curr.span { - // Prev and curr have the same span, and prev's span hasn't - // been modified by other spans. - self.update_pending_dups(); } else { self.cutoff_prev_at_overlapping_curr(); } } - // Drain any remaining dups into the output. - for dup in self.pending_dups.drain(..) { - debug!(" ...adding at least one pending dup={:?}", dup); - self.refined_spans.push(dup.into_refined()); - } - // There is usually a final span remaining in `prev` after the loop ends, // so add it to the output as well. if let Some(prev) = self.some_prev.take() { @@ -359,36 +302,6 @@ impl<'a> SpansRefiner<'a> { self.some_prev.take().unwrap_or_else(|| bug!("some_prev is None (take_prev)")) } - /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the - /// `pending_dups` spans), then one of the following two things happened during the previous - /// iteration: - /// * the previous `curr` span (which is now `prev`) was not a duplicate of the pending_dups - /// (in which case there should be at least two spans in `pending_dups`); or - /// * the `span` of `prev` was modified by `curr_mut().merge_from(prev)` (in which case - /// `pending_dups` could have as few as one span) - /// In either case, no more spans will match the span of `pending_dups`, so - /// add the `pending_dups` if they don't overlap `curr`, and clear the list. - fn maybe_flush_pending_dups(&mut self) { - let Some(last_dup) = self.pending_dups.last() else { return }; - if last_dup.span == self.prev().span { - return; - } - - debug!( - " SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \ - previous iteration, or prev started a new disjoint span" - ); - if last_dup.span.hi() <= self.curr().span.lo() { - for dup in self.pending_dups.drain(..) { - debug!(" ...adding at least one pending={:?}", dup); - self.refined_spans.push(dup.into_refined()); - } - } else { - self.pending_dups.clear(); - } - assert!(self.pending_dups.is_empty()); - } - /// Advance `prev` to `curr` (if any), and `curr` to the next coverage span in sorted order. fn next_coverage_span(&mut self) -> bool { if let Some(curr) = self.some_curr.take() { @@ -408,7 +321,6 @@ impl<'a> SpansRefiner<'a> { ); } else { self.some_curr = Some(CurrCovspan::new(curr.span, curr.bcb, curr.is_closure)); - self.maybe_flush_pending_dups(); return true; } } @@ -433,13 +345,6 @@ impl<'a> SpansRefiner<'a> { let mut pre_closure = self.prev().refined_copy(); pre_closure.span = pre_closure.span.with_hi(left_cutoff); debug!(" prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure); - - for mut dup in self.pending_dups.iter().map(DuplicateCovspan::refined_copy) { - dup.span = dup.span.with_hi(left_cutoff); - debug!(" ...and at least one pre_closure dup={:?}", dup); - self.refined_spans.push(dup); - } - self.refined_spans.push(pre_closure); } @@ -448,58 +353,9 @@ impl<'a> SpansRefiner<'a> { self.prev_mut().span = self.prev().span.with_lo(right_cutoff); debug!(" Mutated prev.span to start after the closure. prev={:?}", self.prev()); - for dup in &mut self.pending_dups { - debug!(" ...and at least one overlapping dup={:?}", dup); - dup.span = dup.span.with_lo(right_cutoff); - } - // Prevent this curr from becoming prev. let closure_covspan = self.take_curr().into_refined(); self.refined_spans.push(closure_covspan); // since self.prev() was already updated - } else { - self.pending_dups.clear(); - } - } - - /// Called if `curr.span` equals `prev.original_span` (and potentially equal to all - /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed. - /// If prev.span() was merged into other spans (with matching BCB, for instance), - /// `prev.span.hi()` will be greater than (further right of) `prev.original_span.hi()`. - /// If prev.span() was split off to the right of a closure, prev.span().lo() will be - /// greater than prev.original_span.lo(). The actual span of `prev.original_span` is - /// not as important as knowing that `prev()` **used to have the same span** as `curr()`, - /// which means their sort order is still meaningful for determining the dominator - /// relationship. - /// - /// When two coverage spans have the same `Span`, dominated spans can be discarded; but if - /// neither coverage span dominates the other, both (or possibly more than two) are held, - /// until their disposition is determined. In this latter case, the `prev` dup is moved into - /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration. - fn update_pending_dups(&mut self) { - let prev_bcb = self.prev().bcb; - let curr_bcb = self.curr().bcb; - - // Equal coverage spans are ordered by dominators before dominated (if any), so it should be - // impossible for `curr` to dominate any previous coverage span. - debug_assert!(!self.basic_coverage_blocks.dominates(curr_bcb, prev_bcb)); - - // `prev` is a duplicate of `curr`, so add it to the list of pending dups. - // If it dominates `curr`, it will be removed by the subsequent discard step. - let prev = self.take_prev().into_dup(); - debug!(?prev, "adding prev to pending dups"); - self.pending_dups.push(prev); - - let initial_pending_count = self.pending_dups.len(); - if initial_pending_count > 0 { - self.pending_dups - .retain(|dup| !self.basic_coverage_blocks.dominates(dup.bcb, curr_bcb)); - - let n_discarded = initial_pending_count - self.pending_dups.len(); - if n_discarded > 0 { - debug!( - " discarded {n_discarded} of {initial_pending_count} pending_dups that dominated curr", - ); - } } } @@ -516,19 +372,15 @@ impl<'a> SpansRefiner<'a> { if it has statements that end before curr; prev={:?}", self.prev() ); - if self.pending_dups.is_empty() { - let curr_span = self.curr().span; - self.prev_mut().cutoff_statements_at(curr_span.lo()); - if self.prev().merged_spans.is_empty() { - debug!(" ... no non-overlapping statements to add"); - } else { - debug!(" ... adding modified prev={:?}", self.prev()); - let prev = self.take_prev().into_refined(); - self.refined_spans.push(prev); - } + + let curr_span = self.curr().span; + self.prev_mut().cutoff_statements_at(curr_span.lo()); + if self.prev().merged_spans.is_empty() { + debug!(" ... no non-overlapping statements to add"); } else { - // with `pending_dups`, `prev` cannot have any statements that don't overlap - self.pending_dups.clear(); + debug!(" ... adding modified prev={:?}", self.prev()); + let prev = self.take_prev().into_refined(); + self.refined_spans.push(prev); } } } -- cgit 1.4.1-3-g733a5 From 3a83b279bef65f8b727d33d1c7a80e5d2432f5aa Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 18 Feb 2024 20:54:10 +1100 Subject: coverage: Simplify (non-closure) covspans truncating each other --- compiler/rustc_mir_transform/src/coverage/spans.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index c2e348cb713..98fb1d8e1c9 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -132,11 +132,13 @@ impl PrevCovspan { self.merged_spans.push(other.span); } - fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) { + fn cutoff_statements_at(mut self, cutoff_pos: BytePos) -> Option { self.merged_spans.retain(|span| span.hi() <= cutoff_pos); if let Some(max_hi) = self.merged_spans.iter().map(|span| span.hi()).max() { self.span = self.span.with_hi(max_hi); } + + if self.merged_spans.is_empty() { None } else { Some(self.into_refined()) } } fn refined_copy(&self) -> RefinedCovspan { @@ -374,13 +376,11 @@ impl SpansRefiner { ); let curr_span = self.curr().span; - self.prev_mut().cutoff_statements_at(curr_span.lo()); - if self.prev().merged_spans.is_empty() { - debug!(" ... no non-overlapping statements to add"); - } else { - debug!(" ... adding modified prev={:?}", self.prev()); - let prev = self.take_prev().into_refined(); + if let Some(prev) = self.take_prev().cutoff_statements_at(curr_span.lo()) { + debug!("after cutoff, adding {prev:?}"); self.refined_spans.push(prev); + } else { + debug!("prev was eliminated by cutoff"); } } } -- cgit 1.4.1-3-g733a5 From c1514a6324cf80c52f7eb39b7a74df89b3769106 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 18 Feb 2024 22:58:14 +0100 Subject: Test one or pattern at a time --- compiler/rustc_mir_build/src/build/matches/mod.rs | 71 ++++++++++++++--------- 1 file changed, 42 insertions(+), 29 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 808b4a130e5..88a5eae281b 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1052,7 +1052,7 @@ struct Ascription<'tcx> { variance: ty::Variance, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct MatchPair<'pat, 'tcx> { // This place... place: PlaceBuilder<'tcx>, @@ -1413,48 +1413,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrows: &mut Option>>, ) { let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap(); - - // All of the or-patterns have been sorted to the end, so if the first - // pattern is an or-pattern we only have or-patterns. - match first_candidate.match_pairs[0].pattern.kind { - PatKind::Or { .. } => (), - _ => { - self.test_candidates( - span, - scrutinee_span, - candidates, - start_block, - otherwise_block, - fake_borrows, - ); - return; - } + assert!(first_candidate.subcandidates.is_empty()); + if !matches!(first_candidate.match_pairs[0].pattern.kind, PatKind::Or { .. }) { + self.test_candidates( + span, + scrutinee_span, + candidates, + start_block, + otherwise_block, + fake_borrows, + ); + return; } let match_pairs = mem::take(&mut first_candidate.match_pairs); + let (first_match_pair, remaining_match_pairs) = match_pairs.split_first().unwrap(); + let PatKind::Or { ref pats } = &first_match_pair.pattern.kind else { unreachable!() }; let remainder_start = self.cfg.start_new_block(); - for match_pair in match_pairs { - let PatKind::Or { ref pats } = &match_pair.pattern.kind else { - bug!("Or-patterns should have been sorted to the end"); - }; - let or_span = match_pair.pattern.span; + let or_span = first_match_pair.pattern.span; + // Test the alternatives of this or-pattern. + self.test_or_pattern( + first_candidate, + start_block, + remainder_start, + pats, + or_span, + &first_match_pair.place, + fake_borrows, + ); + if !remaining_match_pairs.is_empty() { + // If more match pairs remain, test them after each subcandidate. + // We could add them to the or-candidates before the call to `test_or_pattern` but this + // would make it impossible to detect simplifiable or-patterns. That would guarantee + // exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`. first_candidate.visit_leaves(|leaf_candidate| { - let or_start = leaf_candidate.pre_binding_block.unwrap_or(start_block); + assert!(leaf_candidate.match_pairs.is_empty()); + leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned()); + let or_start = leaf_candidate.pre_binding_block.unwrap(); + // In a case like `(a | b, c | d)`, if `a` succeeds and `c | d` fails, we know `(b, + // c | d)` will fail too. If there is no guard, we skip testing of `b` by branching + // directly to `remainder_start`. If there is a guard, we have to try `(b, c | d)`. let or_otherwise = leaf_candidate.otherwise_block.unwrap_or(remainder_start); - self.test_or_pattern( - leaf_candidate, + self.test_candidates_with_or( + span, + scrutinee_span, + &mut [leaf_candidate], or_start, or_otherwise, - pats, - or_span, - &match_pair.place, fake_borrows, ); }); } + // Test the remaining candidates. self.match_candidates( span, scrutinee_span, @@ -1462,7 +1475,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block, remaining_candidates, fake_borrows, - ) + ); } #[instrument( -- cgit 1.4.1-3-g733a5 From 5e0e5b1efb8a5776231b07c71e7c03ef016654b5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Feb 2024 02:55:40 +0100 Subject: Fix liveness analysis in the presence of never patterns --- compiler/rustc_hir/src/pat_util.rs | 11 +++++++++-- compiler/rustc_passes/src/liveness.rs | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index e6050327186..1eaab3d2aca 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -71,14 +71,21 @@ impl hir::Pat<'_> { /// Call `f` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }`. /// - /// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited. + /// When encountering an or-pattern `p_0 | ... | p_n` only the first non-never pattern will be + /// visited. If they're all never patterns we visit nothing, which is ok since a never pattern + /// cannot have bindings. pub fn each_binding_or_first( &self, f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, Ident), ) { self.walk(|p| match &p.kind { PatKind::Or(ps) => { - ps[0].each_binding_or_first(f); + for p in *ps { + if !p.is_never_pattern() { + p.each_binding_or_first(f); + break; + } + } false } PatKind::Binding(bm, _, ident, _) => { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 3a8dc377520..487407014d1 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -526,8 +526,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn define_bindings_in_pat(&mut self, pat: &hir::Pat<'_>, mut succ: LiveNode) -> LiveNode { - // In an or-pattern, only consider the first pattern; any later patterns - // must have the same bindings, and we also consider the first pattern + // In an or-pattern, only consider the first non-never pattern; any later patterns + // must have the same bindings, and we also consider that pattern // to be the "authoritative" set of ids. pat.each_binding_or_first(&mut |_, hir_id, pat_sp, ident| { let ln = self.live_node(hir_id, pat_sp); -- cgit 1.4.1-3-g733a5 From f25c90a83f661d39d9d55e61eaaf4b1beaabaf20 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:17:07 +0000 Subject: Unify dylib loading between proc macros and codegen backends As bonus this makes the errors when failing to load a proc macro more informative to match the backend loading errors. In addition it makes it slightly easier to patch rustc to work on platforms that don't support dynamic linking like wasm. --- Cargo.lock | 1 - compiler/rustc_interface/Cargo.toml | 1 - compiler/rustc_interface/src/lib.rs | 1 - compiler/rustc_interface/src/util.rs | 33 +++++++------------- compiler/rustc_metadata/messages.ftl | 2 +- compiler/rustc_metadata/src/creader.rs | 56 +++++++++++++++++++++++++--------- compiler/rustc_metadata/src/errors.rs | 1 + compiler/rustc_metadata/src/lib.rs | 2 ++ compiler/rustc_metadata/src/locator.rs | 8 ++--- 9 files changed, 60 insertions(+), 45 deletions(-) (limited to 'compiler') diff --git a/Cargo.lock b/Cargo.lock index 61f9c130e38..4dbe4b1b822 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4047,7 +4047,6 @@ dependencies = [ name = "rustc_interface" version = "0.0.0" dependencies = [ - "libloading", "rustc-rayon", "rustc-rayon-core", "rustc_ast", diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index a238eacda44..0e90836145e 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -libloading = "0.8.0" rustc-rayon = { version = "0.5.0", optional = true } rustc-rayon-core = { version = "0.5.0", optional = true } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 24c2e290534..d0ce23dacb5 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,5 +1,4 @@ #![feature(decl_macro)] -#![feature(error_iter)] #![feature(generic_nonzero)] #![feature(lazy_cell)] #![feature(let_chains)] diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 087c43075f1..823614e1f06 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,10 +1,10 @@ use crate::errors; use info; -use libloading::Library; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; #[cfg(parallel_compiler)] use rustc_data_structures::sync; +use rustc_metadata::{load_symbol_from_dylib, DylibError}; use rustc_parse::validate_attr; use rustc_session as session; use rustc_session::config::{self, Cfg, CrateType, OutFileName, OutputFilenames, OutputTypes}; @@ -17,7 +17,6 @@ use rustc_span::symbol::{sym, Symbol}; use session::EarlyDiagCtxt; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; -use std::mem; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; @@ -162,29 +161,19 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( } fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn { - fn format_err(e: &(dyn std::error::Error + 'static)) -> String { - e.sources().map(|e| format!(": {e}")).collect() - } - let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| { - let err = format!("couldn't load codegen backend {path:?}{}", format_err(&err)); - early_dcx.early_fatal(err); - }); - - let backend_sym = unsafe { lib.get::(b"__rustc_codegen_backend") } - .unwrap_or_else(|e| { + match unsafe { load_symbol_from_dylib::(path, "__rustc_codegen_backend") } { + Ok(backend_sym) => backend_sym, + Err(DylibError::DlOpen(path, err)) => { + let err = format!("couldn't load codegen backend {path}{err}"); + early_dcx.early_fatal(err); + } + Err(DylibError::DlSym(_path, err)) => { let e = format!( - "`__rustc_codegen_backend` symbol lookup in the codegen backend failed{}", - format_err(&e) + "`__rustc_codegen_backend` symbol lookup in the codegen backend failed{err}", ); early_dcx.early_fatal(e); - }); - - // Intentionally leak the dynamic library. We can't ever unload it - // since the library can make things that will live arbitrarily long. - let backend_sym = unsafe { backend_sym.into_raw() }; - mem::forget(lib); - - *backend_sym + } + } } /// Get the codegen backend based on the name and specified sysroot. diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 8da6f0007f0..a1c6fba4d43 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -45,7 +45,7 @@ metadata_crate_not_panic_runtime = the crate `{$crate_name}` is not a panic runtime metadata_dl_error = - {$err} + {$path}{$err} metadata_empty_link_name = link name must not be empty diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f6d3dba2470..8fea1a72223 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -692,20 +692,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { path: &Path, stable_crate_id: StableCrateId, ) -> Result<&'static [ProcMacro], CrateError> { - // Make sure the path contains a / or the linker will search for it. - let path = try_canonicalize(path).unwrap(); - let lib = load_dylib(&path, 5).map_err(|err| CrateError::DlOpen(err))?; - let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id); - let sym = unsafe { lib.get::<*const &[ProcMacro]>(sym_name.as_bytes()) } - .map_err(|err| CrateError::DlSym(err.to_string()))?; - - // Intentionally leak the dynamic library. We can't ever unload it - // since the library can make things that will live arbitrarily long. - let sym = unsafe { sym.into_raw() }; - std::mem::forget(lib); - - Ok(unsafe { **sym }) + Ok(unsafe { *load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name)? }) } fn inject_panic_runtime(&mut self, krate: &ast::Crate) { @@ -1116,6 +1104,10 @@ fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec { f.spans } +fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String { + e.sources().map(|e| format!(": {e}")).collect() +} + // On Windows the compiler would sometimes intermittently fail to open the // proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the // system still holds a lock on the file, so we retry a few times before calling it @@ -1154,9 +1146,43 @@ fn load_dylib(path: &Path, max_attempts: usize) -> Result for CrateError { + fn from(err: DylibError) -> CrateError { + match err { + DylibError::DlOpen(path, err) => CrateError::DlOpen(path, err), + DylibError::DlSym(path, err) => CrateError::DlSym(path, err), + } + } +} + +pub unsafe fn load_symbol_from_dylib( + path: &Path, + sym_name: &str, +) -> Result { + // Make sure the path contains a / or the linker will search for it. + let path = try_canonicalize(path).unwrap(); + let lib = + load_dylib(&path, 5).map_err(|err| DylibError::DlOpen(path.display().to_string(), err))?; + + let sym = unsafe { lib.get::(sym_name.as_bytes()) } + .map_err(|err| DylibError::DlSym(path.display().to_string(), format_dlopen_err(&err)))?; + + // Intentionally leak the dynamic library. We can't ever unload it + // since the library can make things that will live arbitrarily long. + let sym = unsafe { sym.into_raw() }; + std::mem::forget(lib); + + Ok(*sym) +} diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 7e0a4fb72d4..9a05d9ac0de 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -535,6 +535,7 @@ pub struct StableCrateIdCollision { pub struct DlError { #[primary_span] pub span: Span, + pub path: String, pub err: String, } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 70ad8598957..f133a2f5f73 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -3,6 +3,7 @@ #![feature(rustdoc_internals)] #![allow(internal_features)] #![feature(decl_macro)] +#![feature(error_iter)] #![feature(extract_if)] #![feature(coroutines)] #![feature(generic_nonzero)] @@ -39,6 +40,7 @@ pub mod errors; pub mod fs; pub mod locator; +pub use creader::{load_symbol_from_dylib, DylibError}; pub use fs::{emit_wrapper_file, METADATA_FILENAME}; pub use native_libs::find_native_static_library; pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER}; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 1ab965e2876..15f56db6278 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -921,8 +921,8 @@ pub(crate) enum CrateError { MultipleCandidates(Symbol, CrateFlavor, Vec), SymbolConflictsCurrent(Symbol), StableCrateIdCollision(Symbol, Symbol), - DlOpen(String), - DlSym(String), + DlOpen(String, String), + DlSym(String, String), LocatorCombined(Box), NotFound(Symbol), } @@ -967,8 +967,8 @@ impl CrateError { CrateError::StableCrateIdCollision(crate_name0, crate_name1) => { dcx.emit_err(errors::StableCrateIdCollision { span, crate_name0, crate_name1 }); } - CrateError::DlOpen(s) | CrateError::DlSym(s) => { - dcx.emit_err(errors::DlError { span, err: s }); + CrateError::DlOpen(path, err) | CrateError::DlSym(path, err) => { + dcx.emit_err(errors::DlError { span, path, err }); } CrateError::LocatorCombined(locator) => { let crate_name = locator.crate_name; -- cgit 1.4.1-3-g733a5 From 9eabdc2a4cc896065004fb8566509daa11d6562a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Feb 2024 14:18:06 +0100 Subject: make it possible for outside crates to inspect a mir::ConstValue with the interpreter --- .../src/const_eval/eval_queries.rs | 25 ++++++++++++++++++---- compiler/rustc_const_eval/src/const_eval/mod.rs | 3 +-- .../rustc_const_eval/src/const_eval/valtrees.rs | 10 +++++---- .../rustc_const_eval/src/util/caller_location.rs | 9 ++++++-- 4 files changed, 35 insertions(+), 12 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 7099cdd5a75..9e4e7911c3a 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -3,10 +3,11 @@ use either::{Left, Right}; use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; +use rustc_middle::query::TyCtxtAt; use rustc_middle::traits::Reveal; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_target::abi::{self, Abi}; @@ -87,13 +88,16 @@ fn eval_body_using_ecx<'mir, 'tcx>( } /// The `InterpCx` is only meant to be used to do field and index projections into constants for -/// `simd_shuffle` and const patterns in match arms. It never performs alignment checks. +/// `simd_shuffle` and const patterns in match arms. +/// +/// This should *not* be used to do any actual interpretation. In particular, alignment checks are +/// turned off! /// /// The function containing the `match` that is currently being analyzed may have generic bounds /// that inform us about the generic bounds of the constant. E.g., using an associated constant /// of a function's generic parameter will require knowledge about the bounds on the generic /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -pub(crate) fn mk_eval_cx<'mir, 'tcx>( +pub(crate) fn mk_eval_cx_to_read_const_val<'mir, 'tcx>( tcx: TyCtxt<'tcx>, root_span: Span, param_env: ty::ParamEnv<'tcx>, @@ -108,6 +112,19 @@ pub(crate) fn mk_eval_cx<'mir, 'tcx>( ) } +/// Create an interpreter context to inspect the given `ConstValue`. +/// Returns both the context and an `OpTy` that represents the constant. +pub fn mk_eval_cx_for_const_val<'mir, 'tcx>( + tcx: TyCtxtAt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + val: mir::ConstValue<'tcx>, + ty: Ty<'tcx>, +) -> Option<(CompileTimeEvalContext<'mir, 'tcx>, OpTy<'tcx>)> { + let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); + let op = ecx.const_val_to_op(val, ty, None).ok()?; + Some((ecx, op)) +} + /// This function converts an interpreter value into a MIR constant. /// /// The `for_diagnostics` flag turns the usual rules for returning `ConstValue::Scalar` into a @@ -203,7 +220,7 @@ pub(crate) fn turn_into_const_value<'tcx>( let def_id = cid.instance.def.def_id(); let is_static = tcx.is_static(def_id); // This is just accessing an already computed constant, so no need to check alignment here. - let ecx = mk_eval_cx( + let ecx = mk_eval_cx_to_read_const_val( tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index cd50701040e..289dcb7d01d 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -47,8 +47,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( ty: Ty<'tcx>, ) -> Option> { let param_env = ty::ParamEnv::reveal_all(); - let ecx = mk_eval_cx(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); - let op = ecx.const_val_to_op(val, ty, None).ok()?; + let (ecx, op) = mk_eval_cx_for_const_val(tcx, param_env, val, ty)?; // We go to `usize` as we cannot allocate anything bigger anyway. let (field_count, variant, down) = match ty.kind() { diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 514a6a7df76..d3428d27d52 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_target::abi::{Abi, VariantIdx}; -use super::eval_queries::{mk_eval_cx, op_to_const}; +use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; use super::machine::CompileTimeEvalContext; use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; use crate::const_eval::CanAccessMutGlobal; @@ -223,7 +223,7 @@ pub(crate) fn eval_to_valtree<'tcx>( let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?; // FIXME Need to provide a span to `eval_to_valtree` - let ecx = mk_eval_cx( + let ecx = mk_eval_cx_to_read_const_val( tcx, DUMMY_SP, param_env, @@ -287,7 +287,8 @@ pub fn valtree_to_const_value<'tcx>( } } ty::Ref(_, inner_ty, _) => { - let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); + let mut ecx = + mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty); let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap()); op_to_const(&ecx, &imm.into(), /* for diagnostics */ false) @@ -314,7 +315,8 @@ pub fn valtree_to_const_value<'tcx>( bug!("could not find non-ZST field during in {layout:#?}"); } - let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); + let mut ecx = + mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); // Need to create a place for this valtree. let place = create_valtree_place(&mut ecx, layout, valtree); diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index d1c2d22b5a9..b8e15c485f5 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_span::symbol::Symbol; use rustc_type_ir::Mutability; -use crate::const_eval::{mk_eval_cx, CanAccessMutGlobal, CompileTimeEvalContext}; +use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeEvalContext}; use crate::interpret::*; /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. @@ -57,7 +57,12 @@ pub(crate) fn const_caller_location_provider( col: u32, ) -> mir::ConstValue<'_> { trace!("const_caller_location: {}:{}:{}", file, line, col); - let mut ecx = mk_eval_cx(tcx.tcx, tcx.span, ty::ParamEnv::reveal_all(), CanAccessMutGlobal::No); + let mut ecx = mk_eval_cx_to_read_const_val( + tcx.tcx, + tcx.span, + ty::ParamEnv::reveal_all(), + CanAccessMutGlobal::No, + ); let loc_place = alloc_caller_location(&mut ecx, file, line, col); if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() { -- cgit 1.4.1-3-g733a5 From a17211b05c883eaeb4057f0a9207947bcbcc3688 Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Wed, 21 Feb 2024 16:49:01 +0100 Subject: Solaris linker does not support --strip-debug Fixes #121381 --- compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'compiler') diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 9f06f398288..1f3383815e2 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -626,7 +626,7 @@ impl<'a> Linker for GccLinker<'a> { // it does support --strip-all as a compatibility alias for -s. // The --strip-debug case is handled by running an external // `strip` utility as a separate step after linking. - if self.sess.target.os != "illumos" { + if !self.sess.target.is_like_solaris { self.linker_arg("--strip-debug"); } } -- cgit 1.4.1-3-g733a5 From da1e6a8c1c282ce4c5d7e8792cc3efa373119c72 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 19 Feb 2024 23:47:05 +0000 Subject: Yeet QueryTypeRelatingDelegate --- .../rustc_borrowck/src/type_check/relate_tys.rs | 4 - .../src/infer/canonical/query_response.rs | 98 +++------------------- compiler/rustc_infer/src/infer/relate/nll.rs | 22 ++--- 3 files changed, 18 insertions(+), 106 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index a60175d9896..2dcfef66257 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -164,10 +164,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> ); } - fn forbid_inference_vars() -> bool { - true - } - fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op( self.locations, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5a2795e790d..9d2e065afa3 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -12,22 +12,19 @@ use crate::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues, QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, }; -use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult}; use crate::traits::query::NoSolution; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt}; +use crate::traits::{TraitEngine, TraitEngineExt}; use rustc_data_structures::captures::Captures; use rustc_index::Idx; use rustc_index::IndexVec; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::{self, BoundVar, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; -use rustc_span::{Span, Symbol}; use std::fmt::Debug; use std::iter; @@ -290,31 +287,19 @@ impl<'tcx> InferCtxt<'tcx> { } (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { - TypeRelating::new( - self, - QueryTypeRelatingDelegate { - infcx: self, - param_env, - cause, - obligations: &mut obligations, - }, - ty::Variance::Invariant, - ) - .relate(v1, v2)?; + obligations.extend( + self.at(&cause, param_env) + .eq(DefineOpaqueTypes::Yes, v1, v2)? + .into_obligations(), + ); } (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { - TypeRelating::new( - self, - QueryTypeRelatingDelegate { - infcx: self, - param_env, - cause, - obligations: &mut obligations, - }, - ty::Variance::Invariant, - ) - .relate(v1, v2)?; + obligations.extend( + self.at(&cause, param_env) + .eq(DefineOpaqueTypes::Yes, v1, v2)? + .into_obligations(), + ); } _ => { @@ -697,60 +682,3 @@ pub fn make_query_region_constraints<'tcx>( QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() } } - -struct QueryTypeRelatingDelegate<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, - obligations: &'a mut Vec>, - param_env: ty::ParamEnv<'tcx>, - cause: &'a ObligationCause<'tcx>, -} - -impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { - fn span(&self) -> Span { - self.cause.span - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn create_next_universe(&mut self) -> ty::UniverseIndex { - self.infcx.create_next_universe() - } - - fn next_existential_region_var( - &mut self, - from_forall: bool, - _name: Option, - ) -> ty::Region<'tcx> { - let origin = NllRegionVariableOrigin::Existential { from_forall }; - self.infcx.next_nll_region_var(origin) - } - - fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - ty::Region::new_placeholder(self.infcx.tcx, placeholder) - } - - fn push_outlives( - &mut self, - sup: ty::Region<'tcx>, - sub: ty::Region<'tcx>, - _info: ty::VarianceDiagInfo<'tcx>, - ) { - self.obligations.push(Obligation { - cause: self.cause.clone(), - param_env: self.param_env, - predicate: ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(sup, sub)) - .to_predicate(self.infcx.tcx), - recursion_depth: 0, - }); - } - - fn forbid_inference_vars() -> bool { - true - } - - fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { - self.obligations.extend(obligations); - } -} diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs index 87a1ae7bbac..069a7eeddc5 100644 --- a/compiler/rustc_infer/src/infer/relate/nll.rs +++ b/compiler/rustc_infer/src/infer/relate/nll.rs @@ -96,10 +96,6 @@ pub trait TypeRelatingDelegate<'tcx> { /// we will invoke this method to instantiate `'b` with a /// placeholder region. fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx>; - - /// Enables some optimizations if we do not expect inference variables - /// in the RHS of the relation. - fn forbid_inference_vars() -> bool; } impl<'me, 'tcx, D> TypeRelating<'me, 'tcx, D> @@ -316,16 +312,11 @@ where } #[instrument(skip(self), level = "debug")] - fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { let infcx = self.infcx; let a = self.infcx.shallow_resolve(a); - - if !D::forbid_inference_vars() { - b = self.infcx.shallow_resolve(b); - } else { - assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); - } + assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); if a == b { return Ok(a); @@ -409,16 +400,13 @@ where fn consts( &mut self, a: ty::Const<'tcx>, - mut b: ty::Const<'tcx>, + b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { let a = self.infcx.shallow_resolve(a); - - if !D::forbid_inference_vars() { - b = self.infcx.shallow_resolve(b); - } + assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); match b.kind() { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { + ty::ConstKind::Infer(InferConst::Var(_)) => { // Forbid inference variables in the RHS. self.infcx .dcx() -- cgit 1.4.1-3-g733a5 From 6c030332ee32fcc635ec61e5183d0181a31c7de9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Feb 2024 00:53:59 +0000 Subject: Make TypeRelating more NLL-specific --- compiler/rustc_borrowck/src/type_check/relate_tys.rs | 8 ++++---- compiler/rustc_infer/src/infer/relate/nll.rs | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 2dcfef66257..34cec4caea1 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,5 +1,5 @@ use rustc_errors::ErrorGuaranteed; -use rustc_infer::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; +use rustc_infer::infer::nll_relate::{NllTypeRelating, NllTypeRelatingDelegate}; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_infer::traits::PredicateObligations; use rustc_middle::mir::ConstraintCategory; @@ -32,7 +32,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) -> Result<(), NoSolution> { - TypeRelating::new( + NllTypeRelating::new( self.infcx, NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)), v, @@ -49,7 +49,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) -> Result<(), NoSolution> { - TypeRelating::new( + NllTypeRelating::new( self.infcx, NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()), ty::Variance::Invariant, @@ -84,7 +84,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { } } -impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { +impl<'tcx> NllTypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { fn span(&self) -> Span { self.locations.span(self.type_checker.body) } diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs index 069a7eeddc5..a34c3313b1a 100644 --- a/compiler/rustc_infer/src/infer/relate/nll.rs +++ b/compiler/rustc_infer/src/infer/relate/nll.rs @@ -34,9 +34,9 @@ use crate::infer::InferCtxt; use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::traits::{Obligation, PredicateObligations}; -pub struct TypeRelating<'me, 'tcx, D> +pub struct NllTypeRelating<'me, 'tcx, D> where - D: TypeRelatingDelegate<'tcx>, + D: NllTypeRelatingDelegate<'tcx>, { infcx: &'me InferCtxt<'tcx>, @@ -54,7 +54,7 @@ where ambient_variance_info: ty::VarianceDiagInfo<'tcx>, } -pub trait TypeRelatingDelegate<'tcx> { +pub trait NllTypeRelatingDelegate<'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx>; fn span(&self) -> Span; @@ -98,9 +98,9 @@ pub trait TypeRelatingDelegate<'tcx> { fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx>; } -impl<'me, 'tcx, D> TypeRelating<'me, 'tcx, D> +impl<'me, 'tcx, D> NllTypeRelating<'me, 'tcx, D> where - D: TypeRelatingDelegate<'tcx>, + D: NllTypeRelatingDelegate<'tcx>, { pub fn new(infcx: &'me InferCtxt<'tcx>, delegate: D, ambient_variance: ty::Variance) -> Self { Self { @@ -273,9 +273,9 @@ where } } -impl<'tcx, D> TypeRelation<'tcx> for TypeRelating<'_, 'tcx, D> +impl<'tcx, D> TypeRelation<'tcx> for NllTypeRelating<'_, 'tcx, D> where - D: TypeRelatingDelegate<'tcx>, + D: NllTypeRelatingDelegate<'tcx>, { fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx @@ -514,9 +514,9 @@ where } } -impl<'tcx, D> ObligationEmittingRelation<'tcx> for TypeRelating<'_, 'tcx, D> +impl<'tcx, D> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'tcx, D> where - D: TypeRelatingDelegate<'tcx>, + D: NllTypeRelatingDelegate<'tcx>, { fn span(&self) -> Span { self.delegate.span() -- cgit 1.4.1-3-g733a5 From 64d6303ac6d3141b05cde8223aadc723bb833709 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Feb 2024 17:45:45 +0000 Subject: Inline NllTypeRelating into its only usage site --- .../rustc_borrowck/src/type_check/relate_tys.rs | 469 ++++++++++++++++- compiler/rustc_infer/src/infer/mod.rs | 1 - .../rustc_infer/src/infer/relate/generalize.rs | 6 +- compiler/rustc_infer/src/infer/relate/mod.rs | 1 - compiler/rustc_infer/src/infer/relate/nll.rs | 573 --------------------- 5 files changed, 451 insertions(+), 599 deletions(-) delete mode 100644 compiler/rustc_infer/src/infer/relate/nll.rs (limited to 'compiler') diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 34cec4caea1..dd355c3525c 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,11 +1,14 @@ +use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; -use rustc_infer::infer::nll_relate::{NllTypeRelating, NllTypeRelatingDelegate}; -use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_infer::traits::PredicateObligations; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::{NllRegionVariableOrigin, ObligationEmittingRelation}; +use rustc_infer::traits::{Obligation, PredicateObligations}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::fold::FnMutDelegate; +use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -32,12 +35,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) -> Result<(), NoSolution> { - NllTypeRelating::new( - self.infcx, - NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)), - v, - ) - .relate(a, b)?; + NllTypeRelating::new(self, locations, category, UniverseInfo::relate(a, b), v) + .relate(a, b)?; Ok(()) } @@ -50,8 +49,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory<'tcx>, ) -> Result<(), NoSolution> { NllTypeRelating::new( - self.infcx, - NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()), + self, + locations, + category, + UniverseInfo::other(), ty::Variance::Invariant, ) .relate(a, b)?; @@ -59,7 +60,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } -struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { +pub struct NllTypeRelating<'me, 'bccx, 'tcx> { type_checker: &'me mut TypeChecker<'bccx, 'tcx>, /// Where (and why) is this relation taking place? @@ -71,26 +72,177 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { /// Information so that error reporting knows what types we are relating /// when reporting a bound region error. universe_info: UniverseInfo<'tcx>, + + /// How are we relating `a` and `b`? + /// + /// - Covariant means `a <: b`. + /// - Contravariant means `b <: a`. + /// - Invariant means `a == b`. + /// - Bivariant means that it doesn't matter. + ambient_variance: ty::Variance, + + ambient_variance_info: ty::VarianceDiagInfo<'tcx>, } -impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { - fn new( +impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { + pub fn new( type_checker: &'me mut TypeChecker<'bccx, 'tcx>, locations: Locations, category: ConstraintCategory<'tcx>, universe_info: UniverseInfo<'tcx>, + ambient_variance: ty::Variance, ) -> Self { - Self { type_checker, locations, category, universe_info } + Self { + type_checker, + locations, + category, + universe_info, + ambient_variance, + ambient_variance_info: ty::VarianceDiagInfo::default(), + } } -} -impl<'tcx> NllTypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { - fn span(&self) -> Span { - self.locations.span(self.type_checker.body) + fn ambient_covariance(&self) -> bool { + match self.ambient_variance { + ty::Variance::Covariant | ty::Variance::Invariant => true, + ty::Variance::Contravariant | ty::Variance::Bivariant => false, + } } - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.type_checker.param_env + fn ambient_contravariance(&self) -> bool { + match self.ambient_variance { + ty::Variance::Contravariant | ty::Variance::Invariant => true, + ty::Variance::Covariant | ty::Variance::Bivariant => false, + } + } + + fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let infcx = self.type_checker.infcx; + debug_assert!(!infcx.next_trait_solver()); + let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; + // `handle_opaque_type` cannot handle subtyping, so to support subtyping + // we instead eagerly generalize here. This is a bit of a mess but will go + // away once we're using the new solver. + let mut enable_subtyping = |ty, ty_is_expected| { + let ty_vid = infcx.next_ty_var_id_in_universe( + TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: self.span(), + }, + ty::UniverseIndex::ROOT, + ); + + let variance = if ty_is_expected { + self.ambient_variance + } else { + self.ambient_variance.xform(ty::Contravariant) + }; + + self.type_checker.infcx.instantiate_ty_var( + self, + ty_is_expected, + ty_vid, + variance, + ty, + )?; + Ok(infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid)))) + }; + + let (a, b) = match (a.kind(), b.kind()) { + (&ty::Alias(ty::Opaque, ..), _) => (a, enable_subtyping(b, false)?), + (_, &ty::Alias(ty::Opaque, ..)) => (enable_subtyping(a, true)?, b), + _ => unreachable!( + "expected at least one opaque type in `relate_opaques`, got {a} and {b}." + ), + }; + let cause = ObligationCause::dummy_with_span(self.span()); + let obligations = + infcx.handle_opaque_type(a, b, true, &cause, self.param_env())?.obligations; + self.register_obligations(obligations); + Ok(()) + } + + fn enter_forall( + &mut self, + binder: ty::Binder<'tcx, T>, + f: impl FnOnce(&mut Self, T) -> U, + ) -> U + where + T: ty::TypeFoldable> + Copy, + { + let value = if let Some(inner) = binder.no_bound_vars() { + inner + } else { + let infcx = self.type_checker.infcx; + let mut lazy_universe = None; + let delegate = FnMutDelegate { + regions: &mut |br: ty::BoundRegion| { + // The first time this closure is called, create a + // new universe for the placeholders we will make + // from here out. + let universe = lazy_universe.unwrap_or_else(|| { + let universe = self.create_next_universe(); + lazy_universe = Some(universe); + universe + }); + + let placeholder = ty::PlaceholderRegion { universe, bound: br }; + debug!(?placeholder); + let placeholder_reg = self.next_placeholder_region(placeholder); + debug!(?placeholder_reg); + + placeholder_reg + }, + types: &mut |_bound_ty: ty::BoundTy| { + unreachable!("we only replace regions in nll_relate, not types") + }, + consts: &mut |_bound_var: ty::BoundVar, _ty| { + unreachable!("we only replace regions in nll_relate, not consts") + }, + }; + + infcx.tcx.replace_bound_vars_uncached(binder, delegate) + }; + + debug!(?value); + f(self, value) + } + + #[instrument(skip(self), level = "debug")] + fn instantiate_binder_with_existentials(&mut self, binder: ty::Binder<'tcx, T>) -> T + where + T: ty::TypeFoldable> + Copy, + { + if let Some(inner) = binder.no_bound_vars() { + return inner; + } + + let infcx = self.type_checker.infcx; + let mut reg_map = FxHashMap::default(); + let delegate = FnMutDelegate { + regions: &mut |br: ty::BoundRegion| { + if let Some(ex_reg_var) = reg_map.get(&br) { + return *ex_reg_var; + } else { + let ex_reg_var = self.next_existential_region_var(true, br.kind.get_name()); + debug!(?ex_reg_var); + reg_map.insert(br, ex_reg_var); + + ex_reg_var + } + }, + types: &mut |_bound_ty: ty::BoundTy| { + unreachable!("we only replace regions in nll_relate, not types") + }, + consts: &mut |_bound_var: ty::BoundVar, _ty| { + unreachable!("we only replace regions in nll_relate, not consts") + }, + }; + + let replaced = infcx.tcx.replace_bound_vars_uncached(binder, delegate); + debug!(?replaced); + + replaced } fn create_next_universe(&mut self) -> ty::UniverseIndex { @@ -163,6 +315,249 @@ impl<'tcx> NllTypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tc }, ); } +} + +impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.type_checker.infcx.tcx + } + + fn tag(&self) -> &'static str { + "nll::subtype" + } + + fn a_is_expected(&self) -> bool { + true + } + + #[instrument(skip(self, info), level = "trace", ret)] + fn relate_with_variance>( + &mut self, + variance: ty::Variance, + info: ty::VarianceDiagInfo<'tcx>, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + let old_ambient_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + self.ambient_variance_info = self.ambient_variance_info.xform(info); + + debug!(?self.ambient_variance); + // In a bivariant context this always succeeds. + let r = + if self.ambient_variance == ty::Variance::Bivariant { a } else { self.relate(a, b)? }; + + self.ambient_variance = old_ambient_variance; + + Ok(r) + } + + #[instrument(skip(self), level = "debug")] + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + let infcx = self.type_checker.infcx; + + let a = self.type_checker.infcx.shallow_resolve(a); + assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); + + if a == b { + return Ok(a); + } + + match (a.kind(), b.kind()) { + (_, &ty::Infer(ty::TyVar(_))) => { + span_bug!( + self.span(), + "should not be relating type variables on the right in MIR typeck" + ); + } + + (&ty::Infer(ty::TyVar(a_vid)), _) => { + infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)? + } + + ( + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), + &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), + ) if a_def_id == b_def_id || infcx.next_trait_solver() => { + infcx.super_combine_tys(self, a, b).map(|_| ()).or_else(|err| { + // This behavior is only there for the old solver, the new solver + // shouldn't ever fail. Instead, it unconditionally emits an + // alias-relate goal. + assert!(!self.type_checker.infcx.next_trait_solver()); + self.tcx().dcx().span_delayed_bug( + self.span(), + "failure to relate an opaque to itself should result in an error later on", + ); + if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } + })?; + } + (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) + | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) + if def_id.is_local() && !self.type_checker.infcx.next_trait_solver() => + { + self.relate_opaques(a, b)?; + } + + _ => { + debug!(?a, ?b, ?self.ambient_variance); + + // Will also handle unification of `IntVar` and `FloatVar`. + self.type_checker.infcx.super_combine_tys(self, a, b)?; + } + } + + Ok(a) + } + + #[instrument(skip(self), level = "trace")] + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + debug!(?self.ambient_variance); + + if self.ambient_covariance() { + // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`. + self.push_outlives(a, b, self.ambient_variance_info); + } + + if self.ambient_contravariance() { + // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`. + self.push_outlives(b, a, self.ambient_variance_info); + } + + Ok(a) + } + + fn consts( + &mut self, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + let a = self.type_checker.infcx.shallow_resolve(a); + assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a); + assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); + + self.type_checker.infcx.super_combine_consts(self, a, b) + } + + #[instrument(skip(self), level = "trace")] + fn binders( + &mut self, + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: Relate<'tcx>, + { + // We want that + // + // ``` + // for<'a> fn(&'a u32) -> &'a u32 <: + // fn(&'b u32) -> &'b u32 + // ``` + // + // but not + // + // ``` + // fn(&'a u32) -> &'a u32 <: + // for<'b> fn(&'b u32) -> &'b u32 + // ``` + // + // We therefore proceed as follows: + // + // - Instantiate binders on `b` universally, yielding a universe U1. + // - Instantiate binders on `a` existentially in U1. + + debug!(?self.ambient_variance); + + if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) { + // Fast path for the common case. + self.relate(a, b)?; + return Ok(ty::Binder::dummy(a)); + } + + if self.ambient_covariance() { + // Covariance, so we want `for<..> A <: for<..> B` -- + // therefore we compare any instantiation of A (i.e., A + // instantiated with existentials) against every + // instantiation of B (i.e., B instantiated with + // universals). + + // Reset the ambient variance to covariant. This is needed + // to correctly handle cases like + // + // for<'a> fn(&'a u32, &'a u32) == for<'b, 'c> fn(&'b u32, &'c u32) + // + // Somewhat surprisingly, these two types are actually + // **equal**, even though the one on the right looks more + // polymorphic. The reason is due to subtyping. To see it, + // consider that each function can call the other: + // + // - The left function can call the right with `'b` and + // `'c` both equal to `'a` + // + // - The right function can call the left with `'a` set to + // `{P}`, where P is the point in the CFG where the call + // itself occurs. Note that `'b` and `'c` must both + // include P. At the point, the call works because of + // subtyping (i.e., `&'b u32 <: &{P} u32`). + let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); + + // Note: the order here is important. Create the placeholders first, otherwise + // we assign the wrong universe to the existential! + self.enter_forall(b, |this, b| { + let a = this.instantiate_binder_with_existentials(a); + this.relate(a, b) + })?; + + self.ambient_variance = variance; + } + + if self.ambient_contravariance() { + // Contravariance, so we want `for<..> A :> for<..> B` + // -- therefore we compare every instantiation of A (i.e., + // A instantiated with universals) against any + // instantiation of B (i.e., B instantiated with + // existentials). Opposite of above. + + // Reset ambient variance to contravariance. See the + // covariant case above for an explanation. + let variance = + std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); + + self.enter_forall(a, |this, a| { + let b = this.instantiate_binder_with_existentials(b); + this.relate(a, b) + })?; + + self.ambient_variance = variance; + } + + Ok(a) + } +} + +impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { + fn span(&self) -> Span { + self.locations.span(self.type_checker.body) + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.type_checker.param_env + } + + fn register_predicates(&mut self, obligations: impl IntoIterator>) { + self.register_obligations( + obligations + .into_iter() + .map(|to_pred| { + Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred) + }) + .collect(), + ); + } fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op( @@ -176,4 +571,32 @@ impl<'tcx> NllTypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tc }, ); } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance") + } + + fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { + self.register_predicates([ty::Binder::dummy(match self.ambient_variance { + ty::Variance::Covariant => ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Subtype, + ), + // a :> b is b <: a + ty::Variance::Contravariant => ty::PredicateKind::AliasRelate( + b.into(), + a.into(), + ty::AliasRelationDirection::Subtype, + ), + ty::Variance::Invariant => ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ), + ty::Variance::Bivariant => { + unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)") + } + })]); + } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 243558b11a8..60711ffeb2c 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -54,7 +54,6 @@ use self::region_constraints::{ RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, }; pub use self::relate::combine::CombineFields; -pub use self::relate::nll as nll_relate; use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 371340c5bbf..90f10a0eba9 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -22,8 +22,12 @@ impl<'tcx> InferCtxt<'tcx> { /// subtyping could occur. This also does the occurs checks, detecting whether /// instantiating `target_vid` would result in a cyclic type. We eagerly error /// in this case. + /// + /// This is *not* expected to be used anywhere except for an implementation of + /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all + /// other usecases (i.e. setting the value of a type var). #[instrument(level = "debug", skip(self, relation, target_is_expected))] - pub(super) fn instantiate_ty_var>( + pub fn instantiate_ty_var>( &self, relation: &mut R, target_is_expected: bool, diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index 26270c77f1a..1207377e857 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -8,5 +8,4 @@ mod glb; mod higher_ranked; mod lattice; mod lub; -pub mod nll; mod sub; diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs deleted file mode 100644 index a34c3313b1a..00000000000 --- a/compiler/rustc_infer/src/infer/relate/nll.rs +++ /dev/null @@ -1,573 +0,0 @@ -//! This code is kind of an alternate way of doing subtyping, -//! supertyping, and type equating, distinct from the `combine.rs` -//! code but very similar in its effect and design. Eventually the two -//! ought to be merged. This code is intended for use in NLL and chalk. -//! -//! Here are the key differences: -//! -//! - This code may choose to bypass some checks (e.g., the occurs check) -//! in the case where we know that there are no unbound type inference -//! variables. This is the case for NLL, because at NLL time types are fully -//! inferred up-to regions. -//! - This code uses "universes" to handle higher-ranked regions and -//! not the leak-check. This is "more correct" than what rustc does -//! and we are generally migrating in this direction, but NLL had to -//! get there first. -//! -//! Also, this code assumes that there are no bound types at all, not even -//! free ones. This is ok because: -//! - we are not relating anything quantified over some type variable -//! - we will have instantiated all the bound type vars already (the one -//! thing we relate in chalk are basically domain goals and their -//! constituents) - -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; -use rustc_span::{Span, Symbol}; - -use super::combine::ObligationEmittingRelation; -use crate::infer::InferCtxt; -use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::traits::{Obligation, PredicateObligations}; - -pub struct NllTypeRelating<'me, 'tcx, D> -where - D: NllTypeRelatingDelegate<'tcx>, -{ - infcx: &'me InferCtxt<'tcx>, - - /// Callback to use when we deduce an outlives relationship. - delegate: D, - - /// How are we relating `a` and `b`? - /// - /// - Covariant means `a <: b`. - /// - Contravariant means `b <: a`. - /// - Invariant means `a == b`. - /// - Bivariant means that it doesn't matter. - ambient_variance: ty::Variance, - - ambient_variance_info: ty::VarianceDiagInfo<'tcx>, -} - -pub trait NllTypeRelatingDelegate<'tcx> { - fn param_env(&self) -> ty::ParamEnv<'tcx>; - fn span(&self) -> Span; - - /// Push a constraint `sup: sub` -- this constraint must be - /// satisfied for the two types to be related. `sub` and `sup` may - /// be regions from the type or new variables created through the - /// delegate. - fn push_outlives( - &mut self, - sup: ty::Region<'tcx>, - sub: ty::Region<'tcx>, - info: ty::VarianceDiagInfo<'tcx>, - ); - - fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>); - - /// Creates a new universe index. Used when instantiating placeholders. - fn create_next_universe(&mut self) -> ty::UniverseIndex; - - /// Creates a new region variable representing a higher-ranked - /// region that is instantiated existentially. This creates an - /// inference variable, typically. - /// - /// So e.g., if you have `for<'a> fn(..) <: for<'b> fn(..)`, then - /// we will invoke this method to instantiate `'a` with an - /// inference variable (though `'b` would be instantiated first, - /// as a placeholder). - fn next_existential_region_var( - &mut self, - was_placeholder: bool, - name: Option, - ) -> ty::Region<'tcx>; - - /// Creates a new region variable representing a - /// higher-ranked region that is instantiated universally. - /// This creates a new region placeholder, typically. - /// - /// So e.g., if you have `for<'a> fn(..) <: for<'b> fn(..)`, then - /// we will invoke this method to instantiate `'b` with a - /// placeholder region. - fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx>; -} - -impl<'me, 'tcx, D> NllTypeRelating<'me, 'tcx, D> -where - D: NllTypeRelatingDelegate<'tcx>, -{ - pub fn new(infcx: &'me InferCtxt<'tcx>, delegate: D, ambient_variance: ty::Variance) -> Self { - Self { - infcx, - delegate, - ambient_variance, - ambient_variance_info: ty::VarianceDiagInfo::default(), - } - } - - fn ambient_covariance(&self) -> bool { - match self.ambient_variance { - ty::Variance::Covariant | ty::Variance::Invariant => true, - ty::Variance::Contravariant | ty::Variance::Bivariant => false, - } - } - - fn ambient_contravariance(&self) -> bool { - match self.ambient_variance { - ty::Variance::Contravariant | ty::Variance::Invariant => true, - ty::Variance::Covariant | ty::Variance::Bivariant => false, - } - } - - /// Push a new outlives requirement into our output set of - /// constraints. - fn push_outlives( - &mut self, - sup: ty::Region<'tcx>, - sub: ty::Region<'tcx>, - info: ty::VarianceDiagInfo<'tcx>, - ) { - debug!("push_outlives({:?}: {:?})", sup, sub); - - self.delegate.push_outlives(sup, sub, info); - } - - fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let infcx = self.infcx; - debug_assert!(!infcx.next_trait_solver()); - let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; - // `handle_opaque_type` cannot handle subtyping, so to support subtyping - // we instead eagerly generalize here. This is a bit of a mess but will go - // away once we're using the new solver. - let mut enable_subtyping = |ty, ty_is_expected| { - let ty_vid = infcx.next_ty_var_id_in_universe( - TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: self.delegate.span(), - }, - ty::UniverseIndex::ROOT, - ); - - let variance = if ty_is_expected { - self.ambient_variance - } else { - self.ambient_variance.xform(ty::Contravariant) - }; - - self.infcx.instantiate_ty_var(self, ty_is_expected, ty_vid, variance, ty)?; - Ok(infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid)))) - }; - - let (a, b) = match (a.kind(), b.kind()) { - (&ty::Alias(ty::Opaque, ..), _) => (a, enable_subtyping(b, false)?), - (_, &ty::Alias(ty::Opaque, ..)) => (enable_subtyping(a, true)?, b), - _ => unreachable!( - "expected at least one opaque type in `relate_opaques`, got {a} and {b}." - ), - }; - let cause = ObligationCause::dummy_with_span(self.delegate.span()); - let obligations = - infcx.handle_opaque_type(a, b, true, &cause, self.delegate.param_env())?.obligations; - self.delegate.register_obligations(obligations); - Ok(()) - } - - fn enter_forall( - &mut self, - binder: ty::Binder<'tcx, T>, - f: impl FnOnce(&mut Self, T) -> U, - ) -> U - where - T: ty::TypeFoldable> + Copy, - { - let value = if let Some(inner) = binder.no_bound_vars() { - inner - } else { - let mut next_region = { - let nll_delegate = &mut self.delegate; - let mut lazy_universe = None; - - move |br: ty::BoundRegion| { - // The first time this closure is called, create a - // new universe for the placeholders we will make - // from here out. - let universe = lazy_universe.unwrap_or_else(|| { - let universe = nll_delegate.create_next_universe(); - lazy_universe = Some(universe); - universe - }); - - let placeholder = ty::PlaceholderRegion { universe, bound: br }; - debug!(?placeholder); - let placeholder_reg = nll_delegate.next_placeholder_region(placeholder); - debug!(?placeholder_reg); - - placeholder_reg - } - }; - - let delegate = FnMutDelegate { - regions: &mut next_region, - types: &mut |_bound_ty: ty::BoundTy| { - unreachable!("we only replace regions in nll_relate, not types") - }, - consts: &mut |_bound_var: ty::BoundVar, _ty| { - unreachable!("we only replace regions in nll_relate, not consts") - }, - }; - - self.infcx.tcx.replace_bound_vars_uncached(binder, delegate) - }; - - debug!(?value); - f(self, value) - } - - #[instrument(skip(self), level = "debug")] - fn instantiate_binder_with_existentials(&mut self, binder: ty::Binder<'tcx, T>) -> T - where - T: ty::TypeFoldable> + Copy, - { - if let Some(inner) = binder.no_bound_vars() { - return inner; - } - - let mut next_region = { - let nll_delegate = &mut self.delegate; - let mut reg_map = FxHashMap::default(); - - move |br: ty::BoundRegion| { - if let Some(ex_reg_var) = reg_map.get(&br) { - return *ex_reg_var; - } else { - let ex_reg_var = - nll_delegate.next_existential_region_var(true, br.kind.get_name()); - debug!(?ex_reg_var); - reg_map.insert(br, ex_reg_var); - - ex_reg_var - } - } - }; - - let delegate = FnMutDelegate { - regions: &mut next_region, - types: &mut |_bound_ty: ty::BoundTy| { - unreachable!("we only replace regions in nll_relate, not types") - }, - consts: &mut |_bound_var: ty::BoundVar, _ty| { - unreachable!("we only replace regions in nll_relate, not consts") - }, - }; - - let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate); - debug!(?replaced); - - replaced - } -} - -impl<'tcx, D> TypeRelation<'tcx> for NllTypeRelating<'_, 'tcx, D> -where - D: NllTypeRelatingDelegate<'tcx>, -{ - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn tag(&self) -> &'static str { - "nll::subtype" - } - - fn a_is_expected(&self) -> bool { - true - } - - #[instrument(skip(self, info), level = "trace", ret)] - fn relate_with_variance>( - &mut self, - variance: ty::Variance, - info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - self.ambient_variance_info = self.ambient_variance_info.xform(info); - - debug!(?self.ambient_variance); - // In a bivariant context this always succeeds. - let r = - if self.ambient_variance == ty::Variance::Bivariant { a } else { self.relate(a, b)? }; - - self.ambient_variance = old_ambient_variance; - - Ok(r) - } - - #[instrument(skip(self), level = "debug")] - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let infcx = self.infcx; - - let a = self.infcx.shallow_resolve(a); - assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); - - if a == b { - return Ok(a); - } - - match (a.kind(), b.kind()) { - (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { - match self.ambient_variance { - ty::Invariant => infcx.inner.borrow_mut().type_variables().equate(a_vid, b_vid), - _ => unimplemented!(), - } - } - - (&ty::Infer(ty::TyVar(a_vid)), _) => { - infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)? - } - - (_, &ty::Infer(ty::TyVar(b_vid))) => infcx.instantiate_ty_var( - self, - false, - b_vid, - self.ambient_variance.xform(ty::Contravariant), - a, - )?, - - ( - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if a_def_id == b_def_id || infcx.next_trait_solver() => { - infcx.super_combine_tys(self, a, b).map(|_| ()).or_else(|err| { - // This behavior is only there for the old solver, the new solver - // shouldn't ever fail. Instead, it unconditionally emits an - // alias-relate goal. - assert!(!self.infcx.next_trait_solver()); - self.tcx().dcx().span_delayed_bug( - self.delegate.span(), - "failure to relate an opaque to itself should result in an error later on", - ); - if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } - })?; - } - (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) - | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if def_id.is_local() && !self.infcx.next_trait_solver() => - { - self.relate_opaques(a, b)?; - } - - _ => { - debug!(?a, ?b, ?self.ambient_variance); - - // Will also handle unification of `IntVar` and `FloatVar`. - self.infcx.super_combine_tys(self, a, b)?; - } - } - - Ok(a) - } - - #[instrument(skip(self), level = "trace")] - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!(?self.ambient_variance); - - if self.ambient_covariance() { - // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`. - self.push_outlives(a, b, self.ambient_variance_info); - } - - if self.ambient_contravariance() { - // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`. - self.push_outlives(b, a, self.ambient_variance_info); - } - - Ok(a) - } - - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - let a = self.infcx.shallow_resolve(a); - assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b); - - match b.kind() { - ty::ConstKind::Infer(InferConst::Var(_)) => { - // Forbid inference variables in the RHS. - self.infcx - .dcx() - .span_bug(self.delegate.span(), format!("unexpected inference var {b:?}")); - } - // FIXME(invariance): see the related FIXME above. - _ => self.infcx.super_combine_consts(self, a, b), - } - } - - #[instrument(skip(self), level = "trace")] - fn binders( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - // We want that - // - // ``` - // for<'a> fn(&'a u32) -> &'a u32 <: - // fn(&'b u32) -> &'b u32 - // ``` - // - // but not - // - // ``` - // fn(&'a u32) -> &'a u32 <: - // for<'b> fn(&'b u32) -> &'b u32 - // ``` - // - // We therefore proceed as follows: - // - // - Instantiate binders on `b` universally, yielding a universe U1. - // - Instantiate binders on `a` existentially in U1. - - debug!(?self.ambient_variance); - - if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) { - // Fast path for the common case. - self.relate(a, b)?; - return Ok(ty::Binder::dummy(a)); - } - - if self.ambient_covariance() { - // Covariance, so we want `for<..> A <: for<..> B` -- - // therefore we compare any instantiation of A (i.e., A - // instantiated with existentials) against every - // instantiation of B (i.e., B instantiated with - // universals). - - // Reset the ambient variance to covariant. This is needed - // to correctly handle cases like - // - // for<'a> fn(&'a u32, &'a u32) == for<'b, 'c> fn(&'b u32, &'c u32) - // - // Somewhat surprisingly, these two types are actually - // **equal**, even though the one on the right looks more - // polymorphic. The reason is due to subtyping. To see it, - // consider that each function can call the other: - // - // - The left function can call the right with `'b` and - // `'c` both equal to `'a` - // - // - The right function can call the left with `'a` set to - // `{P}`, where P is the point in the CFG where the call - // itself occurs. Note that `'b` and `'c` must both - // include P. At the point, the call works because of - // subtyping (i.e., `&'b u32 <: &{P} u32`). - let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); - - // Note: the order here is important. Create the placeholders first, otherwise - // we assign the wrong universe to the existential! - self.enter_forall(b, |this, b| { - let a = this.instantiate_binder_with_existentials(a); - this.relate(a, b) - })?; - - self.ambient_variance = variance; - } - - if self.ambient_contravariance() { - // Contravariance, so we want `for<..> A :> for<..> B` - // -- therefore we compare every instantiation of A (i.e., - // A instantiated with universals) against any - // instantiation of B (i.e., B instantiated with - // existentials). Opposite of above. - - // Reset ambient variance to contravariance. See the - // covariant case above for an explanation. - let variance = - std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); - - self.enter_forall(a, |this, a| { - let b = this.instantiate_binder_with_existentials(b); - this.relate(a, b) - })?; - - self.ambient_variance = variance; - } - - Ok(a) - } -} - -impl<'tcx, D> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'tcx, D> -where - D: NllTypeRelatingDelegate<'tcx>, -{ - fn span(&self) -> Span { - self.delegate.span() - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.delegate.param_env() - } - - fn register_predicates(&mut self, obligations: impl IntoIterator>) { - self.delegate.register_obligations( - obligations - .into_iter() - .map(|to_pred| { - Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred) - }) - .collect(), - ); - } - - fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { - self.delegate.register_obligations(obligations); - } - - fn alias_relate_direction(&self) -> ty::AliasRelationDirection { - unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance") - } - - fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { - self.register_predicates([ty::Binder::dummy(match self.ambient_variance { - ty::Variance::Covariant => ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - ty::AliasRelationDirection::Subtype, - ), - // a :> b is b <: a - ty::Variance::Contravariant => ty::PredicateKind::AliasRelate( - b.into(), - a.into(), - ty::AliasRelationDirection::Subtype, - ), - ty::Variance::Invariant => ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - ty::AliasRelationDirection::Equate, - ), - // FIXME(deferred_projection_equality): Implement this when we trigger it. - // Probably just need to do nothing here. - ty::Variance::Bivariant => { - unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)") - } - })]); - } -} -- cgit 1.4.1-3-g733a5 From b58f647d5488dce73bba517907c44af2c2a618c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Feb 2024 19:04:29 +0100 Subject: rename ptr::invalid -> ptr::without_provenance also introduce ptr::dangling matching NonNull::dangling --- compiler/rustc_arena/src/lib.rs | 2 +- library/alloc/src/rc.rs | 8 +- library/alloc/src/sync.rs | 8 +- library/alloc/tests/fmt.rs | 14 +-- library/alloc/tests/vec.rs | 2 +- library/core/src/alloc/layout.rs | 2 +- library/core/src/intrinsics.rs | 2 +- library/core/src/ptr/const_ptr.rs | 2 +- library/core/src/ptr/mod.rs | 114 +++++++++++++-------- library/core/src/ptr/mut_ptr.rs | 7 +- library/core/src/ptr/non_null.rs | 5 +- library/core/src/slice/iter.rs | 12 ++- library/core/src/sync/atomic.rs | 12 +-- library/core/tests/alloc.rs | 2 +- library/core/tests/hash/mod.rs | 4 +- library/core/tests/ptr.rs | 60 +++++------ library/core/tests/waker.rs | 4 +- library/std/src/backtrace.rs | 2 +- library/std/src/io/error/repr_bitpacked.rs | 10 +- library/std/src/sys/locks/rwlock/queue.rs | 10 +- .../src/sys/pal/common/thread_local/os_local.rs | 2 +- library/std/src/sys/pal/unix/futex.rs | 2 +- .../std/src/sys/pal/unix/thread_parking/netbsd.rs | 13 ++- library/std/src/sys/pal/unix/weak.rs | 6 +- library/std/src/sys/pal/windows/c.rs | 2 +- library/std/src/sys/pal/windows/os.rs | 2 +- .../src/sys/pal/windows/thread_local_key/tests.rs | 4 +- library/std/src/sys/pal/windows/thread_parking.rs | 2 +- library/std/src/sys_common/backtrace.rs | 2 +- library/std/src/sys_common/once/queue.rs | 10 +- .../std/src/sys_common/thread_local_key/tests.rs | 4 +- .../fail/dangling_pointers/deref_dangling_box.rs | 2 +- .../fail/dangling_pointers/deref_dangling_ref.rs | 2 +- .../miri/tests/fail/provenance/ptr_invalid.rs | 4 +- .../tests/fail/provenance/ptr_invalid_offset.rs | 2 +- src/tools/miri/tests/pass-dep/shims/mmap.rs | 8 +- .../miri/tests/pass-dep/shims/posix_memalign.rs | 4 +- src/tools/miri/tests/pass/align_offset_symbolic.rs | 2 +- src/tools/miri/tests/pass/atomic.rs | 6 +- src/tools/miri/tests/pass/ptr_raw.rs | 8 +- src/tools/miri/tests/pass/slices.rs | 6 +- src/tools/miri/tests/pass/underscore_pattern.rs | 4 +- ...e.main.DataflowConstProp.32bit.panic-abort.diff | 18 ++-- ....main.DataflowConstProp.32bit.panic-unwind.diff | 18 ++-- ...e.main.DataflowConstProp.64bit.panic-abort.diff | 18 ++-- ....main.DataflowConstProp.64bit.panic-unwind.diff | 18 ++-- ...ult_boxed_slice.main.GVN.32bit.panic-abort.diff | 18 ++-- ...lt_boxed_slice.main.GVN.32bit.panic-unwind.diff | 18 ++-- ...ult_boxed_slice.main.GVN.64bit.panic-abort.diff | 18 ++-- ...lt_boxed_slice.main.GVN.64bit.panic-unwind.diff | 18 ++-- ...numerated_loop.PreCodegen.after.panic-abort.mir | 2 +- ...umerated_loop.PreCodegen.after.panic-unwind.mir | 2 +- ...r.forward_loop.PreCodegen.after.panic-abort.mir | 2 +- ....forward_loop.PreCodegen.after.panic-unwind.mir | 2 +- ...r.reverse_loop.PreCodegen.after.panic-abort.mir | 2 +- ....reverse_loop.PreCodegen.after.panic-unwind.mir | 2 +- 56 files changed, 303 insertions(+), 232 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 5cb79d9eea5..bdbc59821de 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -95,7 +95,7 @@ impl ArenaChunk { unsafe { if mem::size_of::() == 0 { // A pointer as large as possible for zero-sized elements. - ptr::invalid_mut(!0) + ptr::without_provenance_mut(!0) } else { self.start().add(self.storage.len()) } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 2cc38d90ffe..c3d0019be39 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2804,7 +2804,9 @@ impl Weak { #[must_use] pub const fn new() -> Weak { Weak { - ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::>(usize::MAX)) }, + ptr: unsafe { + NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) + }, alloc: Global, } } @@ -2829,7 +2831,9 @@ impl Weak { #[unstable(feature = "allocator_api", issue = "32838")] pub fn new_in(alloc: A) -> Weak { Weak { - ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::>(usize::MAX)) }, + ptr: unsafe { + NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) + }, alloc, } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index e1211da4c61..524aa35e045 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2555,7 +2555,9 @@ impl Weak { #[must_use] pub const fn new() -> Weak { Weak { - ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::>(usize::MAX)) }, + ptr: unsafe { + NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) + }, alloc: Global, } } @@ -2583,7 +2585,9 @@ impl Weak { #[unstable(feature = "allocator_api", issue = "32838")] pub fn new_in(alloc: A) -> Weak { Weak { - ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::>(usize::MAX)) }, + ptr: unsafe { + NonNull::new_unchecked(ptr::without_provenance_mut::>(usize::MAX)) + }, alloc, } } diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs index 04da95bbb83..379e09ab69a 100644 --- a/library/alloc/tests/fmt.rs +++ b/library/alloc/tests/fmt.rs @@ -77,14 +77,14 @@ fn test_format_macro_interface() { t!(format!("{}", "foo"), "foo"); t!(format!("{}", "foo".to_string()), "foo"); if cfg!(target_pointer_width = "32") { - t!(format!("{:#p}", ptr::invalid::(0x1234)), "0x00001234"); - t!(format!("{:#p}", ptr::invalid_mut::(0x1234)), "0x00001234"); + t!(format!("{:#p}", ptr::without_provenance::(0x1234)), "0x00001234"); + t!(format!("{:#p}", ptr::without_provenance_mut::(0x1234)), "0x00001234"); } else { - t!(format!("{:#p}", ptr::invalid::(0x1234)), "0x0000000000001234"); - t!(format!("{:#p}", ptr::invalid_mut::(0x1234)), "0x0000000000001234"); + t!(format!("{:#p}", ptr::without_provenance::(0x1234)), "0x0000000000001234"); + t!(format!("{:#p}", ptr::without_provenance_mut::(0x1234)), "0x0000000000001234"); } - t!(format!("{:p}", ptr::invalid::(0x1234)), "0x1234"); - t!(format!("{:p}", ptr::invalid_mut::(0x1234)), "0x1234"); + t!(format!("{:p}", ptr::without_provenance::(0x1234)), "0x1234"); + t!(format!("{:p}", ptr::without_provenance_mut::(0x1234)), "0x1234"); t!(format!("{A:x}"), "aloha"); t!(format!("{B:X}"), "adios"); t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); @@ -208,7 +208,7 @@ fn test_format_macro_interface() { { let val = usize::MAX; let exp = format!("{val:#x}"); - t!(format!("{:p}", std::ptr::invalid::(val)), exp); + t!(format!("{:p}", std::ptr::without_provenance::(val)), exp); } // Escaping diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 04bb20e96b7..15ee4d65205 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -2575,7 +2575,7 @@ fn test_box_zero_allocator() { assert!(state.0.insert(addr)); state.1 += 1; std::println!("allocating {addr}"); - std::ptr::invalid_mut(addr) + std::ptr::without_provenance_mut(addr) } else { unsafe { std::alloc::alloc(layout) } }; diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 9ef0a7d7608..2a02870e30b 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -215,7 +215,7 @@ impl Layout { #[inline] pub const fn dangling(&self) -> NonNull { // SAFETY: align is guaranteed to be non-zero - unsafe { NonNull::new_unchecked(crate::ptr::invalid_mut::(self.align())) } + unsafe { NonNull::new_unchecked(crate::ptr::without_provenance_mut::(self.align())) } } /// Creates a layout describing the record that can hold a value diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 4a1187561b3..bec0948c5ed 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1155,7 +1155,7 @@ extern "rust-intrinsic" { /// /// Transmuting pointers *to* integers in a `const` context is [undefined behavior][ub], /// unless the pointer was originally created *from* an integer. - /// (That includes this function specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::invalid], + /// (That includes this function specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling], /// but also semantically-equivalent conversions such as punning through `repr(C)` union fields.) /// Any attempt to use the resulting value for integer operations will abort const-evaluation. /// (And even outside `const`, such transmutation is touching on many unspecified aspects of the diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index c5e3df07a1c..85a56d37ab7 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -181,7 +181,7 @@ impl *const T { /// /// This is similar to `self as usize`, which semantically discards *provenance* and /// *address-space* information. However, unlike `self as usize`, casting the returned address - /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To + /// back to a pointer yields a [pointer without provenance][without_provenance], which is undefined behavior to dereference. To /// properly restore the lost information and obtain a dereferenceable pointer, use /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. /// diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 2bd14f357d8..90b3341f0ad 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -4,13 +4,13 @@ //! //! # Safety //! -//! Many functions in this module take raw pointers as arguments and read from -//! or write to them. For this to be safe, these pointers must be *valid*. -//! Whether a pointer is valid depends on the operation it is used for -//! (read or write), and the extent of the memory that is accessed (i.e., -//! how many bytes are read/written). Most functions use `*mut T` and `*const T` -//! to access only a single value, in which case the documentation omits the size -//! and implicitly assumes it to be `size_of::()` bytes. +//! Many functions in this module take raw pointers as arguments and read from or write to them. For +//! this to be safe, these pointers must be *valid* for the given access. Whether a pointer is valid +//! depends on the operation it is used for (read or write), and the extent of the memory that is +//! accessed (i.e., how many bytes are read/written) -- it makes no sense to ask "is this pointer +//! valid"; one has to ask "is this pointer valid for a given access". Most functions use `*mut T` +//! and `*const T` to access only a single value, in which case the documentation omits the size and +//! implicitly assumes it to be `size_of::()` bytes. //! //! The precise rules for validity are not determined yet. The guarantees that are //! provided at this point are very minimal: @@ -26,7 +26,7 @@ //! some memory happens to exist at that address and gets deallocated. This corresponds to writing //! your own allocator: allocating zero-sized objects is not very hard. The canonical way to //! obtain a pointer that is valid for zero-sized accesses is [`NonNull::dangling`]. -//FIXME: mention `ptr::invalid` above, once it is stable. +//FIXME: mention `ptr::dangling` above, once it is stable. //! * All accesses performed by functions in this module are *non-atomic* in the sense //! of [atomic operations] used to synchronize between threads. This means it is //! undefined behavior to perform two concurrent accesses to the same location from different @@ -44,6 +44,10 @@ //! information, see the [book] as well as the section in the reference devoted //! to [undefined behavior][ub]. //! +//! We say that a pointer is "dangling" if it is not valid for any non-zero-sized accesses. This +//! means out-of-bounds pointers, pointers to freed memory, null pointers, and pointers created with +//! [`NonNull::dangling`] are all dangling. +//! //! ## Alignment //! //! Valid raw pointers as defined above are not necessarily properly aligned (where @@ -167,6 +171,7 @@ //! * The **address-space** it is part of (e.g. "data" vs "code" in WASM). //! * The **address** it points to, which can be represented by a `usize`. //! * The **provenance** it has, defining the memory it has permission to access. +//! Provenance can be absent, in which case the pointer does not have permission to access any memory. //! //! Under Strict Provenance, a usize *cannot* accurately represent a pointer, and converting from //! a pointer to a usize is generally an operation which *only* extracts the address. It is @@ -270,11 +275,12 @@ //! //! But it *is* still sound to: //! -//! * Create an invalid pointer from just an address (see [`ptr::invalid`][]). This can -//! be used for sentinel values like `null` *or* to represent a tagged pointer that will -//! never be dereferenceable. In general, it is always sound for an integer to pretend -//! to be a pointer "for fun" as long as you don't use operations on it which require -//! it to be valid (offset, read, write, etc). +//! * Create a pointer without provenance from just an address (see [`ptr::dangling`][]). Such a +//! pointer cannot be used for memory accesses (except for zero-sized accesses). This can still be +//! useful for sentinel values like `null` *or* to represent a tagged pointer that will never be +//! dereferenceable. In general, it is always sound for an integer to pretend to be a pointer "for +//! fun" as long as you don't use operations on it which require it to be valid (non-zero-sized +//! offset, read, write, etc). //! //! * Forge an allocation of size zero at any sufficiently aligned non-null address. //! i.e. the usual "ZSTs are fake, do what you want" rules apply *but* this only applies @@ -283,7 +289,7 @@ //! that allocation and it will still get invalidated if the allocation gets deallocated. //! In the future we may introduce an API to make such a forged allocation explicit. //! -//! * [`wrapping_offset`][] a pointer outside its provenance. This includes invalid pointers +//! * [`wrapping_offset`][] a pointer outside its provenance. This includes pointers //! which have "no" provenance. Unfortunately there may be practical limits on this for a //! particular platform, and it's an open question as to how to specify this (if at all). //! Notably, [CHERI][] relies on a compression scheme that can't handle a @@ -294,7 +300,7 @@ //! generous (think kilobytes, not bytes). //! //! * Compare arbitrary pointers by address. Addresses *are* just integers and so there is -//! always a coherent answer, even if the pointers are invalid or from different +//! always a coherent answer, even if the pointers are dangling or from different //! address-spaces/provenances. Of course, comparing addresses from different address-spaces //! is generally going to be *meaningless*, but so is comparing Kilograms to Meters, and Rust //! doesn't prevent that either. Similarly, if you get "lucky" and notice that a pointer @@ -367,7 +373,7 @@ //! [`with_addr`]: pointer::with_addr //! [`map_addr`]: pointer::map_addr //! [`addr`]: pointer::addr -//! [`ptr::invalid`]: core::ptr::invalid +//! [`ptr::dangling`]: core::ptr::dangling //! [`expose_addr`]: pointer::expose_addr //! [`from_exposed_addr`]: from_exposed_addr //! [Miri]: https://github.com/rust-lang/miri @@ -537,7 +543,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null"] pub const fn null() -> *const T { - from_raw_parts(invalid(0), ()) + from_raw_parts(without_provenance(0), ()) } /// Creates a null mutable raw pointer. @@ -563,32 +569,26 @@ pub const fn null() -> *const T { #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null_mut"] pub const fn null_mut() -> *mut T { - from_raw_parts_mut(invalid_mut(0), ()) + from_raw_parts_mut(without_provenance_mut(0), ()) } -/// Creates an invalid pointer with the given address. +/// Creates a pointer with the given address and no provenance. +/// +/// Without provenance, this pointer is not associated with any actual allocation. Such a +/// no-provenance pointer may be used for zero-sized memory accesses (if suitably aligned), but +/// non-zero-sized memory accesses with a no-provenance pointer are UB. No-provenance pointers are +/// little more than a usize address in disguise. /// /// This is different from `addr as *const T`, which creates a pointer that picks up a previously /// exposed provenance. See [`from_exposed_addr`] for more details on that operation. /// -/// The module's top-level documentation discusses the precise meaning of an "invalid" -/// pointer but essentially this expresses that the pointer is not associated -/// with any actual allocation and is little more than a usize address in disguise. -/// -/// This pointer will have no provenance associated with it and is therefore -/// UB to read/write/offset. This mostly exists to facilitate things -/// like `ptr::null` and `NonNull::dangling` which make invalid pointers. -/// -/// (Standard "Zero-Sized-Types get to cheat and lie" caveats apply, although it -/// may be desirable to give them their own API just to make that 100% clear.) -/// /// This API and its claimed semantics are part of the Strict Provenance experiment, /// see the [module documentation][crate::ptr] for details. #[inline(always)] #[must_use] #[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] #[unstable(feature = "strict_provenance", issue = "95228")] -pub const fn invalid(addr: usize) -> *const T { +pub const fn without_provenance(addr: usize) -> *const T { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // We use transmute rather than a cast so tools like Miri can tell that this // is *not* the same as from_exposed_addr. @@ -597,21 +597,32 @@ pub const fn invalid(addr: usize) -> *const T { unsafe { mem::transmute(addr) } } -/// Creates an invalid mutable pointer with the given address. +/// Creates a new pointer that is dangling, but well-aligned. /// -/// This is different from `addr as *mut T`, which creates a pointer that picks up a previously -/// exposed provenance. See [`from_exposed_addr_mut`] for more details on that operation. +/// This is useful for initializing types which lazily allocate, like +/// `Vec::new` does. /// -/// The module's top-level documentation discusses the precise meaning of an "invalid" -/// pointer but essentially this expresses that the pointer is not associated -/// with any actual allocation and is little more than a usize address in disguise. +/// Note that the pointer value may potentially represent a valid pointer to +/// a `T`, which means this must not be used as a "not yet initialized" +/// sentinel value. Types that lazily allocate must track initialization by +/// some other means. +#[inline(always)] +#[must_use] +#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] +#[unstable(feature = "strict_provenance", issue = "95228")] +pub const fn dangling() -> *const T { + without_provenance(mem::align_of::()) +} + +/// Creates a pointer with the given address and no provenance. /// -/// This pointer will have no provenance associated with it and is therefore -/// UB to read/write/offset. This mostly exists to facilitate things -/// like `ptr::null` and `NonNull::dangling` which make invalid pointers. +/// Without provenance, this pointer is not associated with any actual allocation. Such a +/// no-provenance pointer may be used for zero-sized memory accesses (if suitably aligned), but +/// non-zero-sized memory accesses with a no-provenance pointer are UB. No-provenance pointers are +/// little more than a usize address in disguise. /// -/// (Standard "Zero-Sized-Types get to cheat and lie" caveats apply, although it -/// may be desirable to give them their own API just to make that 100% clear.) +/// This is different from `addr as *mut T`, which creates a pointer that picks up a previously +/// exposed provenance. See [`from_exposed_addr_mut`] for more details on that operation. /// /// This API and its claimed semantics are part of the Strict Provenance experiment, /// see the [module documentation][crate::ptr] for details. @@ -619,7 +630,7 @@ pub const fn invalid(addr: usize) -> *const T { #[must_use] #[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] #[unstable(feature = "strict_provenance", issue = "95228")] -pub const fn invalid_mut(addr: usize) -> *mut T { +pub const fn without_provenance_mut(addr: usize) -> *mut T { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // We use transmute rather than a cast so tools like Miri can tell that this // is *not* the same as from_exposed_addr. @@ -628,6 +639,23 @@ pub const fn invalid_mut(addr: usize) -> *mut T { unsafe { mem::transmute(addr) } } +/// Creates a new pointer that is dangling, but well-aligned. +/// +/// This is useful for initializing types which lazily allocate, like +/// `Vec::new` does. +/// +/// Note that the pointer value may potentially represent a valid pointer to +/// a `T`, which means this must not be used as a "not yet initialized" +/// sentinel value. Types that lazily allocate must track initialization by +/// some other means. +#[inline(always)] +#[must_use] +#[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] +#[unstable(feature = "strict_provenance", issue = "95228")] +pub const fn dangling_mut() -> *mut T { + without_provenance_mut(mem::align_of::()) +} + /// Convert an address back to a pointer, picking up a previously 'exposed' provenance. /// /// This is a more rigorously specified alternative to `addr as *const T`. The provenance of the diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 376673d67c1..28ba26f5c16 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -188,9 +188,10 @@ impl *mut T { /// /// This is similar to `self as usize`, which semantically discards *provenance* and /// *address-space* information. However, unlike `self as usize`, casting the returned address - /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To - /// properly restore the lost information and obtain a dereferenceable pointer, use - /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. + /// back to a pointer yields yields a [pointer without provenance][without_provenance_mut], which is undefined + /// behavior to dereference. To properly restore the lost information and obtain a + /// dereferenceable pointer, use [`with_addr`][pointer::with_addr] or + /// [`map_addr`][pointer::map_addr]. /// /// If using those APIs is not possible because there is no way to preserve a pointer with the /// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 16e90343993..098ec233855 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -4,8 +4,7 @@ use crate::hash; use crate::intrinsics; use crate::intrinsics::assert_unsafe_precondition; use crate::marker::Unsize; -use crate::mem::SizedTypeProperties; -use crate::mem::{self, MaybeUninit}; +use crate::mem::{MaybeUninit, SizedTypeProperties}; use crate::num::{NonZero, NonZeroUsize}; use crate::ops::{CoerceUnsized, DispatchFromDyn}; use crate::ptr; @@ -114,7 +113,7 @@ impl NonNull { // to a *mut T. Therefore, `ptr` is not null and the conditions for // calling new_unchecked() are respected. unsafe { - let ptr = crate::ptr::invalid_mut::(mem::align_of::()); + let ptr = crate::ptr::dangling_mut::(); NonNull::new_unchecked(ptr) } } diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 617b385a960..d7d4f90c1a5 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -12,7 +12,7 @@ use crate::iter::{ use crate::marker::PhantomData; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZero; -use crate::ptr::{self, invalid, invalid_mut, NonNull}; +use crate::ptr::{self, without_provenance, without_provenance_mut, NonNull}; use super::{from_raw_parts, from_raw_parts_mut}; @@ -67,7 +67,7 @@ pub struct Iter<'a, T: 'a> { ptr: NonNull, /// For non-ZSTs, the non-null pointer to the past-the-end element. /// - /// For ZSTs, this is `ptr::invalid(len)`. + /// For ZSTs, this is `ptr::dangling(len)`. end_or_len: *const T, _marker: PhantomData<&'a T>, } @@ -91,7 +91,8 @@ impl<'a, T> Iter<'a, T> { let ptr: NonNull = NonNull::from(slice).cast(); // SAFETY: Similar to `IterMut::new`. unsafe { - let end_or_len = if T::IS_ZST { invalid(len) } else { ptr.as_ptr().add(len) }; + let end_or_len = + if T::IS_ZST { without_provenance(len) } else { ptr.as_ptr().add(len) }; Self { ptr, end_or_len, _marker: PhantomData } } @@ -189,7 +190,7 @@ pub struct IterMut<'a, T: 'a> { ptr: NonNull, /// For non-ZSTs, the non-null pointer to the past-the-end element. /// - /// For ZSTs, this is `ptr::invalid_mut(len)`. + /// For ZSTs, this is `ptr::without_provenance_mut(len)`. end_or_len: *mut T, _marker: PhantomData<&'a mut T>, } @@ -228,7 +229,8 @@ impl<'a, T> IterMut<'a, T> { // See the `next_unchecked!` and `is_empty!` macros as well as the // `post_inc_start` method for more information. unsafe { - let end_or_len = if T::IS_ZST { invalid_mut(len) } else { ptr.as_ptr().add(len) }; + let end_or_len = + if T::IS_ZST { without_provenance_mut(len) } else { ptr.as_ptr().add(len) }; Self { ptr, end_or_len, _marker: PhantomData } } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index e9a0d9e1d28..45193c11e1d 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1842,7 +1842,7 @@ impl AtomicPtr { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_add(self.p.get(), core::ptr::invalid_mut(val), order).cast() } + unsafe { atomic_add(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() } } /// Offsets the pointer's address by subtracting `val` *bytes*, returning the @@ -1867,7 +1867,7 @@ impl AtomicPtr { /// #![feature(strict_provenance_atomic_ptr, strict_provenance)] /// use core::sync::atomic::{AtomicPtr, Ordering}; /// - /// let atom = AtomicPtr::::new(core::ptr::invalid_mut(1)); + /// let atom = AtomicPtr::::new(core::ptr::without_provenance_mut(1)); /// assert_eq!(atom.fetch_byte_sub(1, Ordering::Relaxed).addr(), 1); /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 0); /// ``` @@ -1877,7 +1877,7 @@ impl AtomicPtr { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_sub(self.p.get(), core::ptr::invalid_mut(val), order).cast() } + unsafe { atomic_sub(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() } } /// Performs a bitwise "or" operation on the address of the current pointer, @@ -1928,7 +1928,7 @@ impl AtomicPtr { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_or(self.p.get(), core::ptr::invalid_mut(val), order).cast() } + unsafe { atomic_or(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() } } /// Performs a bitwise "and" operation on the address of the current @@ -1978,7 +1978,7 @@ impl AtomicPtr { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_and(self.p.get(), core::ptr::invalid_mut(val), order).cast() } + unsafe { atomic_and(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() } } /// Performs a bitwise "xor" operation on the address of the current @@ -2026,7 +2026,7 @@ impl AtomicPtr { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T { // SAFETY: data races are prevented by atomic intrinsics. - unsafe { atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast() } + unsafe { atomic_xor(self.p.get(), core::ptr::without_provenance_mut(val), order).cast() } } /// Returns a mutable pointer to the underlying pointer. diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs index 3ceaeadcec6..b88f1821cd7 100644 --- a/library/core/tests/alloc.rs +++ b/library/core/tests/alloc.rs @@ -10,7 +10,7 @@ fn const_unchecked_layout() { const DANGLING: NonNull = LAYOUT.dangling(); assert_eq!(LAYOUT.size(), SIZE); assert_eq!(LAYOUT.align(), ALIGN); - assert_eq!(Some(DANGLING), NonNull::new(ptr::invalid_mut(ALIGN))); + assert_eq!(Some(DANGLING), NonNull::new(ptr::without_provenance_mut(ALIGN))); } #[test] diff --git a/library/core/tests/hash/mod.rs b/library/core/tests/hash/mod.rs index 3b9351457a9..bdd1c2579de 100644 --- a/library/core/tests/hash/mod.rs +++ b/library/core/tests/hash/mod.rs @@ -87,10 +87,10 @@ fn test_writer_hasher() { let cs: Rc<[u8]> = Rc::new([1, 2, 3]); assert_eq!(hash(&cs), 9); - let ptr = ptr::invalid::(5_usize); + let ptr = ptr::without_provenance::(5_usize); assert_eq!(hash(&ptr), 5); - let ptr = ptr::invalid_mut::(5_usize); + let ptr = ptr::without_provenance_mut::(5_usize); assert_eq!(hash(&ptr), 5); if cfg!(miri) { diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index b3f7dfa1fb9..659fbd255c1 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -350,9 +350,9 @@ fn align_offset_zst() { // all, because no amount of elements will align the pointer. let mut p = 1; while p < 1024 { - assert_eq!(ptr::invalid::<()>(p).align_offset(p), 0); + assert_eq!(ptr::without_provenance::<()>(p).align_offset(p), 0); if p != 1 { - assert_eq!(ptr::invalid::<()>(p + 1).align_offset(p), !0); + assert_eq!(ptr::without_provenance::<()>(p + 1).align_offset(p), !0); } p = (p + 1).next_power_of_two(); } @@ -365,9 +365,9 @@ fn align_offset_zst_const() { // all, because no amount of elements will align the pointer. let mut p = 1; while p < 1024 { - assert!(ptr::invalid::<()>(p).align_offset(p) == 0); + assert!(ptr::without_provenance::<()>(p).align_offset(p) == 0); if p != 1 { - assert!(ptr::invalid::<()>(p + 1).align_offset(p) == !0); + assert!(ptr::without_provenance::<()>(p + 1).align_offset(p) == !0); } p = (p + 1).next_power_of_two(); } @@ -384,7 +384,7 @@ fn align_offset_stride_one() { let expected = ptr % align; let offset = if expected == 0 { 0 } else { align - expected }; assert_eq!( - ptr::invalid::(ptr).align_offset(align), + ptr::without_provenance::(ptr).align_offset(align), offset, "ptr = {}, align = {}, size = 1", ptr, @@ -406,7 +406,7 @@ fn align_offset_stride_one_const() { while ptr < 2 * align { let expected = ptr % align; let offset = if expected == 0 { 0 } else { align - expected }; - assert!(ptr::invalid::(ptr).align_offset(align) == offset); + assert!(ptr::without_provenance::(ptr).align_offset(align) == offset); ptr += 1; } align = (align + 1).next_power_of_two(); @@ -452,30 +452,30 @@ fn align_offset_various_strides() { unsafe { #[repr(packed)] struct A3(#[allow(dead_code)] u16, #[allow(dead_code)] u8); - x |= test_stride::(ptr::invalid::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); struct A4(#[allow(dead_code)] u32); - x |= test_stride::(ptr::invalid::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); #[repr(packed)] struct A5(#[allow(dead_code)] u32, #[allow(dead_code)] u8); - x |= test_stride::(ptr::invalid::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); #[repr(packed)] struct A6(#[allow(dead_code)] u32, #[allow(dead_code)] u16); - x |= test_stride::(ptr::invalid::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); #[repr(packed)] struct A7(#[allow(dead_code)] u32, #[allow(dead_code)] u16, #[allow(dead_code)] u8); - x |= test_stride::(ptr::invalid::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); #[repr(packed)] struct A8(#[allow(dead_code)] u32, #[allow(dead_code)] u32); - x |= test_stride::(ptr::invalid::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); #[repr(packed)] struct A9(#[allow(dead_code)] u32, #[allow(dead_code)] u32, #[allow(dead_code)] u8); - x |= test_stride::(ptr::invalid::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); #[repr(packed)] struct A10( @@ -483,10 +483,10 @@ fn align_offset_various_strides() { #[allow(dead_code)] u32, #[allow(dead_code)] u16, ); - x |= test_stride::(ptr::invalid::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); - x |= test_stride::(ptr::invalid::(ptr), align); - x |= test_stride::(ptr::invalid::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); + x |= test_stride::(ptr::without_provenance::(ptr), align); } } align = (align + 1).next_power_of_two(); @@ -522,18 +522,18 @@ fn align_offset_various_strides_const() { unsafe { #[repr(packed)] struct A3(#[allow(dead_code)] u16, #[allow(dead_code)] u8); - test_stride::(ptr::invalid::(ptr), ptr, align); + test_stride::(ptr::without_provenance::(ptr), ptr, align); struct A4(#[allow(dead_code)] u32); - test_stride::(ptr::invalid::(ptr), ptr, align); + test_stride::(ptr::without_provenance::(ptr), ptr, align); #[repr(packed)] struct A5(#[allow(dead_code)] u32, #[allow(dead_code)] u8); - test_stride::(ptr::invalid::(ptr), ptr, align); + test_stride::(ptr::without_provenance::(ptr), ptr, align); #[repr(packed)] struct A6(#[allow(dead_code)] u32, #[allow(dead_code)] u16); - test_stride::(ptr::invalid::(ptr), ptr, align); + test_stride::(ptr::without_provenance::(ptr), ptr, align); #[repr(packed)] struct A7( @@ -541,11 +541,11 @@ fn align_offset_various_strides_const() { #[allow(dead_code)] u16, #[allow(dead_code)] u8, ); - test_stride::(ptr::invalid::(ptr), ptr, align); + test_stride::(ptr::without_provenance::(ptr), ptr, align); #[repr(packed)] struct A8(#[allow(dead_code)] u32, #[allow(dead_code)] u32); - test_stride::(ptr::invalid::(ptr), ptr, align); + test_stride::(ptr::without_provenance::(ptr), ptr, align); #[repr(packed)] struct A9( @@ -553,7 +553,7 @@ fn align_offset_various_strides_const() { #[allow(dead_code)] u32, #[allow(dead_code)] u8, ); - test_stride::(ptr::invalid::(ptr), ptr, align); + test_stride::(ptr::without_provenance::(ptr), ptr, align); #[repr(packed)] struct A10( @@ -561,10 +561,10 @@ fn align_offset_various_strides_const() { #[allow(dead_code)] u32, #[allow(dead_code)] u16, ); - test_stride::(ptr::invalid::(ptr), ptr, align); + test_stride::(ptr::without_provenance::(ptr), ptr, align); - test_stride::(ptr::invalid::(ptr), ptr, align); - test_stride::(ptr::invalid::(ptr), ptr, align); + test_stride::(ptr::without_provenance::(ptr), ptr, align); + test_stride::(ptr::without_provenance::(ptr), ptr, align); } ptr += 1; } @@ -689,7 +689,7 @@ fn align_offset_issue_103361() { #[cfg(target_pointer_width = "16")] const SIZE: usize = 1 << 13; struct HugeSize(#[allow(dead_code)] [u8; SIZE - 1]); - let _ = ptr::invalid::(SIZE).align_offset(SIZE); + let _ = ptr::without_provenance::(SIZE).align_offset(SIZE); } #[test] @@ -703,9 +703,9 @@ fn align_offset_issue_103361_const() { struct HugeSize(#[allow(dead_code)] [u8; SIZE - 1]); const { - assert!(ptr::invalid::(SIZE - 1).align_offset(SIZE) == SIZE - 1); - assert!(ptr::invalid::(SIZE).align_offset(SIZE) == 0); - assert!(ptr::invalid::(SIZE + 1).align_offset(SIZE) == 1); + assert!(ptr::without_provenance::(SIZE - 1).align_offset(SIZE) == SIZE - 1); + assert!(ptr::without_provenance::(SIZE).align_offset(SIZE) == 0); + assert!(ptr::without_provenance::(SIZE + 1).align_offset(SIZE) == 1); } } diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs index 38a3a0adad9..2c66e0d7ad3 100644 --- a/library/core/tests/waker.rs +++ b/library/core/tests/waker.rs @@ -3,7 +3,7 @@ use std::task::{RawWaker, RawWakerVTable, Waker}; #[test] fn test_waker_getters() { - let raw_waker = RawWaker::new(ptr::invalid_mut(42usize), &WAKER_VTABLE); + let raw_waker = RawWaker::new(ptr::without_provenance_mut(42usize), &WAKER_VTABLE); assert_eq!(raw_waker.data() as usize, 42); assert!(ptr::eq(raw_waker.vtable(), &WAKER_VTABLE)); @@ -15,7 +15,7 @@ fn test_waker_getters() { } static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( - |data| RawWaker::new(ptr::invalid_mut(data as usize + 1), &WAKER_VTABLE), + |data| RawWaker::new(ptr::without_provenance_mut(data as usize + 1), &WAKER_VTABLE), |_| {}, |_| {}, |_| {}, diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 835e35eac34..475b3e7eb93 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -467,7 +467,7 @@ impl RawFrame { match self { RawFrame::Actual(frame) => frame.ip(), #[cfg(test)] - RawFrame::Fake => crate::ptr::invalid_mut(1), + RawFrame::Fake => crate::ptr::without_provenance_mut(1), } } } diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index db175659770..c053e047b1a 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -174,7 +174,10 @@ impl Repr { pub(super) fn new_os(code: RawOsError) -> Self { let utagged = ((code as usize) << 32) | TAG_OS; // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0. - let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData); + let res = Self( + unsafe { NonNull::new_unchecked(ptr::without_provenance_mut(utagged)) }, + PhantomData, + ); // quickly smoke-check we encoded the right thing (This generally will // only run in std's tests, unless the user uses -Zbuild-std) debug_assert!( @@ -188,7 +191,10 @@ impl Repr { pub(super) fn new_simple(kind: ErrorKind) -> Self { let utagged = ((kind as usize) << 32) | TAG_SIMPLE; // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0. - let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData); + let res = Self( + unsafe { NonNull::new_unchecked(ptr::without_provenance_mut(utagged)) }, + PhantomData, + ); // quickly smoke-check we encoded the right thing (This generally will // only run in std's tests, unless the user uses -Zbuild-std) debug_assert!( diff --git a/library/std/src/sys/locks/rwlock/queue.rs b/library/std/src/sys/locks/rwlock/queue.rs index 0f02a98dfdd..dce966086b8 100644 --- a/library/std/src/sys/locks/rwlock/queue.rs +++ b/library/std/src/sys/locks/rwlock/queue.rs @@ -110,7 +110,7 @@ use crate::cell::OnceCell; use crate::hint::spin_loop; use crate::mem; -use crate::ptr::{self, invalid_mut, null_mut, NonNull}; +use crate::ptr::{self, null_mut, without_provenance_mut, NonNull}; use crate::sync::atomic::{ AtomicBool, AtomicPtr, Ordering::{AcqRel, Acquire, Relaxed, Release}, @@ -126,7 +126,7 @@ const SPIN_COUNT: usize = 7; type State = *mut (); type AtomicState = AtomicPtr<()>; -const UNLOCKED: State = invalid_mut(0); +const UNLOCKED: State = without_provenance_mut(0); const LOCKED: usize = 1; const QUEUED: usize = 2; const QUEUE_LOCKED: usize = 4; @@ -144,7 +144,7 @@ fn write_lock(state: State) -> Option { #[inline] fn read_lock(state: State) -> Option { if state.addr() & QUEUED == 0 && state.addr() != LOCKED { - Some(invalid_mut(state.addr().checked_add(SINGLE)? | LOCKED)) + Some(without_provenance_mut(state.addr().checked_add(SINGLE)? | LOCKED)) } else { None } @@ -405,7 +405,7 @@ impl RwLock { match self.state.fetch_update(Release, Acquire, |state| { if state.addr() & QUEUED == 0 { let count = state.addr() - (SINGLE | LOCKED); - Some(if count > 0 { invalid_mut(count | LOCKED) } else { UNLOCKED }) + Some(if count > 0 { without_provenance_mut(count | LOCKED) } else { UNLOCKED }) } else { None } @@ -444,7 +444,7 @@ impl RwLock { #[inline] pub unsafe fn write_unlock(&self) { if let Err(state) = - self.state.compare_exchange(invalid_mut(LOCKED), UNLOCKED, Release, Relaxed) + self.state.compare_exchange(without_provenance_mut(LOCKED), UNLOCKED, Release, Relaxed) { // SAFETY: // Since other threads cannot acquire the lock, the state can only diff --git a/library/std/src/sys/pal/common/thread_local/os_local.rs b/library/std/src/sys/pal/common/thread_local/os_local.rs index 7cf29192122..3edffd7e443 100644 --- a/library/std/src/sys/pal/common/thread_local/os_local.rs +++ b/library/std/src/sys/pal/common/thread_local/os_local.rs @@ -176,7 +176,7 @@ unsafe extern "C" fn destroy_value(ptr: *mut u8) { if let Err(_) = panic::catch_unwind(|| unsafe { let ptr = Box::from_raw(ptr as *mut Value); let key = ptr.key; - key.os.set(ptr::invalid_mut(1)); + key.os.set(ptr::without_provenance_mut(1)); drop(ptr); key.os.set(ptr::null_mut()); }) { diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs index d310be6c7a1..26161a9af79 100644 --- a/library/std/src/sys/pal/unix/futex.rs +++ b/library/std/src/sys/pal/unix/futex.rs @@ -53,7 +53,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) - futex as *const AtomicU32 as *mut _, libc::UMTX_OP_WAIT_UINT_PRIVATE, expected as libc::c_ulong, - crate::ptr::invalid_mut(umtx_timeout_size), + crate::ptr::without_provenance_mut(umtx_timeout_size), umtx_timeout_ptr as *mut _, ) } else if #[cfg(any(target_os = "linux", target_os = "android"))] { diff --git a/library/std/src/sys/pal/unix/thread_parking/netbsd.rs b/library/std/src/sys/pal/unix/thread_parking/netbsd.rs index 3be08122138..5eeb37f8763 100644 --- a/library/std/src/sys/pal/unix/thread_parking/netbsd.rs +++ b/library/std/src/sys/pal/unix/thread_parking/netbsd.rs @@ -25,7 +25,7 @@ pub fn current() -> ThreadId { #[inline] pub fn park(hint: usize) { unsafe { - ___lwp_park60(0, 0, ptr::null_mut(), 0, ptr::invalid(hint), ptr::null()); + ___lwp_park60(0, 0, ptr::null_mut(), 0, ptr::without_provenance(hint), ptr::null()); } } @@ -40,13 +40,20 @@ pub fn park_timeout(dur: Duration, hint: usize) { // Timeout needs to be mutable since it is modified on NetBSD 9.0 and // above. unsafe { - ___lwp_park60(CLOCK_MONOTONIC, 0, &mut timeout, 0, ptr::invalid(hint), ptr::null()); + ___lwp_park60( + CLOCK_MONOTONIC, + 0, + &mut timeout, + 0, + ptr::without_provenance(hint), + ptr::null(), + ); } } #[inline] pub fn unpark(tid: ThreadId, hint: usize) { unsafe { - _lwp_unpark(tid, ptr::invalid(hint)); + _lwp_unpark(tid, ptr::without_provenance(hint)); } } diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs index 61088ff16ed..48cc8633e93 100644 --- a/library/std/src/sys/pal/unix/weak.rs +++ b/library/std/src/sys/pal/unix/weak.rs @@ -80,7 +80,11 @@ pub(crate) struct DlsymWeak { impl DlsymWeak { pub(crate) const fn new(name: &'static str) -> Self { - DlsymWeak { name, func: AtomicPtr::new(ptr::invalid_mut(1)), _marker: PhantomData } + DlsymWeak { + name, + func: AtomicPtr::new(ptr::without_provenance_mut(1)), + _marker: PhantomData, + } } #[inline] diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 1a59ac9a9ca..6b12d7db8b0 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -47,7 +47,7 @@ pub use FD_SET as fd_set; pub use LINGER as linger; pub use TIMEVAL as timeval; -pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::invalid_mut(-1i32 as _); +pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::without_provenance_mut(-1i32 as _); // https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170 pub const EXIT_SUCCESS: u32 = 0; diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 73cb2db8b79..374c9845ea4 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -327,7 +327,7 @@ fn home_dir_crt() -> Option { super::fill_utf16_buf( |buf, mut sz| { match c::GetUserProfileDirectoryW( - ptr::invalid_mut(CURRENT_PROCESS_TOKEN), + ptr::without_provenance_mut(CURRENT_PROCESS_TOKEN), buf, &mut sz, ) { diff --git a/library/std/src/sys/pal/windows/thread_local_key/tests.rs b/library/std/src/sys/pal/windows/thread_local_key/tests.rs index c739f0caf3e..4119f990968 100644 --- a/library/std/src/sys/pal/windows/thread_local_key/tests.rs +++ b/library/std/src/sys/pal/windows/thread_local_key/tests.rs @@ -13,8 +13,8 @@ fn smoke() { unsafe { assert!(K1.get().is_null()); assert!(K2.get().is_null()); - K1.set(ptr::invalid_mut(1)); - K2.set(ptr::invalid_mut(2)); + K1.set(ptr::without_provenance_mut(1)); + K2.set(ptr::without_provenance_mut(2)); assert_eq!(K1.get() as usize, 1); assert_eq!(K2.get() as usize, 2); } diff --git a/library/std/src/sys/pal/windows/thread_parking.rs b/library/std/src/sys/pal/windows/thread_parking.rs index eb9167cd855..343b530b15e 100644 --- a/library/std/src/sys/pal/windows/thread_parking.rs +++ b/library/std/src/sys/pal/windows/thread_parking.rs @@ -220,7 +220,7 @@ impl Parker { } fn keyed_event_handle() -> c::HANDLE { - const INVALID: c::HANDLE = ptr::invalid_mut(!0); + const INVALID: c::HANDLE = ptr::without_provenance_mut(!0); static HANDLE: AtomicPtr = AtomicPtr::new(INVALID); match HANDLE.load(Relaxed) { INVALID => { diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index adfe721cfa9..67711dbd5bc 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -218,7 +218,7 @@ pub fn output_filename( #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] pub fn set_image_base() { let image_base = crate::os::fortanix_sgx::mem::image_base(); - backtrace_rs::set_image_base(crate::ptr::invalid_mut(image_base as _)); + backtrace_rs::set_image_base(crate::ptr::without_provenance_mut(image_base as _)); } #[cfg(not(all(target_vendor = "fortanix", target_env = "sgx")))] diff --git a/library/std/src/sys_common/once/queue.rs b/library/std/src/sys_common/once/queue.rs index def0bcd6fac..3cc1df113e3 100644 --- a/library/std/src/sys_common/once/queue.rs +++ b/library/std/src/sys_common/once/queue.rs @@ -110,7 +110,7 @@ impl Once { #[inline] #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")] pub const fn new() -> Once { - Once { state_and_queue: AtomicPtr::new(ptr::invalid_mut(INCOMPLETE)) } + Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(INCOMPLETE)) } } #[inline] @@ -158,7 +158,7 @@ impl Once { // Try to register this thread as the one RUNNING. let exchange_result = self.state_and_queue.compare_exchange( state_and_queue, - ptr::invalid_mut(RUNNING), + ptr::without_provenance_mut(RUNNING), Ordering::Acquire, Ordering::Acquire, ); @@ -170,14 +170,14 @@ impl Once { // wake them up on drop. let mut waiter_queue = WaiterQueue { state_and_queue: &self.state_and_queue, - set_state_on_drop_to: ptr::invalid_mut(POISONED), + set_state_on_drop_to: ptr::without_provenance_mut(POISONED), }; // Run the initialization function, letting it know if we're // poisoned or not. let init_state = public::OnceState { inner: OnceState { poisoned: state_and_queue.addr() == POISONED, - set_state_on_drop_to: Cell::new(ptr::invalid_mut(COMPLETE)), + set_state_on_drop_to: Cell::new(ptr::without_provenance_mut(COMPLETE)), }, }; init(&init_state); @@ -289,6 +289,6 @@ impl OnceState { #[inline] pub fn poison(&self) { - self.set_state_on_drop_to.set(ptr::invalid_mut(POISONED)); + self.set_state_on_drop_to.set(ptr::without_provenance_mut(POISONED)); } } diff --git a/library/std/src/sys_common/thread_local_key/tests.rs b/library/std/src/sys_common/thread_local_key/tests.rs index 6a44c65d918..48bed31af51 100644 --- a/library/std/src/sys_common/thread_local_key/tests.rs +++ b/library/std/src/sys_common/thread_local_key/tests.rs @@ -9,8 +9,8 @@ fn statik() { unsafe { assert!(K1.get().is_null()); assert!(K2.get().is_null()); - K1.set(ptr::invalid_mut(1)); - K2.set(ptr::invalid_mut(2)); + K1.set(ptr::without_provenance_mut(1)); + K2.set(ptr::without_provenance_mut(2)); assert_eq!(K1.get() as usize, 1); assert_eq!(K2.get() as usize, 2); } diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.rs b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.rs index d2823672ade..fa40f942b8f 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.rs @@ -8,7 +8,7 @@ use std::ptr::{self, addr_of_mut}; // (This test relies on the `deref_copy` pass that lowers `**ptr` to materialize the intermediate pointer.) fn main() { - let mut inner = ptr::invalid::(24); + let mut inner = ptr::without_provenance::(24); let outer = addr_of_mut!(inner).cast::>(); // Now `outer` is a pointer to a dangling reference. // Deref'ing that should be UB. diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.rs b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.rs index b62e041d70c..036ef2580a8 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.rs @@ -8,7 +8,7 @@ use std::ptr::{self, addr_of_mut}; // (This test relies on the `deref_copy` pass that lowers `**ptr` to materialize the intermediate pointer.) fn main() { - let mut inner = ptr::invalid::(24); + let mut inner = ptr::without_provenance::(24); let outer = addr_of_mut!(inner).cast::<&'static mut i32>(); // Now `outer` is a pointer to a dangling reference. // Deref'ing that should be UB. diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs index 5d44928d1d2..730859684a0 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs @@ -1,9 +1,9 @@ #![feature(strict_provenance, exposed_provenance)] -// Ensure that a `ptr::invalid` ptr is truly invalid. +// Ensure that a `ptr::without_provenance` ptr is truly invalid. fn main() { let x = 42; let xptr = &x as *const i32; - let xptr_invalid = std::ptr::invalid::(xptr.expose_addr()); + let xptr_invalid = std::ptr::without_provenance::(xptr.expose_addr()); let _val = unsafe { *xptr_invalid }; //~ ERROR: is a dangling pointer } diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.rs b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.rs index 91ba18f7680..c8be521ef82 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.rs +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.rs @@ -4,7 +4,7 @@ fn main() { let x = 22; let ptr = &x as *const _ as *const u8; - let roundtrip = std::ptr::invalid::(ptr as usize); + let roundtrip = std::ptr::without_provenance::(ptr as usize); // Not even offsetting this is allowed. let _ = unsafe { roundtrip.offset(1) }; //~ERROR: is a dangling pointer } diff --git a/src/tools/miri/tests/pass-dep/shims/mmap.rs b/src/tools/miri/tests/pass-dep/shims/mmap.rs index 7bbb9dd53cb..0cbe8d94294 100644 --- a/src/tools/miri/tests/pass-dep/shims/mmap.rs +++ b/src/tools/miri/tests/pass-dep/shims/mmap.rs @@ -71,7 +71,7 @@ fn test_mmap( let ptr = unsafe { mmap( - ptr::invalid_mut(page_size * 64), + ptr::without_provenance_mut(page_size * 64), page_size, libc::PROT_READ | libc::PROT_WRITE, // We don't support MAP_FIXED @@ -114,13 +114,13 @@ fn test_mmap( assert_eq!(ptr, libc::MAP_FAILED); // We report an error when trying to munmap an address which is not a multiple of the page size - let res = unsafe { libc::munmap(ptr::invalid_mut(1), page_size) }; + let res = unsafe { libc::munmap(ptr::without_provenance_mut(1), page_size) }; assert_eq!(res, -1); assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL); // We report an error when trying to munmap a length that cannot be rounded up to a multiple of // the page size. - let res = unsafe { libc::munmap(ptr::invalid_mut(page_size), usize::MAX - 1) }; + let res = unsafe { libc::munmap(ptr::without_provenance_mut(page_size), usize::MAX - 1) }; assert_eq!(res, -1); assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL); } @@ -156,7 +156,7 @@ fn test_mremap() { // Test all of our error conditions // Not aligned let ptr = - unsafe { libc::mremap(ptr::invalid_mut(1), page_size, page_size, libc::MREMAP_MAYMOVE) }; + unsafe { libc::mremap(ptr::without_provenance_mut(1), page_size, page_size, libc::MREMAP_MAYMOVE) }; assert_eq!(ptr, libc::MAP_FAILED); assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL); diff --git a/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs b/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs index 9bd8a00d68d..5cf62995fbe 100644 --- a/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs +++ b/src/tools/miri/tests/pass-dep/shims/posix_memalign.rs @@ -58,7 +58,7 @@ fn main() { // Non-power of 2 align unsafe { - let mut ptr: *mut libc::c_void = ptr::invalid_mut(0x1234567); + let mut ptr: *mut libc::c_void = ptr::without_provenance_mut(0x1234567); let align = 15; let size = 8; assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL); @@ -70,7 +70,7 @@ fn main() { // Too small align (smaller than ptr) unsafe { - let mut ptr: *mut libc::c_void = ptr::invalid_mut(0x1234567); + let mut ptr: *mut libc::c_void = ptr::without_provenance_mut(0x1234567); let align = std::mem::size_of::() / 2; let size = 8; assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL); diff --git a/src/tools/miri/tests/pass/align_offset_symbolic.rs b/src/tools/miri/tests/pass/align_offset_symbolic.rs index ac28c63e081..c32fa2c8f9b 100644 --- a/src/tools/miri/tests/pass/align_offset_symbolic.rs +++ b/src/tools/miri/tests/pass/align_offset_symbolic.rs @@ -100,7 +100,7 @@ fn huge_align() { #[cfg(target_pointer_width = "16")] const SIZE: usize = 1 << 13; struct HugeSize(#[allow(dead_code)] [u8; SIZE - 1]); - let _ = std::ptr::invalid::(SIZE).align_offset(SIZE); + let _ = std::ptr::without_provenance::(SIZE).align_offset(SIZE); } // This shows that we cannot store the promised alignment info in `AllocExtra`, diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs index 60b8ff87b59..dfdc9b42f81 100644 --- a/src/tools/miri/tests/pass/atomic.rs +++ b/src/tools/miri/tests/pass/atomic.rs @@ -137,7 +137,7 @@ fn atomic_ptr() { let ptr = AtomicPtr::::new(ptr::null_mut()); assert!(ptr.load(Relaxed).addr() == 0); - ptr.store(ptr::invalid_mut(13), SeqCst); + ptr.store(ptr::without_provenance_mut(13), SeqCst); assert!(ptr.swap(x, Relaxed).addr() == 13); unsafe { assert!(*ptr.load(Acquire) == 0) }; @@ -145,7 +145,7 @@ fn atomic_ptr() { assert_eq!( ptr.compare_exchange( (&mut 0 as *mut i32).with_addr(x.addr()), - ptr::invalid_mut(0), + ptr::without_provenance_mut(0), SeqCst, SeqCst ) @@ -156,7 +156,7 @@ fn atomic_ptr() { assert_eq!( ptr.compare_exchange( (&mut 0 as *mut i32).with_addr(x.addr()), - ptr::invalid_mut(0), + ptr::without_provenance_mut(0), SeqCst, SeqCst ) diff --git a/src/tools/miri/tests/pass/ptr_raw.rs b/src/tools/miri/tests/pass/ptr_raw.rs index 11c3455a9ca..dcf13d97ce3 100644 --- a/src/tools/miri/tests/pass/ptr_raw.rs +++ b/src/tools/miri/tests/pass/ptr_raw.rs @@ -35,12 +35,12 @@ fn assign_overlapping() { fn deref_invalid() { unsafe { // `addr_of!(*ptr)` is never UB. - let _val = addr_of!(*ptr::invalid::(0)); - let _val = addr_of!(*ptr::invalid::(1)); // not aligned + let _val = addr_of!(*ptr::without_provenance::(0)); + let _val = addr_of!(*ptr::without_provenance::(1)); // not aligned // Similarly, just mentioning the place is fine. - let _ = *ptr::invalid::(0); - let _ = *ptr::invalid::(1); + let _ = *ptr::without_provenance::(0); + let _ = *ptr::without_provenance::(1); } } diff --git a/src/tools/miri/tests/pass/slices.rs b/src/tools/miri/tests/pass/slices.rs index a99e921150b..d30ca96ea41 100644 --- a/src/tools/miri/tests/pass/slices.rs +++ b/src/tools/miri/tests/pass/slices.rs @@ -29,7 +29,7 @@ fn slice_of_zst() { // In a slice of zero-size elements the pointer is meaningless. // Ensure iteration still works even if the pointer is at the end of the address space. - let slice: &[()] = unsafe { slice::from_raw_parts(ptr::invalid(-5isize as usize), 10) }; + let slice: &[()] = unsafe { slice::from_raw_parts(ptr::without_provenance(-5isize as usize), 10) }; assert_eq!(slice.len(), 10); assert_eq!(slice.iter().count(), 10); @@ -43,7 +43,7 @@ fn slice_of_zst() { // Test mutable iterators as well let slice: &mut [()] = - unsafe { slice::from_raw_parts_mut(ptr::invalid_mut(-5isize as usize), 10) }; + unsafe { slice::from_raw_parts_mut(ptr::without_provenance_mut(-5isize as usize), 10) }; assert_eq!(slice.len(), 10); assert_eq!(slice.iter_mut().count(), 10); @@ -263,7 +263,7 @@ fn test_for_invalidated_pointers() { fn large_raw_slice() { let size = isize::MAX as usize; // Creating a raw slice of size isize::MAX and asking for its size is okay. - let s = std::ptr::slice_from_raw_parts(ptr::invalid::(1), size); + let s = std::ptr::slice_from_raw_parts(ptr::without_provenance::(1), size); assert_eq!(size, unsafe { std::mem::size_of_val_raw(s) }); } diff --git a/src/tools/miri/tests/pass/underscore_pattern.rs b/src/tools/miri/tests/pass/underscore_pattern.rs index b0e85bc1bb0..f0afe558954 100644 --- a/src/tools/miri/tests/pass/underscore_pattern.rs +++ b/src/tools/miri/tests/pass/underscore_pattern.rs @@ -38,7 +38,7 @@ fn invalid_match() { fn dangling_let() { unsafe { - let ptr = ptr::invalid::(0x40); + let ptr = ptr::without_provenance::(0x40); let _ = *ptr; } } @@ -54,7 +54,7 @@ fn invalid_let() { // Adding a type annotation used to change how MIR is generated, make sure we cover both cases. fn dangling_let_type_annotation() { unsafe { - let ptr = ptr::invalid::(0x40); + let ptr = ptr::without_provenance::(0x40); let _: bool = *ptr; } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff index 80191a21f4f..e6b8d5e6c21 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff @@ -17,26 +17,28 @@ scope 4 (inlined Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { - let mut _7: usize; scope 6 { let _6: *mut [bool; 0]; scope 7 { debug ptr => _6; - scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { + scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: bool; let _9: (); let mut _10: *mut (); let mut _11: *const [bool; 0]; - scope 12 { + scope 13 { } } } - scope 8 (inlined align_of::<[bool; 0]>) { - } - scope 9 (inlined invalid_mut::<[bool; 0]>) { - debug addr => _7; - scope 10 { + scope 8 (inlined dangling_mut::<[bool; 0]>) { + let mut _7: usize; + scope 9 (inlined align_of::<[bool; 0]>) { + } + scope 10 (inlined without_provenance_mut::<[bool; 0]>) { + debug addr => _7; + scope 11 { + } } } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff index ed878978e4b..bd74591018b 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff @@ -17,26 +17,28 @@ scope 4 (inlined Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { - let mut _7: usize; scope 6 { let _6: *mut [bool; 0]; scope 7 { debug ptr => _6; - scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { + scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: bool; let _9: (); let mut _10: *mut (); let mut _11: *const [bool; 0]; - scope 12 { + scope 13 { } } } - scope 8 (inlined align_of::<[bool; 0]>) { - } - scope 9 (inlined invalid_mut::<[bool; 0]>) { - debug addr => _7; - scope 10 { + scope 8 (inlined dangling_mut::<[bool; 0]>) { + let mut _7: usize; + scope 9 (inlined align_of::<[bool; 0]>) { + } + scope 10 (inlined without_provenance_mut::<[bool; 0]>) { + debug addr => _7; + scope 11 { + } } } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff index a61902501bf..fdbb0b2df03 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff @@ -17,26 +17,28 @@ scope 4 (inlined Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { - let mut _7: usize; scope 6 { let _6: *mut [bool; 0]; scope 7 { debug ptr => _6; - scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { + scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: bool; let _9: (); let mut _10: *mut (); let mut _11: *const [bool; 0]; - scope 12 { + scope 13 { } } } - scope 8 (inlined align_of::<[bool; 0]>) { - } - scope 9 (inlined invalid_mut::<[bool; 0]>) { - debug addr => _7; - scope 10 { + scope 8 (inlined dangling_mut::<[bool; 0]>) { + let mut _7: usize; + scope 9 (inlined align_of::<[bool; 0]>) { + } + scope 10 (inlined without_provenance_mut::<[bool; 0]>) { + debug addr => _7; + scope 11 { + } } } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff index fca7fe89b4a..d6b5984b81d 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff @@ -17,26 +17,28 @@ scope 4 (inlined Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { - let mut _7: usize; scope 6 { let _6: *mut [bool; 0]; scope 7 { debug ptr => _6; - scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { + scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: bool; let _9: (); let mut _10: *mut (); let mut _11: *const [bool; 0]; - scope 12 { + scope 13 { } } } - scope 8 (inlined align_of::<[bool; 0]>) { - } - scope 9 (inlined invalid_mut::<[bool; 0]>) { - debug addr => _7; - scope 10 { + scope 8 (inlined dangling_mut::<[bool; 0]>) { + let mut _7: usize; + scope 9 (inlined align_of::<[bool; 0]>) { + } + scope 10 (inlined without_provenance_mut::<[bool; 0]>) { + debug addr => _7; + scope 11 { + } } } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff index 0ced2e4deed..c7445aaee6c 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff @@ -17,26 +17,28 @@ scope 4 (inlined Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { - let mut _7: usize; scope 6 { let _6: *mut [bool; 0]; scope 7 { debug ptr => _6; - scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { + scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: bool; let _9: (); let mut _10: *mut (); let mut _11: *const [bool; 0]; - scope 12 { + scope 13 { } } } - scope 8 (inlined align_of::<[bool; 0]>) { - } - scope 9 (inlined invalid_mut::<[bool; 0]>) { - debug addr => _7; - scope 10 { + scope 8 (inlined dangling_mut::<[bool; 0]>) { + let mut _7: usize; + scope 9 (inlined align_of::<[bool; 0]>) { + } + scope 10 (inlined without_provenance_mut::<[bool; 0]>) { + debug addr => _7; + scope 11 { + } } } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff index e17d76a6d95..b8e961bc087 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff @@ -17,26 +17,28 @@ scope 4 (inlined Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { - let mut _7: usize; scope 6 { let _6: *mut [bool; 0]; scope 7 { debug ptr => _6; - scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { + scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: bool; let _9: (); let mut _10: *mut (); let mut _11: *const [bool; 0]; - scope 12 { + scope 13 { } } } - scope 8 (inlined align_of::<[bool; 0]>) { - } - scope 9 (inlined invalid_mut::<[bool; 0]>) { - debug addr => _7; - scope 10 { + scope 8 (inlined dangling_mut::<[bool; 0]>) { + let mut _7: usize; + scope 9 (inlined align_of::<[bool; 0]>) { + } + scope 10 (inlined without_provenance_mut::<[bool; 0]>) { + debug addr => _7; + scope 11 { + } } } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff index ff68b3c2d55..9678db90d05 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff @@ -17,26 +17,28 @@ scope 4 (inlined Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { - let mut _7: usize; scope 6 { let _6: *mut [bool; 0]; scope 7 { debug ptr => _6; - scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { + scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: bool; let _9: (); let mut _10: *mut (); let mut _11: *const [bool; 0]; - scope 12 { + scope 13 { } } } - scope 8 (inlined align_of::<[bool; 0]>) { - } - scope 9 (inlined invalid_mut::<[bool; 0]>) { - debug addr => _7; - scope 10 { + scope 8 (inlined dangling_mut::<[bool; 0]>) { + let mut _7: usize; + scope 9 (inlined align_of::<[bool; 0]>) { + } + scope 10 (inlined without_provenance_mut::<[bool; 0]>) { + debug addr => _7; + scope 11 { + } } } } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff index de951e57fb9..8aa6c9c23e9 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff @@ -17,26 +17,28 @@ scope 4 (inlined Unique::<[bool; 0]>::dangling) { let mut _5: std::ptr::NonNull<[bool; 0]>; scope 5 (inlined NonNull::<[bool; 0]>::dangling) { - let mut _7: usize; scope 6 { let _6: *mut [bool; 0]; scope 7 { debug ptr => _6; - scope 11 (inlined NonNull::<[bool; 0]>::new_unchecked) { + scope 12 (inlined NonNull::<[bool; 0]>::new_unchecked) { debug ptr => _6; let mut _8: bool; let _9: (); let mut _10: *mut (); let mut _11: *const [bool; 0]; - scope 12 { + scope 13 { } } } - scope 8 (inlined align_of::<[bool; 0]>) { - } - scope 9 (inlined invalid_mut::<[bool; 0]>) { - debug addr => _7; - scope 10 { + scope 8 (inlined dangling_mut::<[bool; 0]>) { + let mut _7: usize; + scope 9 (inlined align_of::<[bool; 0]>) { + } + scope 10 (inlined without_provenance_mut::<[bool; 0]>) { + debug addr => _7; + scope 11 { + } } } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 05b01404b69..1eda1ac1365 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -42,7 +42,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 8 { debug end_or_len => _11; } - scope 14 (inlined invalid::) { + scope 14 (inlined without_provenance::) { debug addr => _3; scope 15 { } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 1fb29f5c662..3cd79654fac 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -42,7 +42,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 8 { debug end_or_len => _11; } - scope 14 (inlined invalid::) { + scope 14 (inlined without_provenance::) { debug addr => _3; scope 15 { } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 2e63030aa5e..a6995bbcbe3 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -39,7 +39,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 8 { debug end_or_len => _11; } - scope 14 (inlined invalid::) { + scope 14 (inlined without_provenance::) { debug addr => _3; scope 15 { } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index b6b6b6972e9..039b7e1aa47 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -39,7 +39,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 8 { debug end_or_len => _11; } - scope 14 (inlined invalid::) { + scope 14 (inlined without_provenance::) { debug addr => _3; scope 15 { } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index a78e46a0b78..2465c2381ad 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -44,7 +44,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 8 { debug end_or_len => _11; } - scope 14 (inlined invalid::) { + scope 14 (inlined without_provenance::) { debug addr => _3; scope 15 { } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index 4e54a23e819..c5219ac3390 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -44,7 +44,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 8 { debug end_or_len => _11; } - scope 14 (inlined invalid::) { + scope 14 (inlined without_provenance::) { debug addr => _3; scope 15 { } -- cgit 1.4.1-3-g733a5 From 1e16927ef37eb841d6a38b5e61438931d20c43fb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Feb 2024 10:35:53 +1100 Subject: Remove an out-of-date comment. --- compiler/rustc_errors/src/lib.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'compiler') diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 052d9b3a783..64b88adedbb 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1271,7 +1271,6 @@ impl DiagCtxtInner { fn emit_stashed_diagnostics(&mut self) { let has_errors = !self.err_guars.is_empty(); for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { - // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { if diag.is_lint.is_none() { self.stashed_err_count -= 1; -- cgit 1.4.1-3-g733a5 From 203b4332bb3da3af092344b3459416aeab4c90ef Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Feb 2024 14:50:07 +1100 Subject: Remove dead `expect_error_or_delayed_bug` method. --- compiler/rustc_middle/src/ty/context.rs | 5 ----- compiler/rustc_type_ir/src/interner.rs | 3 --- 2 files changed, 8 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index cc734e7157f..9d59f779470 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -153,11 +153,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> Self::Const { Const::new_bound(self, debruijn, var, ty) } - - fn expect_error_or_delayed_bug() { - let has_errors = ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs()); - assert!(has_errors.is_some()); - } } type InternedSet<'tcx, T> = ShardedHashMap, ()>; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7728ee0e842..7d2c42a6dbe 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -95,9 +95,6 @@ pub trait Interner: Sized { fn mk_bound_ty(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Ty; fn mk_bound_region(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Region; fn mk_bound_const(self, debruijn: DebruijnIndex, var: BoundVar, ty: Self::Ty) -> Self::Const; - - /// Assert that an error has been delayed or emitted. - fn expect_error_or_delayed_bug(); } /// Common capabilities of placeholder kinds -- cgit 1.4.1-3-g733a5 From 9919c3dab3e4eabe466612de5f6c472e3e27ceb6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Feb 2024 15:26:42 +1100 Subject: Remove `EarlyDiagCtxt::abort_if_errors`. Its one use isn't necessary, because it's not possible for errors to have been emitted at that point. --- compiler/rustc_driver_impl/src/lib.rs | 5 ++--- compiler/rustc_session/src/session.rs | 4 ---- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 60f11b1bdd4..9b2d760282f 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -349,11 +349,10 @@ fn run_compiler( }, }; - callbacks.config(&mut config); - - default_early_dcx.abort_if_errors(); drop(default_early_dcx); + callbacks.config(&mut config); + interface::run_compiler(config, |compiler| { let sess = &compiler.sess; let codegen_backend = &*compiler.codegen_backend; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9d1133c487f..422bbadf6a8 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1410,10 +1410,6 @@ impl EarlyDiagCtxt { Self { dcx: DiagCtxt::with_emitter(emitter) } } - pub fn abort_if_errors(&self) { - self.dcx.abort_if_errors() - } - /// Swap out the underlying dcx once we acquire the user's preference on error emission /// format. Any errors prior to that will cause an abort and all stashed diagnostics of the /// previous dcx will be emitted. -- cgit 1.4.1-3-g733a5 From 46f49833566381887ba74e3f756271a6e8723636 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 09:36:08 +1100 Subject: Adjust the `has_errors*` methods. Currently `has_errors` excludes lint errors. This commit changes it to include lint errors. The motivation for this is that for most places it doesn't matter whether lint errors are included or not. But there are multiple places where they must be includes, and only one place where they must not be included. So it makes sense for `has_errors` to do the thing that fits the most situations, and the new `has_errors_excluding_lint_errors` method in the one exceptional place. The same change is made for `err_count`. Annoyingly, this requires the introduction of `err_count_excluding_lint_errs` for one place, to preserve existing error printing behaviour. But I still think the change is worthwhile overall. --- compiler/rustc_errors/src/lib.rs | 46 ++++++++++++---------- compiler/rustc_incremental/src/persist/fs.rs | 2 +- compiler/rustc_incremental/src/persist/save.rs | 4 +- compiler/rustc_infer/src/infer/mod.rs | 9 +++-- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_metadata/src/creader.rs | 2 +- compiler/rustc_query_system/src/dep_graph/graph.rs | 2 +- compiler/rustc_session/src/session.rs | 3 +- src/librustdoc/core.rs | 3 +- src/librustdoc/doctest.rs | 3 +- 10 files changed, 41 insertions(+), 35 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 64b88adedbb..a6b0a0e8f17 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -754,13 +754,20 @@ impl DiagCtxt { self.inner.borrow_mut().emit_stashed_diagnostics() } - /// This excludes lint errors, delayed bugs, and stashed errors. + /// This excludes lint errors, delayed bugs and stashed errors. #[inline] - pub fn err_count(&self) -> usize { + pub fn err_count_excluding_lint_errs(&self) -> usize { self.inner.borrow().err_guars.len() } - /// This excludes normal errors, lint errors and delayed bugs. Unless + /// This excludes delayed bugs and stashed errors. + #[inline] + pub fn err_count(&self) -> usize { + let inner = self.inner.borrow(); + inner.err_guars.len() + inner.lint_err_guars.len() + } + + /// This excludes normal errors, lint errors, and delayed bugs. Unless /// absolutely necessary, avoid using this. It's dubious because stashed /// errors can later be cancelled, so the presence of a stashed error at /// some point of time doesn't guarantee anything -- there are no @@ -769,21 +776,21 @@ impl DiagCtxt { self.inner.borrow().stashed_err_count } - /// This excludes lint errors, delayed bugs, and stashed errors. - pub fn has_errors(&self) -> Option { - self.inner.borrow().has_errors() + /// This excludes lint errors, delayed bugs, and stashed errors. Unless + /// absolutely necessary, prefer `has_errors` to this method. + pub fn has_errors_excluding_lint_errors(&self) -> Option { + self.inner.borrow().has_errors_excluding_lint_errors() } - /// This excludes delayed bugs and stashed errors. Unless absolutely - /// necessary, prefer `has_errors` to this method. - pub fn has_errors_or_lint_errors(&self) -> Option { - self.inner.borrow().has_errors_or_lint_errors() + /// This excludes delayed bugs and stashed errors. + pub fn has_errors(&self) -> Option { + self.inner.borrow().has_errors() } /// This excludes stashed errors. Unless absolutely necessary, prefer - /// `has_errors` or `has_errors_or_lint_errors` to this method. - pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option { - self.inner.borrow().has_errors_or_lint_errors_or_delayed_bugs() + /// `has_errors` to this method. + pub fn has_errors_or_delayed_bugs(&self) -> Option { + self.inner.borrow().has_errors_or_delayed_bugs() } pub fn print_error_count(&self, registry: &Registry) { @@ -1328,7 +1335,7 @@ impl DiagCtxtInner { DelayedBug => { // If we have already emitted at least one error, we don't need // to record the delayed bug, because it'll never be used. - return if let Some(guar) = self.has_errors_or_lint_errors() { + return if let Some(guar) = self.has_errors() { Some(guar) } else { let backtrace = std::backtrace::Backtrace::capture(); @@ -1444,17 +1451,16 @@ impl DiagCtxtInner { .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get()) } - fn has_errors(&self) -> Option { + fn has_errors_excluding_lint_errors(&self) -> Option { self.err_guars.get(0).copied() } - fn has_errors_or_lint_errors(&self) -> Option { - self.has_errors().or_else(|| self.lint_err_guars.get(0).copied()) + fn has_errors(&self) -> Option { + self.has_errors_excluding_lint_errors().or_else(|| self.lint_err_guars.get(0).copied()) } - fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option { - self.has_errors_or_lint_errors() - .or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied()) + fn has_errors_or_delayed_bugs(&self) -> Option { + self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied()) } /// Translate `message` eagerly with `args` to `SubdiagnosticMessage::Eager`. diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 23d29916922..dd9c16d006a 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -312,7 +312,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option) { let incr_comp_session_dir: PathBuf = sess.incr_comp_session_dir().clone(); - if sess.dcx().has_errors_or_lint_errors_or_delayed_bugs().is_some() { + if sess.dcx().has_errors_or_delayed_bugs().is_some() { // If there have been any errors during compilation, we don't want to // publish this session directory. Rather, we'll just delete it. diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index ff0c58d09de..32759f5284a 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -32,7 +32,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { return; } // This is going to be deleted in finalize_session_directory, so let's not create it. - if sess.dcx().has_errors_or_lint_errors_or_delayed_bugs().is_some() { + if sess.dcx().has_errors_or_delayed_bugs().is_some() { return; } @@ -87,7 +87,7 @@ pub fn save_work_product_index( return; } // This is going to be deleted in finalize_session_directory, so let's not create it - if sess.dcx().has_errors_or_lint_errors().is_some() { + if sess.dcx().has_errors().is_some() { return; } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 243558b11a8..f131d11c411 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -713,7 +713,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { reported_trait_errors: Default::default(), reported_signature_mismatch: Default::default(), tainted_by_errors: Cell::new(None), - err_count_on_creation: tcx.dcx().err_count(), + err_count_on_creation: tcx.dcx().err_count_excluding_lint_errs(), stashed_err_count_on_creation: tcx.dcx().stashed_err_count(), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, @@ -1268,8 +1268,11 @@ impl<'tcx> InferCtxt<'tcx> { pub fn tainted_by_errors(&self) -> Option { if let Some(guar) = self.tainted_by_errors.get() { Some(guar) - } else if self.dcx().err_count() > self.err_count_on_creation { - // Errors reported since this infcx was made. + } else if self.dcx().err_count_excluding_lint_errs() > self.err_count_on_creation { + // Errors reported since this infcx was made. Lint errors are + // excluded to avoid some being swallowed in the presence of + // non-lint errors. (It's arguable whether or not this exclusion is + // important.) let guar = self.dcx().has_errors().unwrap(); self.set_tainted_by_errors(guar); Some(guar) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 60d13f02ad7..858db594b47 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -772,7 +772,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { // lot of annoying errors in the ui tests (basically, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis - if let Some(reported) = sess.dcx().has_errors() { + if let Some(reported) = sess.dcx().has_errors_excluding_lint_errors() { return Err(reported); } else if sess.dcx().stashed_err_count() > 0 { // Without this case we sometimes get delayed bug ICEs and I don't diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f6d3dba2470..baa9af87a83 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -926,7 +926,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { what: &str, needs_dep: &dyn Fn(&CrateMetadata) -> bool, ) { - // don't perform this validation if the session has errors, as one of + // Don't perform this validation if the session has errors, as one of // those errors may indicate a circular dependency which could cause // this to stack overflow. if self.dcx().has_errors().is_some() { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index b6ac54a9ab5..7dc1a1f7917 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -817,7 +817,7 @@ impl DepGraphData { None => {} } - if let None = qcx.dep_context().sess().dcx().has_errors_or_lint_errors_or_delayed_bugs() { + if let None = qcx.dep_context().sess().dcx().has_errors_or_delayed_bugs() { panic!("try_mark_previous_green() - Forcing the DepNode should have set its color") } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 422bbadf6a8..f8a1d79659d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -313,8 +313,7 @@ impl Session { } pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> { - // We must include lint errors here. - if let Some(reported) = self.dcx().has_errors_or_lint_errors() { + if let Some(reported) = self.dcx().has_errors() { self.dcx().emit_stashed_diagnostics(); Err(reported) } else { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index efad5a8d808..3f7edd049a7 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -452,8 +452,7 @@ pub(crate) fn run_global_ctxt( tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc))); - // We must include lint errors here. - if tcx.dcx().has_errors_or_lint_errors().is_some() { + if tcx.dcx().has_errors().is_some() { rustc_errors::FatalError.raise(); } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index f9d4d1af114..09a90b62d97 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -153,8 +153,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { collector }); - // We must include lint errors here. - if compiler.sess.dcx().has_errors_or_lint_errors().is_some() { + if compiler.sess.dcx().has_errors().is_some() { FatalError.raise(); } -- cgit 1.4.1-3-g733a5 From 72b172bdf631483d0f802c54c8dc8246f6b4e00e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 10:00:19 +1100 Subject: Overhaul the handling of errors at the top-level. Currently `emit_stashed_diagnostic` is called from four(!) different places: `print_error_count`, `DiagCtxtInner::drop`, `abort_if_errors`, and `compile_status`. And `flush_delayed` is called from two different places: `DiagCtxtInner::drop` and `Queries`. This is pretty gross! Each one should really be called from a single place, but there's a bunch of entanglements. This commit cleans up this mess. Specifically, it: - Removes all the existing calls to `emit_stashed_diagnostic`, and adds a single new call in `finish_diagnostics`. - Removes the early `flush_delayed` call in `codegen_and_build_linker`, replacing it with a simple early return if delayed bugs are present. - Changes `DiagCtxtInner::drop` and `DiagCtxtInner::flush_delayed` so they both assert that the stashed diagnostics are empty (i.e. processed beforehand). - Changes `interface::run_compiler` so that any errors emitted during `finish_diagnostics` (i.e. late-emitted stashed diagnostics) are counted and cannot be overlooked. This requires adding `ErrorGuaranteed` return values to several functions. - Removes the `stashed_err_count` call in `analysis`. This is possible now that we don't have to worry about calling `flush_delayed` early from `codegen_and_build_linker` when stashed diagnostics are pending. - Changes the `span_bug` case in `handle_tuple_field_pattern_match` to a `delayed_span_bug`, because it now can be reached due to the removal of the `stashed_err_count` call in `analysis`. - Slightly changes the expected output of three tests. If no errors are emitted but there are delayed bugs, the error count is no longer printed. This is because delayed bugs are now always printed after the error count is printed (or not printed, if the error count is zero). There is a lot going on in this commit. It's hard to break into smaller pieces because the existing code is very tangled. It took me a long time and a lot of effort to understand how the different pieces interact, and I think the new code is a lot simpler and easier to understand. --- compiler/rustc_errors/src/lib.rs | 32 ++++++++++++------- compiler/rustc_interface/src/interface.rs | 37 ++++++++++++++++++---- compiler/rustc_interface/src/passes.rs | 11 +++---- compiler/rustc_interface/src/queries.rs | 12 +++---- compiler/rustc_passes/src/dead.rs | 5 ++- compiler/rustc_session/src/session.rs | 14 +++++--- .../equality-in-canonical-query.clone.stderr | 2 -- tests/ui/inference/issue-80409.no-compat.stderr | 2 -- ...tait_equality_in_canonical_query.current.stderr | 2 -- 9 files changed, 76 insertions(+), 41 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a6b0a0e8f17..fafd636bb70 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -471,9 +471,10 @@ struct DiagCtxtInner { emitted_diagnostics: FxHashSet, /// Stashed diagnostics emitted in one stage of the compiler that may be - /// stolen by other stages (e.g. to improve them and add more information). - /// The stashed diagnostics count towards the total error count. - /// When `.abort_if_errors()` is called, these are also emitted. + /// stolen and emitted/cancelled by other stages (e.g. to improve them and + /// add more information). All stashed diagnostics must be emitted with + /// `emit_stashed_diagnostics` by the time the `DiagCtxtInner` is dropped, + /// otherwise an assertion failure will occur. stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>, future_breakage_diagnostics: Vec, @@ -558,7 +559,9 @@ pub struct DiagCtxtFlags { impl Drop for DiagCtxtInner { fn drop(&mut self) { - self.emit_stashed_diagnostics(); + // Any stashed diagnostics should have been handled by + // `emit_stashed_diagnostics` by now. + assert!(self.stashed_diagnostics.is_empty()); if self.err_guars.is_empty() { self.flush_delayed() @@ -750,7 +753,7 @@ impl DiagCtxt { } /// Emit all stashed diagnostics. - pub fn emit_stashed_diagnostics(&self) { + pub fn emit_stashed_diagnostics(&self) -> Option { self.inner.borrow_mut().emit_stashed_diagnostics() } @@ -796,7 +799,9 @@ impl DiagCtxt { pub fn print_error_count(&self, registry: &Registry) { let mut inner = self.inner.borrow_mut(); - inner.emit_stashed_diagnostics(); + // Any stashed diagnostics should have been handled by + // `emit_stashed_diagnostics` by now. + assert!(inner.stashed_diagnostics.is_empty()); if inner.treat_err_as_bug() { return; @@ -872,9 +877,7 @@ impl DiagCtxt { } pub fn abort_if_errors(&self) { - let mut inner = self.inner.borrow_mut(); - inner.emit_stashed_diagnostics(); - if !inner.err_guars.is_empty() { + if self.has_errors().is_some() { FatalError.raise(); } } @@ -1275,7 +1278,8 @@ impl DiagCtxt { // `DiagCtxtInner::foo`. impl DiagCtxtInner { /// Emit all stashed diagnostics. - fn emit_stashed_diagnostics(&mut self) { + fn emit_stashed_diagnostics(&mut self) -> Option { + let mut guar = None; let has_errors = !self.err_guars.is_empty(); for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { if diag.is_error() { @@ -1290,8 +1294,9 @@ impl DiagCtxtInner { continue; } } - self.emit_diagnostic(diag); + guar = guar.or(self.emit_diagnostic(diag)); } + guar } // Return value is only `Some` if the level is `Error` or `DelayedBug`. @@ -1493,6 +1498,11 @@ impl DiagCtxtInner { } fn flush_delayed(&mut self) { + // Stashed diagnostics must be emitted before delayed bugs are flushed. + // Otherwise, we might ICE prematurely when errors would have + // eventually happened. + assert!(self.stashed_diagnostics.is_empty()); + if self.delayed_bugs.is_empty() { return; } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 8a4705e0056..cd7957c3bce 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -423,18 +423,43 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se Compiler { sess, codegen_backend, override_queries: config.override_queries }; rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || { - let r = { - let _sess_abort_error = defer(|| { - compiler.sess.finish_diagnostics(&config.registry); + // There are two paths out of `f`. + // - Normal exit. + // - Panic, e.g. triggered by `abort_if_errors`. + // + // We must run `finish_diagnostics` in both cases. + let res = { + // If `f` panics, `finish_diagnostics` will run during + // unwinding because of the `defer`. + let mut guar = None; + let sess_abort_guard = defer(|| { + guar = compiler.sess.finish_diagnostics(&config.registry); }); - f(&compiler) + let res = f(&compiler); + + // If `f` doesn't panic, `finish_diagnostics` will run + // normally when `sess_abort_guard` is dropped. + drop(sess_abort_guard); + + // If `finish_diagnostics` emits errors (e.g. stashed + // errors) we can't return an error directly, because the + // return type of this function is `R`, not `Result`. + // But we need to communicate the errors' existence to the + // caller, otherwise the caller might mistakenly think that + // no errors occurred and return a zero exit code. So we + // abort (panic) instead, similar to if `f` had panicked. + if guar.is_some() { + compiler.sess.dcx().abort_if_errors(); + } + + res }; let prof = compiler.sess.prof.clone(); - prof.generic_activity("drop_compiler").run(move || drop(compiler)); - r + + res }) }, ) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 858db594b47..d35c2be1fb4 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -772,12 +772,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { // lot of annoying errors in the ui tests (basically, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis - if let Some(reported) = sess.dcx().has_errors_excluding_lint_errors() { - return Err(reported); - } else if sess.dcx().stashed_err_count() > 0 { - // Without this case we sometimes get delayed bug ICEs and I don't - // understand why. -nnethercote - return Err(sess.dcx().delayed_bug("some stashed error is waiting for use")); + // + // But we exclude lint errors from this, because lint errors are typically + // less serious and we're more likely to want to continue (#87337). + if let Some(guar) = sess.dcx().has_errors_excluding_lint_errors() { + return Err(guar); } sess.time("misc_checking_3", || { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 211bcb9da94..8170c0a5a1a 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -222,12 +222,12 @@ impl<'tcx> Queries<'tcx> { pub fn codegen_and_build_linker(&'tcx self) -> Result { self.global_ctxt()?.enter(|tcx| { - // Don't do code generation if there were any errors - self.compiler.sess.compile_status()?; - - // If we have any delayed bugs, for example because we created TyKind::Error earlier, - // it's likely that codegen will only cause more ICEs, obscuring the original problem - self.compiler.sess.dcx().flush_delayed(); + // Don't do code generation if there were any errors. Likewise if + // there were any delayed bugs, because codegen will likely cause + // more ICEs, obscuring the original problem. + if let Some(guar) = self.compiler.sess.dcx().has_errors_or_delayed_bugs() { + return Err(guar); + } // Hook for UI tests. Self::check_for_rustc_errors_attr(tcx); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 486396b0677..a3106856a67 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -237,7 +237,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { ty::Adt(adt, _) => adt.variant_of_res(res), - _ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"), + _ => { + self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern"); + return; + } }; let dotdot = dotdot.as_opt_usize().unwrap_or(pats.len()); let first_n = pats.iter().enumerate().take(dotdot); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f8a1d79659d..48a18fca27e 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -258,7 +258,8 @@ impl Session { } } - fn check_miri_unleashed_features(&self) { + fn check_miri_unleashed_features(&self) -> Option { + let mut guar = None; let unleashed_features = self.miri_unleashed_features.lock(); if !unleashed_features.is_empty() { let mut must_err = false; @@ -279,18 +280,22 @@ impl Session { // If we should err, make sure we did. if must_err && self.dcx().has_errors().is_none() { // We have skipped a feature gate, and not run into other errors... reject. - self.dcx().emit_err(errors::NotCircumventFeature); + guar = Some(self.dcx().emit_err(errors::NotCircumventFeature)); } } + guar } /// Invoked all the way at the end to finish off diagnostics printing. - pub fn finish_diagnostics(&self, registry: &Registry) { - self.check_miri_unleashed_features(); + pub fn finish_diagnostics(&self, registry: &Registry) -> Option { + let mut guar = None; + guar = guar.or(self.check_miri_unleashed_features()); + guar = guar.or(self.dcx().emit_stashed_diagnostics()); self.dcx().print_error_count(registry); if self.opts.json_future_incompat { self.dcx().emit_future_breakage_report(); } + guar } /// Returns true if the crate is a testing one. @@ -314,7 +319,6 @@ impl Session { pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> { if let Some(reported) = self.dcx().has_errors() { - self.dcx().emit_stashed_diagnostics(); Err(reported) } else { Ok(()) diff --git a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr index 0e3cd2ff060..e4c8aec3973 100644 --- a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr +++ b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr @@ -21,5 +21,3 @@ LL | same_output(foo, rpit); query stack during panic: end of query stack -error: aborting due to 2 previous errors - diff --git a/tests/ui/inference/issue-80409.no-compat.stderr b/tests/ui/inference/issue-80409.no-compat.stderr index f9772b2d5a6..523ca229b06 100644 --- a/tests/ui/inference/issue-80409.no-compat.stderr +++ b/tests/ui/inference/issue-80409.no-compat.stderr @@ -12,5 +12,3 @@ LL | builder.state().on_entry(|_| {}); query stack during panic: end of query stack -error: aborting due to 1 previous error - diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr index fd76526644b..069292239bc 100644 --- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr +++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr @@ -21,5 +21,3 @@ LL | query(get_rpit); query stack during panic: end of query stack -error: aborting due to 2 previous errors - -- cgit 1.4.1-3-g733a5 From c2512a130f398d923229c3dc401be10c357a3b8d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 10:13:51 +1100 Subject: Inline and remove `Session::compile_status`. Because it's now simple enough that it doesn't provide much benefit. --- compiler/rustc_codegen_ssa/src/back/link.rs | 4 +++- compiler/rustc_driver_impl/src/lib.rs | 17 ++++++++++++----- compiler/rustc_interface/src/queries.rs | 4 +++- compiler/rustc_session/src/session.rs | 8 -------- src/tools/miri/src/bin/miri.rs | 2 +- 5 files changed, 19 insertions(+), 16 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 435b517e602..7e3f324fe14 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -487,7 +487,9 @@ fn collate_raw_dylibs<'a, 'b>( } } } - sess.compile_status()?; + if let Some(guar) = sess.dcx().has_errors() { + return Err(guar); + } Ok(dylib_table .into_iter() .map(|(name, imports)| { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9b2d760282f..1057235c0a2 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -357,18 +357,25 @@ fn run_compiler( let sess = &compiler.sess; let codegen_backend = &*compiler.codegen_backend; + // This is used for early exits unrelated to errors. E.g. when just + // printing some information without compiling, or exiting immediately + // after parsing, etc. + let early_exit = || { + if let Some(guar) = sess.dcx().has_errors() { Err(guar) } else { Ok(()) } + }; + // This implements `-Whelp`. It should be handled very early, like // `--help`/`-Zhelp`/`-Chelp`. This is the earliest it can run, because // it must happen after lints are registered, during session creation. if sess.opts.describe_lints { describe_lints(sess); - return sess.compile_status(); + return early_exit(); } let early_dcx = EarlyDiagCtxt::new(sess.opts.error_format); if print_crate_info(&early_dcx, codegen_backend, sess, has_input) == Compilation::Stop { - return sess.compile_status(); + return early_exit(); } if !has_input { @@ -377,16 +384,16 @@ fn run_compiler( if !sess.opts.unstable_opts.ls.is_empty() { list_metadata(&early_dcx, sess, &*codegen_backend.metadata_loader()); - return sess.compile_status(); + return early_exit(); } if sess.opts.unstable_opts.link_only { process_rlink(sess, compiler); - return sess.compile_status(); + return early_exit(); } let linker = compiler.enter(|queries| { - let early_exit = || sess.compile_status().map(|_| None); + let early_exit = || early_exit().map(|_| None); queries.parse()?; if let Some(ppm) = &sess.opts.pretty { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 8170c0a5a1a..86858bfe41d 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -261,7 +261,9 @@ impl Linker { let (codegen_results, work_products) = codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames); - sess.compile_status()?; + if let Some(guar) = sess.dcx().has_errors() { + return Err(guar); + } sess.time("serialize_work_products", || { rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 48a18fca27e..02c7a0c6371 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -317,14 +317,6 @@ impl Session { err } - pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> { - if let Some(reported) = self.dcx().has_errors() { - Err(reported) - } else { - Ok(()) - } - } - /// Record the fact that we called `trimmed_def_paths`, and do some /// checking about whether its cost was justified. pub fn record_trimmed_def_paths(&self) { diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index db4c4a28deb..8a7133fea43 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -68,7 +68,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries: &'tcx rustc_interface::Queries<'tcx>, ) -> Compilation { queries.global_ctxt().unwrap().enter(|tcx| { - if tcx.sess.compile_status().is_err() { + if tcx.sess.dcx().has_errors().is_some() { tcx.dcx().fatal("miri cannot be run on programs that fail compilation"); } -- cgit 1.4.1-3-g733a5 From 4da67fff61ccc460370df6047563f8091c7e66bd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 10:23:58 +1100 Subject: Replace unnecessary `abort_if_errors`. Replace `abort_if_errors` calls that are certain to abort -- because we emit an error immediately beforehand -- with `FatalErro.raise()`. --- compiler/rustc_codegen_ssa/src/back/link.rs | 9 +++------ compiler/rustc_codegen_ssa/src/base.rs | 5 +---- compiler/rustc_errors/src/lib.rs | 4 ++++ compiler/rustc_interface/src/passes.rs | 4 +--- compiler/rustc_session/src/output.rs | 3 ++- .../src/traits/error_reporting/type_err_ctxt_ext.rs | 11 ++--------- 6 files changed, 13 insertions(+), 23 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 7e3f324fe14..1ad0dec0640 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3,7 +3,7 @@ use rustc_ast::CRATE_NODE_ID; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_errors::{DiagCtxt, ErrorGuaranteed}; +use rustc_errors::{DiagCtxt, ErrorGuaranteed, FatalError}; use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; @@ -722,10 +722,7 @@ fn link_dwarf_object<'a>( Ok(()) }) { Ok(()) => {} - Err(e) => { - sess.dcx().emit_err(errors::ThorinErrorWrapper(e)); - sess.dcx().abort_if_errors(); - } + Err(e) => sess.dcx().emit_fatal(errors::ThorinErrorWrapper(e)), } } @@ -1001,7 +998,7 @@ fn link_natively<'a>( sess.dcx().emit_note(errors::CheckInstalledVisualStudio); sess.dcx().emit_note(errors::InsufficientVSCodeProduct); } - sess.dcx().abort_if_errors(); + FatalError.raise(); } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 760b3f30ee5..f7afd22a48c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -449,10 +449,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let Some(llfn) = cx.declare_c_main(llfty) else { // FIXME: We should be smart and show a better diagnostic here. let span = cx.tcx().def_span(rust_main_def_id); - let dcx = cx.tcx().dcx(); - dcx.emit_err(errors::MultipleMainFunctions { span }); - dcx.abort_if_errors(); - bug!(); + cx.tcx().dcx().emit_fatal(errors::MultipleMainFunctions { span }); }; // `main` should respect same config for frame pointer elimination as rest of code diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index fafd636bb70..7e3d15ffc92 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -876,6 +876,10 @@ impl DiagCtxt { } } + /// This excludes delayed bugs and stashed errors. Used for early aborts + /// after errors occurred -- e.g. because continuing in the face of errors is + /// likely to lead to bad results, such as spurious/uninteresting + /// additional errors -- when returning an error `Result` is difficult. pub fn abort_if_errors(&self) { if self.has_errors().is_some() { FatalError.raise(); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index d35c2be1fb4..66140168759 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -936,9 +936,7 @@ pub fn start_codegen<'tcx>( if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx) { - let dcx = tcx.dcx(); - dcx.emit_err(errors::CantEmitMIR { error }); - dcx.abort_if_errors(); + tcx.dcx().emit_fatal(errors::CantEmitMIR { error }); } } diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index db976b30404..74d26237f24 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -6,6 +6,7 @@ use crate::errors::{ }; use crate::Session; use rustc_ast::{self as ast, attr}; +use rustc_errors::FatalError; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use std::path::Path; @@ -115,7 +116,7 @@ pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option) { } if err_count > 0 { - sess.dcx().abort_if_errors(); + FatalError.raise(); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index aa8bd5fdc86..7186b96b40d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -22,7 +22,7 @@ use crate::traits::{ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, - MultiSpan, StashKey, StringPart, + FatalError, MultiSpan, StashKey, StringPart, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; @@ -193,14 +193,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit); mutate(&mut err); err.emit(); - - self.dcx().abort_if_errors(); - // FIXME: this should be something like `build_overflow_error_fatal`, which returns - // `DiagnosticBuilder<', !>`. Then we don't even need anything after that `emit()`. - unreachable!( - "did not expect compilation to continue after `abort_if_errors`, \ - since an error was definitely emitted!" - ); + FatalError.raise(); } fn build_overflow_error( -- cgit 1.4.1-3-g733a5 From f16c226af3ad4d21021433745214c71e95f10236 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Feb 2024 13:51:53 +1100 Subject: Inline and remove `abort_on_err`. It's clumsy and doesn't improve readability. --- compiler/rustc_driver_impl/src/lib.rs | 17 ++++------------- compiler/rustc_driver_impl/src/pretty.rs | 14 ++++++++++---- src/librustdoc/lib.rs | 5 ++--- 3 files changed, 16 insertions(+), 20 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 1057235c0a2..692c059beb0 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -144,16 +144,6 @@ pub const EXIT_FAILURE: i32 = 1; pub const DEFAULT_BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\ ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md"; -pub fn abort_on_err(result: Result, sess: &Session) -> T { - match result { - Err(..) => { - sess.dcx().abort_if_errors(); - panic!("error reported but abort_if_errors didn't abort???"); - } - Ok(x) => x, - } -} - pub trait Callbacks { /// Called before creating the compiler instance fn config(&mut self, _config: &mut interface::Config) {} @@ -665,10 +655,11 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) { }; } }; - let result = compiler.codegen_backend.link(sess, codegen_results, &outputs); - abort_on_err(result, sess); + if compiler.codegen_backend.link(sess, codegen_results, &outputs).is_err() { + FatalError.raise(); + } } else { - dcx.emit_fatal(RlinkNotAFile {}) + dcx.emit_fatal(RlinkNotAFile {}); } } diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index e5a7d550115..ff5ffd2454a 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -2,6 +2,7 @@ use rustc_ast as ast; use rustc_ast_pretty::pprust as pprust_ast; +use rustc_errors::FatalError; use rustc_hir as hir; use rustc_hir_pretty as pprust_hir; use rustc_middle::bug; @@ -18,7 +19,6 @@ use std::fmt::Write; pub use self::PpMode::*; pub use self::PpSourceMode::*; -use crate::abort_on_err; struct AstNoAnn; @@ -243,7 +243,9 @@ impl<'tcx> PrintExtra<'tcx> { pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { if ppm.needs_analysis() { - abort_on_err(ex.tcx().analysis(()), sess); + if ex.tcx().analysis(()).is_err() { + FatalError.raise(); + } } let (src, src_name) = get_source(sess); @@ -334,7 +336,9 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { ThirTree => { let tcx = ex.tcx(); let mut out = String::new(); - abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); + if rustc_hir_analysis::check_crate(tcx).is_err() { + FatalError.raise(); + } debug!("pretty printing THIR tree"); for did in tcx.hir().body_owners() { let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did)); @@ -344,7 +348,9 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { ThirFlat => { let tcx = ex.tcx(); let mut out = String::new(); - abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); + if rustc_hir_analysis::check_crate(tcx).is_err() { + FatalError.raise(); + } debug!("pretty printing THIR flat"); for did in tcx.hir().body_owners() { let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did)); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index f88381ad788..33837fe5652 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -78,8 +78,7 @@ use std::io::{self, IsTerminal}; use std::process; use std::sync::{atomic::AtomicBool, Arc}; -use rustc_driver::abort_on_err; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{ErrorGuaranteed, FatalError}; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; @@ -779,7 +778,7 @@ fn main_args( } compiler.enter(|queries| { - let mut gcx = abort_on_err(queries.global_ctxt(), sess); + let Ok(mut gcx) = queries.global_ctxt() else { FatalError.raise() }; if sess.dcx().has_errors().is_some() { sess.dcx().fatal("Compilation failed, aborting rustdoc"); } -- cgit 1.4.1-3-g733a5