From c9a4a4a192403864ca70461a2747846c57a975f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Ho=C5=A1ek?= Date: Mon, 26 Feb 2024 15:35:30 +0100 Subject: [PATCH 01/18] Clarify behavior of slice prefix/suffix operations in case of equality Operations such as starts_with, ends_with, strip_prefix and strip_suffix can be either strict (do not consider a slice to be a prefix/suffix of itself) or not. In Rust's case, they are not strict. Add a few phrases to the documentation to clarify this. --- library/core/src/slice/mod.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 1ad81fcfcfe..aaedbed0d55 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2519,7 +2519,7 @@ impl [T] { cmp::SliceContains::slice_contains(x, self) } - /// Returns `true` if `needle` is a prefix of the slice. + /// Returns `true` if `needle` is a prefix of the slice or equal to the slice. /// /// # Examples /// @@ -2527,6 +2527,7 @@ impl [T] { /// let v = [10, 40, 30]; /// assert!(v.starts_with(&[10])); /// assert!(v.starts_with(&[10, 40])); + /// assert!(v.starts_with(&v)); /// assert!(!v.starts_with(&[50])); /// assert!(!v.starts_with(&[10, 50])); /// ``` @@ -2549,7 +2550,7 @@ impl [T] { self.len() >= n && needle == &self[..n] } - /// Returns `true` if `needle` is a suffix of the slice. + /// Returns `true` if `needle` is a suffix of the slice or equal to the slice. /// /// # Examples /// @@ -2557,6 +2558,7 @@ impl [T] { /// let v = [10, 40, 30]; /// assert!(v.ends_with(&[30])); /// assert!(v.ends_with(&[40, 30])); + /// assert!(v.ends_with(&v)); /// assert!(!v.ends_with(&[50])); /// assert!(!v.ends_with(&[50, 30])); /// ``` @@ -2582,7 +2584,8 @@ impl [T] { /// Returns a subslice with the prefix removed. /// /// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`. - /// If `prefix` is empty, simply returns the original slice. + /// If `prefix` is empty, simply returns the original slice. If `prefix` is equal to the + /// original slice, returns an empty slice. /// /// If the slice does not start with `prefix`, returns `None`. /// @@ -2592,6 +2595,7 @@ impl [T] { /// let v = &[10, 40, 30]; /// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..])); /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..])); /// assert_eq!(v.strip_prefix(&[50]), None); /// assert_eq!(v.strip_prefix(&[10, 50]), None); /// @@ -2620,7 +2624,8 @@ impl [T] { /// Returns a subslice with the suffix removed. /// /// If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`. - /// If `suffix` is empty, simply returns the original slice. + /// If `suffix` is empty, simply returns the original slice. If `suffix` is equal to the + /// original slice, returns an empty slice. /// /// If the slice does not end with `suffix`, returns `None`. /// @@ -2630,6 +2635,7 @@ impl [T] { /// let v = &[10, 40, 30]; /// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..])); /// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..])); + /// assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..])); /// assert_eq!(v.strip_suffix(&[50]), None); /// assert_eq!(v.strip_suffix(&[50, 30]), None); /// ``` From 5e11a99bb662629cc7d0ad3ce7475b7738c9c2cb Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 15 Feb 2024 04:22:56 +0100 Subject: [PATCH 02/18] Remove hacky branch in `sort_candidate` Reusing `self.test` wasn't actually pulling a lot of weight. --- .../rustc_mir_build/src/build/matches/test.rs | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 1c97de58863..a97d0de27e3 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -673,6 +673,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } } + (TestKind::Len { .. }, _) => { + fully_matched = false; + None + } (TestKind::Range(test), &TestCase::Range(pat)) => { if test.as_ref() == pat { @@ -700,29 +704,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None } - (&TestKind::Eq { .. } | &TestKind::Len { .. }, _) => { - // The call to `self.test(&match_pair)` below is not actually used to generate any - // MIR. Instead, we just want to compare with `test` (the parameter of the method) - // to see if it is the same. - // - // However, at this point we can still encounter or-patterns that were extracted - // from previous calls to `sort_candidate`, so we need to manually address that - // case to avoid panicking in `self.test()`. - if let TestCase::Or { .. } = &match_pair.test_case { - return None; - } - - // These are all binary tests. - // - // FIXME(#29623) we can be more clever here - let pattern_test = self.test(match_pair); - if pattern_test.kind == test.kind { - fully_matched = true; - Some(0) - } else { - fully_matched = false; - None - } + // FIXME(#29623): return `Some(1)` when the values are different. + (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) + if test_val == case_val => + { + fully_matched = true; + Some(0) + } + (TestKind::Eq { .. }, _) => { + fully_matched = false; + None } }; From f363c1a3fe58f66924955755a6408dd1caedbdac Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Feb 2024 22:59:11 +0100 Subject: [PATCH 03/18] Group default cases in `sort_candidate` --- .../rustc_mir_build/src/build/matches/test.rs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index a97d0de27e3..3712b8fb95b 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -575,10 +575,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fully_matched = true; Some(variant_index.as_usize()) } - (&TestKind::Switch { .. }, _) => { - fully_matched = false; - None - } // If we are performing a switch over integers, then this informs integer // equality, but nothing else. @@ -603,10 +599,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { options.len() }) } - (&TestKind::SwitchInt { .. }, _) => { - fully_matched = false; - None - } ( &TestKind::Len { len: test_len, op: BinOp::Eq }, @@ -673,10 +665,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } } - (TestKind::Len { .. }, _) => { - fully_matched = false; - None - } (TestKind::Range(test), &TestCase::Range(pat)) => { if test.as_ref() == pat { @@ -699,10 +687,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None } } - (&TestKind::Range { .. }, _) => { - fully_matched = false; - None - } // FIXME(#29623): return `Some(1)` when the values are different. (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) @@ -711,7 +695,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fully_matched = true; Some(0) } - (TestKind::Eq { .. }, _) => { + + ( + TestKind::Switch { .. } + | TestKind::SwitchInt { .. } + | TestKind::Len { .. } + | TestKind::Range { .. } + | TestKind::Eq { .. }, + _, + ) => { fully_matched = false; None } From 9d713862521f70c610b687d1629ee8fc4fb1e5ce Mon Sep 17 00:00:00 2001 From: Qiu Chaofan Date: Wed, 28 Feb 2024 17:41:12 +0800 Subject: [PATCH 04/18] Add profiling support to AIX AIX ld needs special option to merge objects with profiling. Also, profiler_builtins should include builtins for AIX from compiler-rt. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 4 +++- library/profiler_builtins/build.rs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 1f3383815e2..e52efd86955 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1631,7 +1631,9 @@ impl<'a> Linker for AixLinker<'a> { fn optimize(&mut self) {} - fn pgo_gen(&mut self) {} + fn pgo_gen(&mut self) { + self.cmd.arg("-bdbg:namedsects:ss"); + } fn control_flow_guard(&mut self) {} diff --git a/library/profiler_builtins/build.rs b/library/profiler_builtins/build.rs index 8e7b72f8372..9d1c1ba305b 100644 --- a/library/profiler_builtins/build.rs +++ b/library/profiler_builtins/build.rs @@ -26,6 +26,7 @@ fn main() { "InstrProfilingMerge.c", "InstrProfilingMergeFile.c", "InstrProfilingNameVar.c", + "InstrProfilingPlatformAIX.c", "InstrProfilingPlatformDarwin.c", "InstrProfilingPlatformFuchsia.c", "InstrProfilingPlatformLinux.c", From d6332ae79cf43b9c6ea74478cc5a4333dae685bb Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 28 Feb 2024 17:46:31 +0100 Subject: [PATCH 05/18] Separate the `bool` case from other integers in `TestKind` --- .../rustc_mir_build/src/build/matches/mod.rs | 17 ++-- .../rustc_mir_build/src/build/matches/test.rs | 77 +++++++++---------- ...fg-initial.after-ElaborateDrops.after.diff | 15 ++-- ...fg-initial.after-ElaborateDrops.after.diff | 15 ++-- 4 files changed, 59 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 641a278c1d3..e94489b8189 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1091,21 +1091,18 @@ enum TestKind<'tcx> { variants: BitSet, }, - /// Test what value an integer, `bool`, or `char` has. + /// Test what value an integer or `char` has. SwitchInt { - /// The type of the value that we're testing. - switch_ty: Ty<'tcx>, /// The (ordered) set of values that we test for. /// - /// For integers and `char`s we create a branch to each of the values in - /// `options`, as well as an "otherwise" branch for all other values, even - /// in the (rare) case that `options` is exhaustive. - /// - /// For `bool` we always generate two edges, one for `true` and one for - /// `false`. + /// We create a branch to each of the values in `options`, as well as an "otherwise" branch + /// for all other values, even in the (rare) case that `options` is exhaustive. options: FxIndexMap, u128>, }, + /// Test what value a `bool` has. + If, + /// Test for equality with value, possibly after an unsizing coercion to /// `ty`, Eq { @@ -1611,7 +1608,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // a test like SwitchInt, we may want to add cases based on the candidates that are // available match test.kind { - TestKind::SwitchInt { switch_ty: _, ref mut options } => { + TestKind::SwitchInt { ref mut options } => { for candidate in candidates.iter() { if !self.add_cases_to_switch(&match_place, candidate, options) { break; diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 1c97de58863..7a5a8a1a81a 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -34,12 +34,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) } } + TestCase::Constant { .. } if match_pair.pattern.ty.is_bool() => TestKind::If, + TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => { // For integers, we use a `SwitchInt` match, which allows // us to handle more cases. TestKind::SwitchInt { - switch_ty: match_pair.pattern.ty, - // these maps are empty to start; cases are // added below in add_cases_to_switch options: Default::default(), @@ -182,34 +182,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } - TestKind::SwitchInt { switch_ty, ref options } => { - let terminator = if *switch_ty.kind() == ty::Bool { - assert!(!options.is_empty() && options.len() <= 2); - let [first_bb, second_bb] = *target_blocks else { - bug!("`TestKind::SwitchInt` on `bool` should have two targets") - }; - let (true_bb, false_bb) = match options[0] { - 1 => (first_bb, second_bb), - 0 => (second_bb, first_bb), - v => span_bug!(test.span, "expected boolean value but got {:?}", v), - }; - TerminatorKind::if_(Operand::Copy(place), true_bb, false_bb) - } else { - // The switch may be inexhaustive so we have a catch all block - debug_assert_eq!(options.len() + 1, target_blocks.len()); - let otherwise_block = *target_blocks.last().unwrap(); - let switch_targets = SwitchTargets::new( - options.values().copied().zip(target_blocks), - otherwise_block, - ); - TerminatorKind::SwitchInt { - discr: Operand::Copy(place), - targets: switch_targets, - } + TestKind::SwitchInt { ref options } => { + // The switch may be inexhaustive so we have a catch-all block + debug_assert_eq!(options.len() + 1, target_blocks.len()); + let otherwise_block = *target_blocks.last().unwrap(); + let switch_targets = SwitchTargets::new( + options.values().copied().zip(target_blocks), + otherwise_block, + ); + let terminator = TerminatorKind::SwitchInt { + discr: Operand::Copy(place), + targets: switch_targets, }; self.cfg.terminate(block, self.source_info(match_start_span), terminator); } + TestKind::If => { + let [false_bb, true_bb] = *target_blocks else { + bug!("`TestKind::If` should have two targets") + }; + let terminator = TerminatorKind::if_(Operand::Copy(place), true_bb, false_bb); + self.cfg.terminate(block, self.source_info(match_start_span), terminator); + } + TestKind::Eq { value, ty } => { let tcx = self.tcx; let [success_block, fail_block] = *target_blocks else { @@ -585,14 +580,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // FIXME(#29623) we could use PatKind::Range to rule // things out here, in some cases. - (TestKind::SwitchInt { switch_ty: _, options }, TestCase::Constant { value }) + (TestKind::SwitchInt { options }, TestCase::Constant { value }) if is_switch_ty(match_pair.pattern.ty) => { fully_matched = true; let index = options.get_index_of(value).unwrap(); Some(index) } - (TestKind::SwitchInt { switch_ty: _, options }, TestCase::Range(range)) => { + (TestKind::SwitchInt { options }, TestCase::Range(range)) => { fully_matched = false; let not_contained = self.values_not_contained_in_range(&*range, options).unwrap_or(false); @@ -608,6 +603,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None } + (&TestKind::If, TestCase::Constant { value }) => { + fully_matched = true; + let value = value.try_eval_bool(self.tcx, self.param_env).unwrap_or_else(|| { + span_bug!(test.span, "expected boolean value but got {value:?}") + }); + Some(value as usize) + } + (&TestKind::If, _) => { + fully_matched = false; + None + } + ( &TestKind::Len { len: test_len, op: BinOp::Eq }, &TestCase::Slice { len, variable_length }, @@ -755,7 +762,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { impl Test<'_> { pub(super) fn targets(&self) -> usize { match self.kind { - TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } => 2, + TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } | TestKind::If => 2, TestKind::Switch { adt_def, .. } => { // While the switch that we generate doesn't test for all // variants, we have a target for each variant and the @@ -763,21 +770,13 @@ impl Test<'_> { // specified have the same block. adt_def.variants().len() + 1 } - TestKind::SwitchInt { switch_ty, ref options, .. } => { - if switch_ty.is_bool() { - // `bool` is special cased in `perform_test` to always - // branch to two blocks. - 2 - } else { - options.len() + 1 - } - } + TestKind::SwitchInt { ref options } => options.len() + 1, } } } fn is_switch_ty(ty: Ty<'_>) -> bool { - ty.is_integral() || ty.is_char() || ty.is_bool() + ty.is_integral() || ty.is_char() } fn trait_method<'tcx>( diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 307f7105dd2..619fda339a6 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -42,15 +42,11 @@ } bb2: { -- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3]; +- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4]; + switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; } bb3: { -- falseEdge -> [real: bb20, imaginary: bb4]; -- } -- -- bb4: { StorageLive(_15); _15 = (_2.1: bool); StorageLive(_16); @@ -59,8 +55,12 @@ + goto -> bb16; } + bb4: { +- falseEdge -> [real: bb20, imaginary: bb3]; +- } +- - bb5: { -- falseEdge -> [real: bb13, imaginary: bb3]; +- falseEdge -> [real: bb13, imaginary: bb4]; - } - - bb6: { @@ -68,7 +68,6 @@ - } - - bb7: { -+ bb4: { _0 = const 1_i32; - drop(_7) -> [return: bb18, unwind: bb25]; + drop(_7) -> [return: bb15, unwind: bb22]; @@ -184,7 +183,7 @@ StorageDead(_12); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb2, imaginary: bb3]; +- falseEdge -> [real: bb2, imaginary: bb4]; + goto -> bb2; } diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 307f7105dd2..619fda339a6 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -42,15 +42,11 @@ } bb2: { -- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3]; +- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4]; + switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17]; } bb3: { -- falseEdge -> [real: bb20, imaginary: bb4]; -- } -- -- bb4: { StorageLive(_15); _15 = (_2.1: bool); StorageLive(_16); @@ -59,8 +55,12 @@ + goto -> bb16; } + bb4: { +- falseEdge -> [real: bb20, imaginary: bb3]; +- } +- - bb5: { -- falseEdge -> [real: bb13, imaginary: bb3]; +- falseEdge -> [real: bb13, imaginary: bb4]; - } - - bb6: { @@ -68,7 +68,6 @@ - } - - bb7: { -+ bb4: { _0 = const 1_i32; - drop(_7) -> [return: bb18, unwind: bb25]; + drop(_7) -> [return: bb15, unwind: bb22]; @@ -184,7 +183,7 @@ StorageDead(_12); StorageDead(_8); StorageDead(_6); -- falseEdge -> [real: bb2, imaginary: bb3]; +- falseEdge -> [real: bb2, imaginary: bb4]; + goto -> bb2; } From e6f48fa0bb2c66bb29661bc81d4df5fadad32515 Mon Sep 17 00:00:00 2001 From: yukang Date: Fri, 16 Feb 2024 00:25:56 +0800 Subject: [PATCH 06/18] Suggest removing superfluous semicolos when statements used as expressions --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 6 +- .../src/fn_ctxt/suggestions.rs | 2 +- .../src/infer/error_reporting/mod.rs | 1 + .../src/infer/error_reporting/suggest.rs | 96 +++++++++++++ .../ui/inference/issue-105431-stmts-as-exp.rs | 76 +++++++++++ .../issue-105431-stmts-as-exp.stderr | 129 ++++++++++++++++++ 6 files changed, 308 insertions(+), 2 deletions(-) create mode 100644 tests/ui/inference/issue-105431-stmts-as-exp.rs create mode 100644 tests/ui/inference/issue-105431-stmts-as-exp.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 61c52422d19..bf58840f0f9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1744,7 +1744,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_unit(self.tcx), ); } - if !self.consider_removing_semicolon(blk, expected_ty, err) { + if !self.err_ctxt().consider_removing_semicolon( + blk, + expected_ty, + err, + ) { self.err_ctxt().consider_returning_binding( blk, expected_ty, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index ccd9b38bf62..d5161b00fbc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -22,7 +22,7 @@ use rustc_hir::{ Path, QPath, Stmt, StmtKind, TyKind, WherePredicate, }; use rustc_hir_analysis::astconv::AstConv; -use rustc_infer::traits::{self, StatementAsExpression}; +use rustc_infer::traits::{self}; use rustc_middle::lint::in_external_macro; use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::print::with_no_trimmed_paths; diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 911b2f16c8b..6bb8c119942 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1976,6 +1976,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag); self.suggest_await_on_expect_found(cause, span, &exp_found, diag); self.suggest_function_pointers(cause, span, &exp_found, diag); + self.suggest_for_statments_as_exp(cause, &exp_found, diag); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index cfe8b75bdd7..be2437bfd60 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -1,8 +1,13 @@ +use crate::infer::error_reporting::hir::Path; use hir::def::CtorKind; use hir::intravisit::{walk_expr, walk_stmt, Visitor}; +use hir::{Local, QPath}; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::MatchSource; +use rustc_hir::Node; use rustc_middle::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, StatementAsExpression, @@ -293,6 +298,97 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } + pub(super) fn suggest_for_statments_as_exp( + &self, + cause: &ObligationCause<'tcx>, + exp_found: &ty::error::ExpectedFound>, + diag: &mut Diagnostic, + ) { + let ty::error::ExpectedFound { expected, found } = exp_found; + if !found.peel_refs().is_unit() { + return; + } + + let ObligationCauseCode::BlockTailExpression(hir_id, MatchSource::Normal) = cause.code() + else { + return; + }; + + let node = self.tcx.hir_node(*hir_id); + let mut blocks = vec![]; + if let hir::Node::Block(block) = node + && let Some(expr) = block.expr + && let hir::ExprKind::Path(QPath::Resolved(_, Path { res, .. })) = expr.kind + && let Res::Local(local) = res + && let Node::Local(Local { init: Some(init), .. }) = self.tcx.parent_hir_node(*local) + { + fn collect_blocks<'hir>(expr: &hir::Expr<'hir>, blocks: &mut Vec<&hir::Block<'hir>>) { + match expr.kind { + // `blk1` and `blk2` must be have the same types, it will be reported before reaching here + hir::ExprKind::If(_, blk1, Some(blk2)) => { + collect_blocks(blk1, blocks); + collect_blocks(blk2, blocks); + } + hir::ExprKind::Match(_, arms, _) => { + // all arms must have same types + for arm in arms.iter() { + collect_blocks(arm.body, blocks); + } + } + hir::ExprKind::Block(blk, _) => { + blocks.push(blk); + } + _ => {} + } + } + collect_blocks(init, &mut blocks); + } + + let expected_inner: Ty<'_> = expected.peel_refs(); + for block in blocks.iter() { + self.consider_removing_semicolon(block, expected_inner, diag); + } + } + + /// A common error is to add an extra semicolon: + /// + /// ```compile_fail,E0308 + /// fn foo() -> usize { + /// 22; + /// } + /// ``` + /// + /// This routine checks if the final statement in a block is an + /// expression with an explicit semicolon whose type is compatible + /// with `expected_ty`. If so, it suggests removing the semicolon. + pub fn consider_removing_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + err: &mut Diagnostic, + ) -> bool { + if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) { + if let StatementAsExpression::NeedsBoxing = boxed { + err.span_suggestion_verbose( + span_semi, + "consider removing this semicolon and boxing the expression", + "", + Applicability::HasPlaceholders, + ); + } else { + err.span_suggestion_short( + span_semi, + "remove this semicolon to return this value", + "", + Applicability::MachineApplicable, + ); + } + true + } else { + false + } + } + pub(super) fn suggest_function_pointers( &self, cause: &ObligationCause<'tcx>, diff --git a/tests/ui/inference/issue-105431-stmts-as-exp.rs b/tests/ui/inference/issue-105431-stmts-as-exp.rs new file mode 100644 index 00000000000..b5adb4a2b66 --- /dev/null +++ b/tests/ui/inference/issue-105431-stmts-as-exp.rs @@ -0,0 +1,76 @@ +#![allow(unused)] + +fn test_if() -> i32 { + let x = if true { + eprintln!("hello"); + 3; + } + else { + 4; + }; + x //~ ERROR mismatched types +} + +fn test_if_without_binding() -> i32 { + if true { //~ ERROR mismatched types + eprintln!("hello"); + 3; + } + else { //~ ERROR mismatched types + 4; + } +} + +fn test_match() -> i32 { + let v = 1; + let res = match v { + 1 => { 1; } + _ => { 2; } + }; + res //~ ERROR mismatched types +} + +fn test_match_match_without_binding() -> i32 { + let v = 1; + match v { + 1 => { 1; } //~ ERROR mismatched types + _ => { 2; } //~ ERROR mismatched types + } +} + +fn test_match_arm_different_types() -> i32 { + let v = 1; + let res = match v { + 1 => { if 1 < 2 { 1 } else { 2 } } + _ => { 2; } //~ ERROR `match` arms have incompatible types + }; + res +} + +fn test_if_match_mixed() -> i32 { + let x = if true { + 3; + } else { + match 1 { + 1 => { 1 } + _ => { 2 } + }; + }; + x //~ ERROR mismatched types +} + +fn test_if_match_mixed_failed() -> i32 { + let x = if true { + 3; + } else { + // because this is a tailed expr, so we won't check deeper + match 1 { + 1 => { 33; } + _ => { 44; } + } + }; + x //~ ERROR mismatched types +} + + +fn main() {} diff --git a/tests/ui/inference/issue-105431-stmts-as-exp.stderr b/tests/ui/inference/issue-105431-stmts-as-exp.stderr new file mode 100644 index 00000000000..2878d602ec5 --- /dev/null +++ b/tests/ui/inference/issue-105431-stmts-as-exp.stderr @@ -0,0 +1,129 @@ +error[E0308]: mismatched types + --> $DIR/issue-105431-stmts-as-exp.rs:11:5 + | +LL | fn test_if() -> i32 { + | --- expected `i32` because of return type +... +LL | x + | ^ expected `i32`, found `()` + | +help: remove this semicolon to return this value + | +LL - 3; +LL + 3 + | +help: remove this semicolon to return this value + | +LL - 4; +LL + 4 + | + +error[E0308]: mismatched types + --> $DIR/issue-105431-stmts-as-exp.rs:15:13 + | +LL | if true { + | _____________^ +LL | | eprintln!("hello"); +LL | | 3; + | | - help: remove this semicolon to return this value +LL | | } + | |_____^ expected `i32`, found `()` + +error[E0308]: mismatched types + --> $DIR/issue-105431-stmts-as-exp.rs:19:10 + | +LL | else { + | __________^ +LL | | 4; + | | - help: remove this semicolon to return this value +LL | | } + | |_____^ expected `i32`, found `()` + +error[E0308]: mismatched types + --> $DIR/issue-105431-stmts-as-exp.rs:30:5 + | +LL | fn test_match() -> i32 { + | --- expected `i32` because of return type +... +LL | res + | ^^^ expected `i32`, found `()` + | +help: remove this semicolon to return this value + | +LL - 1 => { 1; } +LL + 1 => { 1 } + | +help: remove this semicolon to return this value + | +LL - _ => { 2; } +LL + _ => { 2 } + | + +error[E0308]: mismatched types + --> $DIR/issue-105431-stmts-as-exp.rs:36:14 + | +LL | 1 => { 1; } + | ^^^-^^ + | | | + | | help: remove this semicolon to return this value + | expected `i32`, found `()` + +error[E0308]: mismatched types + --> $DIR/issue-105431-stmts-as-exp.rs:37:14 + | +LL | _ => { 2; } + | ^^^-^^ + | | | + | | help: remove this semicolon to return this value + | expected `i32`, found `()` + +error[E0308]: `match` arms have incompatible types + --> $DIR/issue-105431-stmts-as-exp.rs:45:16 + | +LL | let res = match v { + | _______________- +LL | | 1 => { if 1 < 2 { 1 } else { 2 } } + | | ------------------------- this is found to be of type `{integer}` +LL | | _ => { 2; } + | | ^- + | | || + | | |help: consider removing this semicolon + | | expected integer, found `()` +LL | | }; + | |_____- `match` arms have incompatible types + +error[E0308]: mismatched types + --> $DIR/issue-105431-stmts-as-exp.rs:59:5 + | +LL | fn test_if_match_mixed() -> i32 { + | --- expected `i32` because of return type +... +LL | x + | ^ expected `i32`, found `()` + | +help: remove this semicolon to return this value + | +LL - 3; +LL + 3 + | +help: remove this semicolon to return this value + | +LL - }; +LL + } + | + +error[E0308]: mismatched types + --> $DIR/issue-105431-stmts-as-exp.rs:72:5 + | +LL | fn test_if_match_mixed_failed() -> i32 { + | --- expected `i32` because of return type +LL | let x = if true { +LL | 3; + | - help: remove this semicolon to return this value +... +LL | x + | ^ expected `i32`, found `()` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0308`. From e2ce5d74a5f87f9fb6baadd191288025ed974296 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 21 Feb 2024 09:37:45 +0800 Subject: [PATCH 07/18] renaming test cases --- .../src/fn_ctxt/suggestions.rs | 39 ------------------- .../src/infer/error_reporting/mod.rs | 2 +- .../src/infer/error_reporting/suggest.rs | 10 ++--- ...stmts-as-exp.rs => stmts-as-exp-105431.rs} | 0 ...-exp.stderr => stmts-as-exp-105431.stderr} | 18 ++++----- 5 files changed, 15 insertions(+), 54 deletions(-) rename tests/ui/inference/{issue-105431-stmts-as-exp.rs => stmts-as-exp-105431.rs} (100%) rename tests/ui/inference/{issue-105431-stmts-as-exp.stderr => stmts-as-exp-105431.stderr} (88%) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index d5161b00fbc..809102557ac 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1791,45 +1791,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// A common error is to add an extra semicolon: - /// - /// ```compile_fail,E0308 - /// fn foo() -> usize { - /// 22; - /// } - /// ``` - /// - /// This routine checks if the final statement in a block is an - /// expression with an explicit semicolon whose type is compatible - /// with `expected_ty`. If so, it suggests removing the semicolon. - pub(crate) fn consider_removing_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - err: &mut Diag<'_>, - ) -> bool { - if let Some((span_semi, boxed)) = self.err_ctxt().could_remove_semicolon(blk, expected_ty) { - if let StatementAsExpression::NeedsBoxing = boxed { - err.span_suggestion_verbose( - span_semi, - "consider removing this semicolon and boxing the expression", - "", - Applicability::HasPlaceholders, - ); - } else { - err.span_suggestion_short( - span_semi, - "remove this semicolon to return this value", - "", - Applicability::MachineApplicable, - ); - } - true - } else { - false - } - } - pub(crate) fn is_field_suggestable( &self, field: &ty::FieldDef, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 6bb8c119942..e19879ae06d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1976,7 +1976,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag); self.suggest_await_on_expect_found(cause, span, &exp_found, diag); self.suggest_function_pointers(cause, span, &exp_found, diag); - self.suggest_for_statments_as_exp(cause, &exp_found, diag); + self.suggest_turning_stmt_into_expr(cause, &exp_found, diag); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index be2437bfd60..472dab639d5 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -298,11 +298,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - pub(super) fn suggest_for_statments_as_exp( + pub(super) fn suggest_turning_stmt_into_expr( &self, cause: &ObligationCause<'tcx>, exp_found: &ty::error::ExpectedFound>, - diag: &mut Diagnostic, + diag: &mut Diag<'_>, ) { let ty::error::ExpectedFound { expected, found } = exp_found; if !found.peel_refs().is_unit() { @@ -365,18 +365,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, - err: &mut Diagnostic, + diag: &mut Diag<'_>, ) -> bool { if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) { if let StatementAsExpression::NeedsBoxing = boxed { - err.span_suggestion_verbose( + diag.span_suggestion_verbose( span_semi, "consider removing this semicolon and boxing the expression", "", Applicability::HasPlaceholders, ); } else { - err.span_suggestion_short( + diag.span_suggestion_short( span_semi, "remove this semicolon to return this value", "", diff --git a/tests/ui/inference/issue-105431-stmts-as-exp.rs b/tests/ui/inference/stmts-as-exp-105431.rs similarity index 100% rename from tests/ui/inference/issue-105431-stmts-as-exp.rs rename to tests/ui/inference/stmts-as-exp-105431.rs diff --git a/tests/ui/inference/issue-105431-stmts-as-exp.stderr b/tests/ui/inference/stmts-as-exp-105431.stderr similarity index 88% rename from tests/ui/inference/issue-105431-stmts-as-exp.stderr rename to tests/ui/inference/stmts-as-exp-105431.stderr index 2878d602ec5..f3da04b39a3 100644 --- a/tests/ui/inference/issue-105431-stmts-as-exp.stderr +++ b/tests/ui/inference/stmts-as-exp-105431.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-105431-stmts-as-exp.rs:11:5 + --> $DIR/stmts-as-exp-105431.rs:11:5 | LL | fn test_if() -> i32 { | --- expected `i32` because of return type @@ -19,7 +19,7 @@ LL + 4 | error[E0308]: mismatched types - --> $DIR/issue-105431-stmts-as-exp.rs:15:13 + --> $DIR/stmts-as-exp-105431.rs:15:13 | LL | if true { | _____________^ @@ -30,7 +30,7 @@ LL | | } | |_____^ expected `i32`, found `()` error[E0308]: mismatched types - --> $DIR/issue-105431-stmts-as-exp.rs:19:10 + --> $DIR/stmts-as-exp-105431.rs:19:10 | LL | else { | __________^ @@ -40,7 +40,7 @@ LL | | } | |_____^ expected `i32`, found `()` error[E0308]: mismatched types - --> $DIR/issue-105431-stmts-as-exp.rs:30:5 + --> $DIR/stmts-as-exp-105431.rs:30:5 | LL | fn test_match() -> i32 { | --- expected `i32` because of return type @@ -60,7 +60,7 @@ LL + _ => { 2 } | error[E0308]: mismatched types - --> $DIR/issue-105431-stmts-as-exp.rs:36:14 + --> $DIR/stmts-as-exp-105431.rs:36:14 | LL | 1 => { 1; } | ^^^-^^ @@ -69,7 +69,7 @@ LL | 1 => { 1; } | expected `i32`, found `()` error[E0308]: mismatched types - --> $DIR/issue-105431-stmts-as-exp.rs:37:14 + --> $DIR/stmts-as-exp-105431.rs:37:14 | LL | _ => { 2; } | ^^^-^^ @@ -78,7 +78,7 @@ LL | _ => { 2; } | expected `i32`, found `()` error[E0308]: `match` arms have incompatible types - --> $DIR/issue-105431-stmts-as-exp.rs:45:16 + --> $DIR/stmts-as-exp-105431.rs:45:16 | LL | let res = match v { | _______________- @@ -93,7 +93,7 @@ LL | | }; | |_____- `match` arms have incompatible types error[E0308]: mismatched types - --> $DIR/issue-105431-stmts-as-exp.rs:59:5 + --> $DIR/stmts-as-exp-105431.rs:59:5 | LL | fn test_if_match_mixed() -> i32 { | --- expected `i32` because of return type @@ -113,7 +113,7 @@ LL + } | error[E0308]: mismatched types - --> $DIR/issue-105431-stmts-as-exp.rs:72:5 + --> $DIR/stmts-as-exp-105431.rs:72:5 | LL | fn test_if_match_mixed_failed() -> i32 { | --- expected `i32` because of return type From 5ec9b8d778b91cb579dc177eedaff4ba69bba33f Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 23 Feb 2024 10:12:08 +0100 Subject: [PATCH 08/18] distinguish recursion limit based overflow for diagnostics also change the number of allowed fixpoint steps to be fixed instead of using the `log` of the total recursion depth. --- compiler/rustc_infer/src/traits/mod.rs | 10 +++--- .../src/traits/structural_impls.rs | 6 ++-- compiler/rustc_middle/src/traits/solve.rs | 30 +++++++++++------ .../src/solve/alias_relate.rs | 6 ++-- .../src/solve/eval_ctxt/mod.rs | 33 +++++++++---------- .../src/solve/fulfill.rs | 11 ++++--- .../rustc_trait_selection/src/solve/mod.rs | 11 +++++++ .../src/solve/search_graph.rs | 21 +++++------- .../error_reporting/type_err_ctxt_ext.rs | 14 +++++--- .../src/traits/fulfill.rs | 2 +- .../trait-bounds/issue-95230.next.stderr | 1 - .../inherent-impls-overflow.next.stderr | 2 -- .../next-solver/alias-bound-unsound.stderr | 10 ------ ...trait_ref_is_knowable-norm-overflow.stderr | 3 ++ .../fixpoint-exponential-growth.stderr | 1 - .../double-cycle-inductive-coinductive.stderr | 2 -- .../cycles/inductive-fixpoint-hang.stderr | 1 - .../cycles/inductive-not-on-stack.stderr | 2 -- .../next-solver/cycles/mixed-cycles-1.stderr | 1 - .../next-solver/cycles/mixed-cycles-2.stderr | 1 - .../next-solver/normalize-param-env-2.stderr | 8 ----- .../normalize-param-env-4.next.stderr | 5 --- .../overflow/exponential-trait-goals.stderr | 1 - .../recursion-limit-zero-issue-115351.rs | 7 +--- .../recursion-limit-zero-issue-115351.stderr | 27 --------------- 25 files changed, 91 insertions(+), 125 deletions(-) delete mode 100644 tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 72ec07375ac..4808a1defdd 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -135,16 +135,18 @@ pub struct FulfillmentError<'tcx> { #[derive(Clone)] pub enum FulfillmentErrorCode<'tcx> { - /// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented. + /// Inherently impossible to fulfill; this trait is implemented if and only + /// if it is already implemented. Cycle(Vec>), SelectionError(SelectionError<'tcx>), ProjectionError(MismatchedProjectionTypes<'tcx>), SubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate ConstEquateError(ExpectedFound>, TypeError<'tcx>), Ambiguity { - /// Overflow reported from the new solver `-Znext-solver`, which will - /// be reported as an regular error as opposed to a fatal error. - overflow: bool, + /// Overflow is only `Some(suggest_recursion_limit)` when using the next generation + /// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by + /// emitting a fatal error instead. + overflow: Option, }, } diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 3b4050fcd27..bf4f88530d0 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -47,8 +47,10 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { ConstEquateError(ref a, ref b) => { write!(f, "CodeConstEquateError({a:?}, {b:?})") } - Ambiguity { overflow: false } => write!(f, "Ambiguity"), - Ambiguity { overflow: true } => write!(f, "Overflow"), + Ambiguity { overflow: None } => write!(f, "Ambiguity"), + Ambiguity { overflow: Some(suggest_increasing_limit) } => { + write!(f, "Overflow({suggest_increasing_limit})") + } Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"), } } diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 048df367bd6..0dc65126011 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -60,7 +60,6 @@ pub enum Certainty { impl Certainty { pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity); - pub const OVERFLOW: Certainty = Certainty::Maybe(MaybeCause::Overflow); /// Use this function to merge the certainty of multiple nested subgoals. /// @@ -79,16 +78,13 @@ impl Certainty { (Certainty::Yes, Certainty::Yes) => Certainty::Yes, (Certainty::Yes, Certainty::Maybe(_)) => other, (Certainty::Maybe(_), Certainty::Yes) => self, - (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => { - Certainty::Maybe(MaybeCause::Ambiguity) - } - (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow)) - | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity)) - | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => { - Certainty::Maybe(MaybeCause::Overflow) - } + (Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)), } } + + pub const fn overflow(suggest_increasing_limit: bool) -> Certainty { + Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }) + } } /// Why we failed to evaluate a goal. @@ -99,7 +95,21 @@ pub enum MaybeCause { /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals. Ambiguity, /// We gave up due to an overflow, most often by hitting the recursion limit. - Overflow, + Overflow { suggest_increasing_limit: bool }, +} + +impl MaybeCause { + fn unify_with(self, other: MaybeCause) -> MaybeCause { + match (self, other) { + (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity, + (MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other, + (MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self, + ( + MaybeCause::Overflow { suggest_increasing_limit: a }, + MaybeCause::Overflow { suggest_increasing_limit: b }, + ) => MaybeCause::Overflow { suggest_increasing_limit: a || b }, + } + } } #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index afd9d95cb57..67657c81cf6 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -36,11 +36,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; let Some(lhs) = self.try_normalize_term(param_env, lhs)? else { - return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW); + return self + .evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true)); }; let Some(rhs) = self.try_normalize_term(param_env, rhs)? else { - return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW); + return self + .evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true)); }; let variance = match direction { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index ed428bb8e66..e20cec18790 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -7,6 +7,7 @@ use rustc_infer::infer::{ BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt, }; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::solve::MaybeCause; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; @@ -29,7 +30,7 @@ use std::ops::ControlFlow; use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; use super::inspect::ProofTreeBuilder; -use super::{search_graph, GoalEvaluationKind}; +use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT}; use super::{search_graph::SearchGraph, Goal}; use super::{GoalSource, SolverMode}; pub use select::InferCtxtSelectExt; @@ -154,10 +155,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { self.search_graph.solver_mode() } - pub(super) fn local_overflow_limit(&self) -> usize { - self.search_graph.local_overflow_limit() - } - /// Creates a root evaluation context and search graph. This should only be /// used from outside of any evaluation, and other methods should be preferred /// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]). @@ -167,7 +164,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R, ) -> (R, Option>) { let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; - let mut search_graph = search_graph::SearchGraph::new(infcx.tcx, mode); + let mut search_graph = search_graph::SearchGraph::new(mode); let mut ecx = EvalCtxt { search_graph: &mut search_graph, @@ -388,16 +385,18 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { && source != GoalSource::ImplWhereBound }; - if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() { - (Certainty::OVERFLOW, false) - } else { - let has_changed = !response.value.var_values.is_identity_modulo_regions() - || !response.value.external_constraints.opaque_types.is_empty(); - - let certainty = - self.instantiate_and_apply_query_response(param_env, original_values, response); - (certainty, has_changed) + if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty + && !keep_overflow_constraints() + { + return (response.value.certainty, false); } + + let has_changed = !response.value.var_values.is_identity_modulo_regions() + || !response.value.external_constraints.opaque_types.is_empty(); + + let certainty = + self.instantiate_and_apply_query_response(param_env, original_values, response); + (certainty, has_changed) } fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> { @@ -466,8 +465,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let inspect = self.inspect.new_evaluate_added_goals(); let inspect = core::mem::replace(&mut self.inspect, inspect); - let mut response = Ok(Certainty::OVERFLOW); - for _ in 0..self.local_overflow_limit() { + let mut response = Ok(Certainty::overflow(false)); + for _ in 0..FIXPOINT_STEP_LIMIT { // FIXME: This match is a bit ugly, it might be nice to change the inspect // stuff to use a closure instead. which should hopefully simplify this a bit. match self.evaluate_added_goals_step() { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index c1b07765e50..368e2e8810c 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -80,11 +80,14 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { .0 { Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { - FulfillmentErrorCode::Ambiguity { overflow: false } - } - Ok((_, Certainty::Maybe(MaybeCause::Overflow))) => { - FulfillmentErrorCode::Ambiguity { overflow: true } + FulfillmentErrorCode::Ambiguity { overflow: None } } + Ok(( + _, + Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }), + )) => FulfillmentErrorCode::Ambiguity { + overflow: Some(suggest_increasing_limit), + }, Ok((_, Certainty::Yes)) => { bug!("did not expect successful goal when collecting ambiguity errors") } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 51094b781c0..0bf28f520a4 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -42,6 +42,17 @@ pub use fulfill::FulfillmentCtxt; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +/// How many fixpoint iterations we should attempt inside of the solver before bailing +/// with overflow. +/// +/// We previously used `tcx.recursion_limit().0.checked_ilog2().unwrap_or(0)` for this. +/// However, it feels unlikely that uncreasing the recursion limit by a power of two +/// to get one more itereation is every useful or desirable. We now instead used a constant +/// here. If there ever ends up some use-cases where a bigger number of fixpoint iterations +/// is required, we can add a new attribute for that or revert this to be dependant on the +/// recursion limit again. However, this feels very unlikely. +const FIXPOINT_STEP_LIMIT: usize = 8; + #[derive(Debug, Clone, Copy)] enum SolverMode { /// Ordinary trait solving, using everywhere except for coherence. diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs index bede94a2e43..07a8aca85a0 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs @@ -1,3 +1,5 @@ +use crate::solve::FIXPOINT_STEP_LIMIT; + use super::inspect; use super::inspect::ProofTreeBuilder; use super::SolverMode; @@ -99,7 +101,6 @@ impl<'tcx> ProvisionalCacheEntry<'tcx> { pub(super) struct SearchGraph<'tcx> { mode: SolverMode, - local_overflow_limit: usize, /// The stack of goals currently being computed. /// /// An element is *deeper* in the stack if its index is *lower*. @@ -116,10 +117,9 @@ pub(super) struct SearchGraph<'tcx> { } impl<'tcx> SearchGraph<'tcx> { - pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> { + pub(super) fn new(mode: SolverMode) -> SearchGraph<'tcx> { Self { mode, - local_overflow_limit: tcx.recursion_limit().0.checked_ilog2().unwrap_or(0) as usize, stack: Default::default(), provisional_cache: Default::default(), cycle_participants: Default::default(), @@ -130,10 +130,6 @@ impl<'tcx> SearchGraph<'tcx> { self.mode } - pub(super) fn local_overflow_limit(&self) -> usize { - self.local_overflow_limit - } - /// Update the stack and reached depths on cache hits. #[instrument(level = "debug", skip(self))] fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) { @@ -277,7 +273,7 @@ impl<'tcx> SearchGraph<'tcx> { } inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow); - return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW); + return Self::response_no_constraints(tcx, input, Certainty::overflow(true)); }; // Try to fetch the goal from the global cache. @@ -370,7 +366,7 @@ impl<'tcx> SearchGraph<'tcx> { } else if is_coinductive_cycle { Self::response_no_constraints(tcx, input, Certainty::Yes) } else { - Self::response_no_constraints(tcx, input, Certainty::OVERFLOW) + Self::response_no_constraints(tcx, input, Certainty::overflow(false)) }; } else { // No entry, we push this goal on the stack and try to prove it. @@ -398,7 +394,7 @@ impl<'tcx> SearchGraph<'tcx> { // of this we continuously recompute the cycle until the result // of the previous iteration is equal to the final result, at which // point we are done. - for _ in 0..self.local_overflow_limit() { + for _ in 0..FIXPOINT_STEP_LIMIT { let result = prove_goal(self, inspect); let stack_entry = self.pop_stack(); debug_assert_eq!(stack_entry.input, input); @@ -431,7 +427,8 @@ impl<'tcx> SearchGraph<'tcx> { } else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE { Self::response_no_constraints(tcx, input, Certainty::Yes) == result } else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE { - Self::response_no_constraints(tcx, input, Certainty::OVERFLOW) == result + Self::response_no_constraints(tcx, input, Certainty::overflow(false)) + == result } else { false }; @@ -452,7 +449,7 @@ impl<'tcx> SearchGraph<'tcx> { debug!("canonical cycle overflow"); let current_entry = self.pop_stack(); debug_assert!(current_entry.has_been_used.is_empty()); - let result = Self::response_no_constraints(tcx, input, Certainty::OVERFLOW); + let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false)); (current_entry, result) }); 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 dcbb63f00f7..cbf52ea9e5a 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 @@ -335,12 +335,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } - fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed { + fn report_overflow_no_abort( + &self, + obligation: PredicateObligation<'tcx>, + suggest_increasing_limit: bool, + ) -> ErrorGuaranteed { let obligation = self.resolve_vars_if_possible(obligation); let mut err = self.build_overflow_error( OverflowCause::TraitSolver(obligation.predicate), obligation.cause.span, - true, + suggest_increasing_limit, ); self.note_obligation_cause(&mut err, &obligation); self.point_at_returns_when_relevant(&mut err, &obligation); @@ -1422,11 +1426,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { FulfillmentErrorCode::ProjectionError(ref e) => { self.report_projection_error(&error.obligation, e) } - FulfillmentErrorCode::Ambiguity { overflow: false } => { + FulfillmentErrorCode::Ambiguity { overflow: None } => { self.maybe_report_ambiguity(&error.obligation) } - FulfillmentErrorCode::Ambiguity { overflow: true } => { - self.report_overflow_no_abort(error.obligation.clone()) + FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => { + self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit) } FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self .report_mismatched_types( diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index b91698af942..2fd64f474d5 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -138,7 +138,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { _infcx: &InferCtxt<'tcx>, ) -> Vec> { self.predicates - .to_errors(FulfillmentErrorCode::Ambiguity { overflow: false }) + .to_errors(FulfillmentErrorCode::Ambiguity { overflow: None }) .into_iter() .map(to_fulfillment_error) .collect() diff --git a/tests/ui/higher-ranked/trait-bounds/issue-95230.next.stderr b/tests/ui/higher-ranked/trait-bounds/issue-95230.next.stderr index 6155579c9fa..9b0efe9abe6 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-95230.next.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-95230.next.stderr @@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `for<'a> &'a mut Bar well-form LL | for<'a> &'a mut Self:; | ^^^^^^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_95230`) note: required by a bound in `Bar` --> $DIR/issue-95230.rs:9:13 | diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr b/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr index 85e8061f173..80377bf6c20 100644 --- a/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr +++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr @@ -3,8 +3,6 @@ error[E0275]: overflow evaluating the requirement `Loop == _` | LL | impl Loop {} | ^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`) error[E0392]: type parameter `T` is never used --> $DIR/inherent-impls-overflow.rs:13:12 diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.stderr b/tests/ui/traits/next-solver/alias-bound-unsound.stderr index 2408e05728a..a5c2f215134 100644 --- a/tests/ui/traits/next-solver/alias-bound-unsound.stderr +++ b/tests/ui/traits/next-solver/alias-bound-unsound.stderr @@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `String: Copy` LL | type Item = String where String: Copy; | ^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) note: the requirement `String: Copy` appears on the `impl`'s associated type `Item` but not on the corresponding trait's associated type --> $DIR/alias-bound-unsound.rs:8:10 | @@ -18,32 +17,24 @@ error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item` | LL | drop(<() as Foo>::copy_me(&x)); | ^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _` --> $DIR/alias-bound-unsound.rs:24:10 | LL | drop(<() as Foo>::copy_me(&x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) error[E0275]: overflow evaluating the requirement `&<() as Foo>::Item well-formed` --> $DIR/alias-bound-unsound.rs:24:31 | LL | drop(<() as Foo>::copy_me(&x)); | ^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) error[E0275]: overflow evaluating the requirement `<() as Foo>::Item well-formed` --> $DIR/alias-bound-unsound.rs:24:10 | LL | drop(<() as Foo>::copy_me(&x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _` --> $DIR/alias-bound-unsound.rs:24:10 @@ -51,7 +42,6 @@ error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _` LL | drop(<() as Foo>::copy_me(&x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 6 previous errors diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr index fc145b81196..a04fa1ab8a1 100644 --- a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr @@ -6,6 +6,9 @@ LL | impl Trait for T {} LL | struct LocalTy; LL | impl Trait for ::Assoc {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + | + = note: overflow evaluating the requirement `_ == ::Assoc` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`trait_ref_is_knowable_norm_overflow`) error[E0275]: overflow evaluating the requirement `::Assoc: Sized` --> $DIR/trait_ref_is_knowable-norm-overflow.rs:10:18 diff --git a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr index 150100f2c53..8d7d8cee08a 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr @@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `W<_>: Trait` LL | impls::>(); | ^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`fixpoint_exponential_growth`) note: required by a bound in `impls` --> $DIR/fixpoint-exponential-growth.rs:30:13 | diff --git a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr index a3404da51f0..7cedb4d36c9 100644 --- a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr +++ b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr @@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `(): Trait` LL | impls_trait::<()>(); | ^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`double_cycle_inductive_coinductive`) note: required by a bound in `impls_trait` --> $DIR/double-cycle-inductive-coinductive.rs:17:19 | @@ -17,7 +16,6 @@ error[E0275]: overflow evaluating the requirement `(): TraitRev` LL | impls_trait_rev::<()>(); | ^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`double_cycle_inductive_coinductive`) note: required by a bound in `impls_trait_rev` --> $DIR/double-cycle-inductive-coinductive.rs:29:23 | diff --git a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr index 42451920744..a2a5c028cf8 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr +++ b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr @@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `W<_>: Trait` LL | impls_trait::>(); | ^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_fixpoint_hang`) note: required by a bound in `impls_trait` --> $DIR/inductive-fixpoint-hang.rs:28:19 | diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr index 859b3f3f1c7..e9cc6bc6c81 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr +++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr @@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `(): A` LL | impls_a::<()>(); | ^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_not_on_stack`) note: required by a bound in `impls_a` --> $DIR/inductive-not-on-stack.rs:25:15 | @@ -17,7 +16,6 @@ error[E0275]: overflow evaluating the requirement `(): AR` LL | impls_ar::<()>(); | ^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_not_on_stack`) note: required by a bound in `impls_ar` --> $DIR/inductive-not-on-stack.rs:38:16 | diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr index e828bdeb16b..17544eb1da5 100644 --- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr +++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr @@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `(): A` LL | impls_a::<()>(); | ^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mixed_cycles_1`) note: required by a bound in `impls_a` --> $DIR/mixed-cycles-1.rs:34:15 | diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr index ec13093f707..a9be1016c74 100644 --- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr +++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr @@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `(): A` LL | impls_a::<()>(); | ^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mixed_cycles_2`) note: required by a bound in `impls_a` --> $DIR/mixed-cycles-2.rs:27:15 | diff --git a/tests/ui/traits/next-solver/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize-param-env-2.stderr index 86729eb8a4b..74a0a90885d 100644 --- a/tests/ui/traits/next-solver/normalize-param-env-2.stderr +++ b/tests/ui/traits/next-solver/normalize-param-env-2.stderr @@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` LL | Self::Assoc: A, | ^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_2`) note: the requirement `<() as A>::Assoc: A` appears on the `impl`'s method `f` but not on the corresponding trait's method --> $DIR/normalize-param-env-2.rs:12:8 | @@ -19,24 +18,18 @@ error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` | LL | Self::Assoc: A, | ^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_2`) error[E0275]: overflow evaluating the requirement `<() as A>::Assoc well-formed` --> $DIR/normalize-param-env-2.rs:24:22 | LL | Self::Assoc: A, | ^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_2`) error[E0275]: overflow evaluating the requirement `(): A` --> $DIR/normalize-param-env-2.rs:27:10 | LL | <() as A>::f(); | ^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_2`) error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` --> $DIR/normalize-param-env-2.rs:27:9 @@ -44,7 +37,6 @@ error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` LL | <() as A>::f(); | ^^^^^^^^^^^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_2`) note: required by a bound in `A::f` --> $DIR/normalize-param-env-2.rs:14:22 | diff --git a/tests/ui/traits/next-solver/normalize-param-env-4.next.stderr b/tests/ui/traits/next-solver/normalize-param-env-4.next.stderr index 2a017fac104..1bee8ee88ff 100644 --- a/tests/ui/traits/next-solver/normalize-param-env-4.next.stderr +++ b/tests/ui/traits/next-solver/normalize-param-env-4.next.stderr @@ -3,16 +3,12 @@ error[E0275]: overflow evaluating the requirement `::Assoc: Trait` | LL | ::Assoc: Trait, | ^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_4`) error[E0275]: overflow evaluating the requirement `::Assoc well-formed` --> $DIR/normalize-param-env-4.rs:18:26 | LL | ::Assoc: Trait, | ^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_4`) error[E0275]: overflow evaluating the requirement `T: Trait` --> $DIR/normalize-param-env-4.rs:31:19 @@ -20,7 +16,6 @@ error[E0275]: overflow evaluating the requirement `T: Trait` LL | impls_trait::(); | ^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`normalize_param_env_4`) note: required by a bound in `impls_trait` --> $DIR/normalize-param-env-4.rs:14:19 | diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr index 90b54b1e789..b032ae3e740 100644 --- a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr +++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr @@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `W<_>: Trait` LL | impls::>(); | ^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`exponential_trait_goals`) note: required by a bound in `impls` --> $DIR/exponential-trait-goals.rs:14:13 | diff --git a/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs index fb668f83b01..1b80287d9da 100644 --- a/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs +++ b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs @@ -1,12 +1,7 @@ -//~ ERROR overflow evaluating the requirement `Self well-formed` -//~| ERROR overflow evaluating the requirement `Self: Trait` - // This is a non-regression test for issue #115351, where a recursion limit of 0 caused an ICE. //@ compile-flags: -Znext-solver --crate-type=lib -//@ check-fail +//@ check-pass #![recursion_limit = "0"] trait Trait {} impl Trait for u32 {} -//~^ ERROR overflow evaluating the requirement `u32: Trait` -//~| ERROR overflow evaluating the requirement `u32 well-formed` diff --git a/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr deleted file mode 100644 index 16b25d90ace..00000000000 --- a/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0275]: overflow evaluating the requirement `Self: Trait` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`) - -error[E0275]: overflow evaluating the requirement `Self well-formed` - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`) - -error[E0275]: overflow evaluating the requirement `u32: Trait` - --> $DIR/recursion-limit-zero-issue-115351.rs:10:16 - | -LL | impl Trait for u32 {} - | ^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`) - -error[E0275]: overflow evaluating the requirement `u32 well-formed` - --> $DIR/recursion-limit-zero-issue-115351.rs:10:16 - | -LL | impl Trait for u32 {} - | ^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`) - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0275`. From dd4be4cb2f182bfd0ca8a107f5e374f53c05704b Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 23 Feb 2024 10:35:43 +0100 Subject: [PATCH 09/18] extract fulfillment err creation --- .../src/solve/fulfill.rs | 155 +++++++++--------- 1 file changed, 73 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 368e2e8810c..b3579d745b1 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -73,36 +73,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { self.obligations .drain(..) - .map(|obligation| { - let code = infcx.probe(|_| { - match infcx - .evaluate_root_goal(obligation.clone().into(), GenerateProofTree::IfEnabled) - .0 - { - Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { - FulfillmentErrorCode::Ambiguity { overflow: None } - } - Ok(( - _, - Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }), - )) => FulfillmentErrorCode::Ambiguity { - overflow: Some(suggest_increasing_limit), - }, - Ok((_, Certainty::Yes)) => { - bug!("did not expect successful goal when collecting ambiguity errors") - } - Err(_) => { - bug!("did not expect selection error when collecting ambiguity errors") - } - } - }); - - FulfillmentError { - obligation: obligation.clone(), - code, - root_obligation: obligation, - } - }) + .map(|obligation| fulfillment_error_for_stalled(infcx, obligation)) .collect() } @@ -125,58 +96,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let (changed, certainty) = match result { Ok(result) => result, Err(NoSolution) => { - errors.push(FulfillmentError { - obligation: obligation.clone(), - code: match goal.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { - FulfillmentErrorCode::ProjectionError( - // FIXME: This could be a `Sorts` if the term is a type - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::NormalizesTo(..) => { - FulfillmentErrorCode::ProjectionError( - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::AliasRelate(_, _, _) => { - FulfillmentErrorCode::ProjectionError( - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::Subtype(pred) => { - let (a, b) = infcx.enter_forall_and_leak_universe( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(true, a, b); - FulfillmentErrorCode::SubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Coerce(pred) => { - let (a, b) = infcx.enter_forall_and_leak_universe( - goal.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(false, a, b); - FulfillmentErrorCode::SubtypeError( - expected_found, - TypeError::Sorts(expected_found), - ) - } - ty::PredicateKind::Clause(_) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::Ambiguous => { - FulfillmentErrorCode::SelectionError( - SelectionError::Unimplemented, - ) - } - ty::PredicateKind::ConstEquate(..) => { - bug!("unexpected goal: {goal:?}") - } - }, - root_obligation: obligation, - }); + errors.push(fulfillment_error_for_no_solution(infcx, obligation)); continue; } }; @@ -206,3 +126,74 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { std::mem::take(&mut self.obligations) } } + +fn fulfillment_error_for_no_solution<'tcx>( + infcx: &InferCtxt<'tcx>, + obligation: PredicateObligation<'tcx>, +) -> FulfillmentError<'tcx> { + let code = match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { + FulfillmentErrorCode::ProjectionError( + // FIXME: This could be a `Sorts` if the term is a type + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::NormalizesTo(..) => { + FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes { + err: TypeError::Mismatch, + }) + } + ty::PredicateKind::AliasRelate(_, _, _) => { + FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes { + err: TypeError::Mismatch, + }) + } + ty::PredicateKind::Subtype(pred) => { + let (a, b) = infcx.enter_forall_and_leak_universe( + obligation.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(true, a, b); + FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found)) + } + ty::PredicateKind::Coerce(pred) => { + let (a, b) = infcx.enter_forall_and_leak_universe( + obligation.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(false, a, b); + FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found)) + } + ty::PredicateKind::Clause(_) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::Ambiguous => { + FulfillmentErrorCode::SelectionError(SelectionError::Unimplemented) + } + ty::PredicateKind::ConstEquate(..) => { + bug!("unexpected goal: {obligation:?}") + } + }; + FulfillmentError { root_obligation: obligation.clone(), code, obligation } +} + +fn fulfillment_error_for_stalled<'tcx>( + infcx: &InferCtxt<'tcx>, + obligation: PredicateObligation<'tcx>, +) -> FulfillmentError<'tcx> { + let code = infcx.probe(|_| { + match infcx.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::Never).0 { + Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { + FulfillmentErrorCode::Ambiguity { overflow: None } + } + Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => { + FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } + } + Ok((_, Certainty::Yes)) => { + bug!("did not expect successful goal when collecting ambiguity errors") + } + Err(_) => { + bug!("did not expect selection error when collecting ambiguity errors") + } + } + }); + + FulfillmentError { obligation: obligation.clone(), code, root_obligation: obligation } +} From 3605a09ca236d9643a44f00494a40d6f15d86618 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 23 Feb 2024 11:25:57 +0100 Subject: [PATCH 10/18] stash overflowing obligations in fulfill --- .../src/solve/fulfill.rs | 87 ++++++++++++++++--- 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index b3579d745b1..bc2bae9da61 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -24,7 +24,7 @@ use super::{Certainty, InferCtxtEvalExt}; /// It is also likely that we want to use slightly different datastructures /// here as this will have to deal with far more root goals than `evaluate_all`. pub struct FulfillmentCtxt<'tcx> { - obligations: Vec>, + obligations: ObligationStorage<'tcx>, /// The snapshot in which this context was created. Using the context /// outside of this snapshot leads to subtle bugs if the snapshot @@ -33,6 +33,57 @@ pub struct FulfillmentCtxt<'tcx> { usable_in_snapshot: usize, } +#[derive(Default)] +struct ObligationStorage<'tcx> { + /// Obligations which resulted in an overflow in fulfillment itself. + /// + /// We cannot eagerly return these as error so we instead store them here + /// to avoid recomputing them each time `select_where_possible` is called. + /// This also allows us to return the correct `FulfillmentError` for them. + overflowed: Vec>, + pending: Vec>, +} + +impl<'tcx> ObligationStorage<'tcx> { + fn register(&mut self, obligation: PredicateObligation<'tcx>) { + self.pending.push(obligation); + } + + fn clone_pending(&self) -> Vec> { + let mut obligations = self.pending.clone(); + obligations.extend(self.overflowed.iter().cloned()); + obligations + } + + fn take_pending(&mut self) -> Vec> { + let mut obligations = mem::take(&mut self.pending); + obligations.extend(self.overflowed.drain(..)); + obligations + } + + fn unstalled_for_select(&mut self) -> impl Iterator> { + mem::take(&mut self.pending).into_iter() + } + + fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) { + infcx.probe(|_| { + // IMPORTANT: we must not use solve any inference variables in the obligations + // as this is all happening inside of a probe. We use a probe to make sure + // we get all obligations involved in the overflow. We pretty much check: if + // we were to do another step of `select_where_possible`, which goals would + // change. + self.overflowed.extend(self.pending.extract_if(|o| { + let goal = o.clone().into(); + let result = infcx.evaluate_root_goal(goal, GenerateProofTree::Never).0; + match result { + Ok((has_changed, _)) => has_changed, + _ => false, + } + })); + }) + } +} + impl<'tcx> FulfillmentCtxt<'tcx> { pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> { assert!( @@ -40,7 +91,10 @@ impl<'tcx> FulfillmentCtxt<'tcx> { "new trait solver fulfillment context created when \ infcx is set up for old trait solver" ); - FulfillmentCtxt { obligations: Vec::new(), usable_in_snapshot: infcx.num_open_snapshots() } + FulfillmentCtxt { + obligations: Default::default(), + usable_in_snapshot: infcx.num_open_snapshots(), + } } fn inspect_evaluated_obligation( @@ -67,14 +121,24 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { obligation: PredicateObligation<'tcx>, ) { assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); - self.obligations.push(obligation); + self.obligations.register(obligation); } fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { - self.obligations + let mut errors: Vec<_> = self + .obligations + .pending .drain(..) .map(|obligation| fulfillment_error_for_stalled(infcx, obligation)) - .collect() + .collect(); + + errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError { + root_obligation: obligation.clone(), + code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, + obligation, + })); + + errors } fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec> { @@ -82,14 +146,13 @@ 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) { - // Only return true errors that we have accumulated while processing; - // keep ambiguities around, *including overflows*, because they shouldn't - // be considered true errors. + self.obligations.on_fulfillment_overflow(infcx); + // Only return true errors that we have accumulated while processing. return errors; } let mut has_changed = false; - for obligation in mem::take(&mut self.obligations) { + for obligation in self.obligations.unstalled_for_select() { let goal = obligation.clone().into(); let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0; self.inspect_evaluated_obligation(infcx, &obligation, &result); @@ -103,7 +166,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { has_changed |= changed; match certainty { Certainty::Yes => {} - Certainty::Maybe(_) => self.obligations.push(obligation), + Certainty::Maybe(_) => self.obligations.register(obligation), } } @@ -116,14 +179,14 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { } fn pending_obligations(&self) -> Vec> { - self.obligations.clone() + self.obligations.clone_pending() } fn drain_unstalled_obligations( &mut self, _: &InferCtxt<'tcx>, ) -> Vec> { - std::mem::take(&mut self.obligations) + self.obligations.take_pending() } } From 8c5e83df85e2fd884a9519e3a8743754d43d7ef9 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 23 Feb 2024 11:57:59 +0100 Subject: [PATCH 11/18] track overflowing goals for overfow errors --- .../src/traits/coherence.rs | 103 +++++++++++++----- .../error_reporting/type_err_ctxt_ext.rs | 38 ++++--- .../src/traits/specialize/mod.rs | 9 ++ .../traits/specialize/specialization_graph.rs | 1 + .../coherence-fulfill-overflow.stderr | 3 + 5 files changed, 110 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 6778cb7b7a9..68111c4cc1f 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -22,7 +22,7 @@ use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{util, TraitEngine, TraitEngineExt}; +use rustc_infer::traits::{util, FulfillmentErrorCode, TraitEngine, TraitEngineExt}; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::specialization_graph::OverlapMode; @@ -35,6 +35,8 @@ use rustc_span::DUMMY_SP; use std::fmt::Debug; use std::ops::ControlFlow; +use super::error_reporting::suggest_new_overflow_limit; + /// Whether we do the orphan check relative to this crate or /// to some remote crate. #[derive(Copy, Clone, Debug)] @@ -56,6 +58,9 @@ pub struct OverlapResult<'tcx> { /// `true` if the overlap might've been permitted before the shift /// to universes. pub involves_placeholder: bool, + + /// Used in the new solver to suggest increasing the recursion limit. + pub overflowing_predicates: Vec>, } pub fn add_placeholder_note(err: &mut Diag<'_, G>) { @@ -65,6 +70,18 @@ pub fn add_placeholder_note(err: &mut Diag<'_, G>) { ); } +pub fn suggest_increasing_recursion_limit<'tcx, G: EmissionGuarantee>( + tcx: TyCtxt<'tcx>, + err: &mut Diag<'_, G>, + overflowing_predicates: &[ty::Predicate<'tcx>], +) { + for pred in overflowing_predicates { + err.note(format!("overflow evaluating the requirement `{}`", pred)); + } + + suggest_new_overflow_limit(tcx, err); +} + #[derive(Debug, Clone, Copy)] enum TrackAmbiguityCauses { Yes, @@ -221,11 +238,13 @@ fn overlap<'tcx>( ), ); + let mut overflowing_predicates = Vec::new(); if overlap_mode.use_implicit_negative() { - if let Some(_failing_obligation) = - impl_intersection_has_impossible_obligation(selcx, &obligations) - { - return None; + match impl_intersection_has_impossible_obligation(selcx, &obligations) { + IntersectionHasImpossibleObligations::Yes => return None, + IntersectionHasImpossibleObligations::No { overflowing_predicates: p } => { + overflowing_predicates = p + } } } @@ -261,7 +280,12 @@ fn overlap<'tcx>( impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header); } - Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) + Some(OverlapResult { + impl_header, + intercrate_ambiguity_causes, + involves_placeholder, + overflowing_predicates, + }) } #[instrument(level = "debug", skip(infcx), ret)] @@ -287,6 +311,19 @@ fn equate_impl_headers<'tcx>( result.map(|infer_ok| infer_ok.obligations).ok() } +/// The result of [fn impl_intersection_has_impossible_obligation]. +enum IntersectionHasImpossibleObligations<'tcx> { + Yes, + No { + /// With `-Znext-solver=coherence`, some obligations may + /// fail if only the user increased the recursion limit. + /// + /// We return those obligations here and mention them in the + /// error message. + overflowing_predicates: Vec>, + }, +} + /// Check if both impls can be satisfied by a common type by considering whether /// any of either impl's obligations is not known to hold. /// @@ -308,7 +345,7 @@ fn equate_impl_headers<'tcx>( fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligations: &'a [PredicateObligation<'tcx>], -) -> Option> { +) -> IntersectionHasImpossibleObligations<'tcx> { let infcx = selcx.infcx; if infcx.next_trait_solver() { @@ -317,28 +354,42 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( // We only care about the obligations that are *definitely* true errors. // Ambiguities do not prove the disjointness of two impls. - let mut errors = fulfill_cx.select_where_possible(infcx); - errors.pop().map(|err| err.obligation) + let errors = fulfill_cx.select_where_possible(infcx); + if errors.is_empty() { + let overflow_errors = fulfill_cx.collect_remaining_errors(infcx); + let overflowing_predicates = overflow_errors + .into_iter() + .filter(|e| match e.code { + FulfillmentErrorCode::Ambiguity { overflow: Some(true) } => true, + _ => false, + }) + .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate)) + .collect(); + IntersectionHasImpossibleObligations::No { overflowing_predicates } + } else { + IntersectionHasImpossibleObligations::Yes + } } else { - obligations - .iter() - .find(|obligation| { - // We use `evaluate_root_obligation` to correctly track intercrate - // ambiguity clauses. We cannot use this in the new solver. - let evaluation_result = selcx.evaluate_root_obligation(obligation); + for obligation in obligations { + // We use `evaluate_root_obligation` to correctly track intercrate + // ambiguity clauses. + let evaluation_result = selcx.evaluate_root_obligation(obligation); - match evaluation_result { - Ok(result) => !result.may_apply(), - // If overflow occurs, we need to conservatively treat the goal as possibly holding, - // since there can be instantiations of this goal that don't overflow and result in - // success. This isn't much of a problem in the old solver, since we treat overflow - // fatally (this still can be encountered: ), - // but in the new solver, this is very important for correctness, since overflow - // *must* be treated as ambiguity for completeness. - Err(_overflow) => false, + match evaluation_result { + Ok(result) => { + if !result.may_apply() { + return IntersectionHasImpossibleObligations::Yes; + } } - }) - .cloned() + // If overflow occurs, we need to conservatively treat the goal as possibly holding, + // since there can be instantiations of this goal that don't overflow and result in + // success. While this isn't much of a problem in the old solver, since we treat overflow + // fatally, this still can be encountered: . + Err(_overflow) => {} + } + } + + IntersectionHasImpossibleObligations::No { overflowing_predicates: Vec::new() } } } 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 cbf52ea9e5a..0023fd60287 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 @@ -20,10 +20,9 @@ use crate::traits::{ SelectionError, SignatureMismatch, TraitNotObjectSafe, }; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError, - MultiSpan, StashKey, StringPart, -}; +use rustc_errors::codes::*; +use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart}; +use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -62,6 +61,22 @@ pub enum OverflowCause<'tcx> { TraitSolver(ty::Predicate<'tcx>), } +pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>( + tcx: TyCtxt<'tcx>, + err: &mut Diag<'_, G>, +) { + let suggested_limit = match tcx.recursion_limit() { + Limit(0) => Limit(2), + limit => limit * 2, + }; + err.help(format!( + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", + suggested_limit, + tcx.crate_name(LOCAL_CRATE), + )); +} + #[extension(pub trait TypeErrCtxtExt<'tcx>)] impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn report_fulfillment_errors( @@ -263,7 +278,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; if suggest_increasing_limit { - self.suggest_new_overflow_limit(&mut err); + suggest_new_overflow_limit(self.tcx, &mut err); } err @@ -303,19 +318,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } - fn suggest_new_overflow_limit(&self, err: &mut Diag<'_>) { - let suggested_limit = match self.tcx.recursion_limit() { - Limit(0) => Limit(2), - limit => limit * 2, - }; - err.help(format!( - "consider increasing the recursion limit by adding a \ - `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", - suggested_limit, - self.tcx.crate_name(LOCAL_CRATE), - )); - } - /// Reports that a cycle was detected which led to overflow and halts /// compilation. This is equivalent to `report_overflow_obligation` except /// that we can give a more helpful error message (and, in particular, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index b329739609c..f5bc6c3ad2c 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -39,6 +39,7 @@ pub struct OverlapError<'tcx> { pub self_ty: Option>, pub intercrate_ambiguity_causes: FxIndexSet>, pub involves_placeholder: bool, + pub overflowing_predicates: Vec>, } /// Given the generic parameters for the requested impl, translate it to the generic parameters @@ -435,6 +436,14 @@ fn report_conflicting_impls<'tcx>( if overlap.involves_placeholder { coherence::add_placeholder_note(err); } + + if !overlap.overflowing_predicates.is_empty() { + coherence::suggest_increasing_recursion_limit( + tcx, + err, + &overlap.overflowing_predicates, + ); + } } let msg = DelayDm(|| { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index f3b77d68922..95db9e2092f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -103,6 +103,7 @@ impl<'tcx> Children { self_ty: self_ty.has_concrete_skeleton().then_some(self_ty), intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, involves_placeholder: overlap.involves_placeholder, + overflowing_predicates: overlap.overflowing_predicates, } }; diff --git a/tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr index 406c0ccca97..57cba790b55 100644 --- a/tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr +++ b/tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr @@ -5,6 +5,9 @@ LL | impl Trait for W {} | ------------------------------------- first implementation here LL | impl Trait for T {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W>>>>>>>>>>>>>>>>>>>>` + | + = note: overflow evaluating the requirement `W>>>>>>>>>>>>>>>>>>>>: TwoW` + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`) error: aborting due to 1 previous error From 5ce15af6b1d0c16df722db929dc81b9a97c2bd1f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 9 Jan 2024 12:02:55 +0100 Subject: [PATCH 12/18] Make `invalid_doc_attributes` deny by default --- compiler/rustc_lint_defs/src/builtin.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 1cddb45428c..94f8bbe2437 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3586,18 +3586,9 @@ declare_lint! { /// being validated. Usually these should be rejected as a hard error, /// but this lint was introduced to avoid breaking any existing /// crates which included them. - /// - /// This is a [future-incompatible] lint to transition this to a hard - /// error in the future. See [issue #82730] for more details. - /// - /// [issue #82730]: https://github.com/rust-lang/rust/issues/82730 pub INVALID_DOC_ATTRIBUTES, - Warn, + Deny, "detects invalid `#[doc(...)]` attributes", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #82730 ", - }; } declare_lint! { From 8e817af3ae955aec532eba3d5eaaaf6621b700fa Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 29 Feb 2024 14:43:11 +0100 Subject: [PATCH 13/18] Update ui tests --- tests/rustdoc-ui/doc-include-suggestion.rs | 6 +-- .../rustdoc-ui/doc-include-suggestion.stderr | 10 ++-- tests/rustdoc-ui/doctest/doc-test-attr.rs | 4 -- tests/rustdoc-ui/doctest/doc-test-attr.stderr | 20 ++------ tests/rustdoc-ui/lints/doc-attr.rs | 8 --- tests/rustdoc-ui/lints/doc-attr.stderr | 41 +++------------ tests/rustdoc-ui/lints/doc-spotlight.fixed | 2 - tests/rustdoc-ui/lints/doc-spotlight.rs | 2 - tests/rustdoc-ui/lints/doc-spotlight.stderr | 11 +--- tests/rustdoc-ui/lints/doc_cfg_hide.rs | 4 -- tests/rustdoc-ui/lints/doc_cfg_hide.stderr | 21 ++------ tests/rustdoc-ui/lints/invalid-doc-attr.rs | 9 ---- .../rustdoc-ui/lints/invalid-doc-attr.stderr | 50 ++++++------------- tests/ui/attributes/doc-attr.rs | 8 --- tests/ui/attributes/doc-attr.stderr | 41 +++------------ tests/ui/attributes/doc-test-literal.rs | 3 -- tests/ui/attributes/doc-test-literal.stderr | 11 +--- tests/ui/future-incompatible-lint-group.rs | 3 +- .../ui/future-incompatible-lint-group.stderr | 9 +--- tests/ui/repr/invalid_repr_list_help.rs | 3 +- tests/ui/repr/invalid_repr_list_help.stderr | 8 ++- tests/ui/rustdoc/deny-invalid-doc-attrs.rs | 2 - .../ui/rustdoc/deny-invalid-doc-attrs.stderr | 2 - tests/ui/rustdoc/doc-primitive.rs | 1 - tests/ui/rustdoc/doc-primitive.stderr | 2 - tests/ui/rustdoc/doc-test-attr.rs | 3 -- tests/ui/rustdoc/doc-test-attr.stderr | 12 +---- 27 files changed, 55 insertions(+), 241 deletions(-) diff --git a/tests/rustdoc-ui/doc-include-suggestion.rs b/tests/rustdoc-ui/doc-include-suggestion.rs index 5c8d1efa76f..aff0a24ace8 100644 --- a/tests/rustdoc-ui/doc-include-suggestion.rs +++ b/tests/rustdoc-ui/doc-include-suggestion.rs @@ -1,10 +1,6 @@ -//@ check-pass - #[doc(include = "external-cross-doc.md")] -//~^ WARNING unknown `doc` attribute `include` +//~^ ERROR unknown `doc` attribute `include` //~| HELP use `doc = include_str!` instead // FIXME(#85497): make this a deny instead so it's more clear what's happening //~| NOTE on by default -//~| WARNING previously accepted -//~| NOTE see issue #82730 pub struct NeedMoreDocs; diff --git a/tests/rustdoc-ui/doc-include-suggestion.stderr b/tests/rustdoc-ui/doc-include-suggestion.stderr index fcc93d0532a..1b4b78a8f26 100644 --- a/tests/rustdoc-ui/doc-include-suggestion.stderr +++ b/tests/rustdoc-ui/doc-include-suggestion.stderr @@ -1,12 +1,10 @@ -warning: unknown `doc` attribute `include` - --> $DIR/doc-include-suggestion.rs:3:7 +error: unknown `doc` attribute `include` + --> $DIR/doc-include-suggestion.rs:1:7 | LL | #[doc(include = "external-cross-doc.md")] | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 - = note: `#[warn(invalid_doc_attributes)]` on by default + = note: `#[deny(invalid_doc_attributes)]` on by default -warning: 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/doctest/doc-test-attr.rs b/tests/rustdoc-ui/doctest/doc-test-attr.rs index 46178ad865a..8570252c449 100644 --- a/tests/rustdoc-ui/doctest/doc-test-attr.rs +++ b/tests/rustdoc-ui/doctest/doc-test-attr.rs @@ -1,14 +1,10 @@ #![crate_type = "lib"] -#![deny(invalid_doc_attributes)] #![doc(test)] //~^ ERROR `#[doc(test(...)]` takes a list of attributes -//~^^ WARN this was previously accepted by the compiler #![doc(test = "hello")] //~^ ERROR `#[doc(test(...)]` takes a list of attributes -//~^^ WARN this was previously accepted by the compiler #![doc(test(a))] //~^ ERROR unknown `doc(test)` attribute `a` -//~^^ WARN this was previously accepted by the compiler pub fn foo() {} diff --git a/tests/rustdoc-ui/doctest/doc-test-attr.stderr b/tests/rustdoc-ui/doctest/doc-test-attr.stderr index 5e6014954a4..415251cc5e9 100644 --- a/tests/rustdoc-ui/doctest/doc-test-attr.stderr +++ b/tests/rustdoc-ui/doctest/doc-test-attr.stderr @@ -1,34 +1,22 @@ error: `#[doc(test(...)]` takes a list of attributes - --> $DIR/doc-test-attr.rs:4:8 + --> $DIR/doc-test-attr.rs:3:8 | LL | #![doc(test)] | ^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 -note: the lint level is defined here - --> $DIR/doc-test-attr.rs:2:9 - | -LL | #![deny(invalid_doc_attributes)] - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(invalid_doc_attributes)]` on by default error: `#[doc(test(...)]` takes a list of attributes - --> $DIR/doc-test-attr.rs:7:8 + --> $DIR/doc-test-attr.rs:5:8 | LL | #![doc(test = "hello")] | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: unknown `doc(test)` attribute `a` - --> $DIR/doc-test-attr.rs:10:13 + --> $DIR/doc-test-attr.rs:7:13 | LL | #![doc(test(a))] | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: aborting due to 3 previous errors diff --git a/tests/rustdoc-ui/lints/doc-attr.rs b/tests/rustdoc-ui/lints/doc-attr.rs index 980d1c0e207..666aeb55cbe 100644 --- a/tests/rustdoc-ui/lints/doc-attr.rs +++ b/tests/rustdoc-ui/lints/doc-attr.rs @@ -1,25 +1,17 @@ #![crate_type = "lib"] -#![deny(warnings)] #![doc(as_ptr)] //~^ ERROR unknown `doc` attribute -//~^^ WARN #[doc(as_ptr)] //~^ ERROR unknown `doc` attribute -//~^^ WARN pub fn foo() {} #[doc(123)] //~^ ERROR invalid `doc` attribute -//~| WARN #[doc("hello", "bar")] //~^ ERROR invalid `doc` attribute -//~| WARN //~| ERROR invalid `doc` attribute -//~| WARN #[doc(foo::bar, crate::bar::baz = "bye")] //~^ ERROR unknown `doc` attribute -//~| WARN //~| ERROR unknown `doc` attribute -//~| WARN fn bar() {} diff --git a/tests/rustdoc-ui/lints/doc-attr.stderr b/tests/rustdoc-ui/lints/doc-attr.stderr index 68df2771fd7..091ffc20d46 100644 --- a/tests/rustdoc-ui/lints/doc-attr.stderr +++ b/tests/rustdoc-ui/lints/doc-attr.stderr @@ -1,71 +1,46 @@ error: unknown `doc` attribute `as_ptr` - --> $DIR/doc-attr.rs:7:7 + --> $DIR/doc-attr.rs:5:7 | LL | #[doc(as_ptr)] | ^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 -note: the lint level is defined here - --> $DIR/doc-attr.rs:2:9 - | -LL | #![deny(warnings)] - | ^^^^^^^^ - = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` + = note: `#[deny(invalid_doc_attributes)]` on by default error: invalid `doc` attribute - --> $DIR/doc-attr.rs:12:7 + --> $DIR/doc-attr.rs:9:7 | LL | #[doc(123)] | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: invalid `doc` attribute - --> $DIR/doc-attr.rs:15:7 + --> $DIR/doc-attr.rs:11:7 | LL | #[doc("hello", "bar")] | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: invalid `doc` attribute - --> $DIR/doc-attr.rs:15:16 + --> $DIR/doc-attr.rs:11:16 | LL | #[doc("hello", "bar")] | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: unknown `doc` attribute `foo::bar` - --> $DIR/doc-attr.rs:20:7 + --> $DIR/doc-attr.rs:14:7 | LL | #[doc(foo::bar, crate::bar::baz = "bye")] | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: unknown `doc` attribute `crate::bar::baz` - --> $DIR/doc-attr.rs:20:17 + --> $DIR/doc-attr.rs:14:17 | LL | #[doc(foo::bar, crate::bar::baz = "bye")] | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: unknown `doc` attribute `as_ptr` - --> $DIR/doc-attr.rs:3:8 + --> $DIR/doc-attr.rs:2:8 | LL | #![doc(as_ptr)] | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: aborting due to 7 previous errors diff --git a/tests/rustdoc-ui/lints/doc-spotlight.fixed b/tests/rustdoc-ui/lints/doc-spotlight.fixed index 6de95a33589..0f8f11a9430 100644 --- a/tests/rustdoc-ui/lints/doc-spotlight.fixed +++ b/tests/rustdoc-ui/lints/doc-spotlight.fixed @@ -1,8 +1,6 @@ //@ run-rustfix -#![deny(warnings)] #![feature(doc_notable_trait)] #[doc(notable_trait)] //~^ ERROR unknown `doc` attribute `spotlight` -//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! trait MyTrait {} diff --git a/tests/rustdoc-ui/lints/doc-spotlight.rs b/tests/rustdoc-ui/lints/doc-spotlight.rs index 9823ea90522..c1f90dd442b 100644 --- a/tests/rustdoc-ui/lints/doc-spotlight.rs +++ b/tests/rustdoc-ui/lints/doc-spotlight.rs @@ -1,8 +1,6 @@ //@ run-rustfix -#![deny(warnings)] #![feature(doc_notable_trait)] #[doc(spotlight)] //~^ ERROR unknown `doc` attribute `spotlight` -//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! trait MyTrait {} diff --git a/tests/rustdoc-ui/lints/doc-spotlight.stderr b/tests/rustdoc-ui/lints/doc-spotlight.stderr index 5d93b4132fc..9682a3c0c8b 100644 --- a/tests/rustdoc-ui/lints/doc-spotlight.stderr +++ b/tests/rustdoc-ui/lints/doc-spotlight.stderr @@ -1,19 +1,12 @@ error: unknown `doc` attribute `spotlight` - --> $DIR/doc-spotlight.rs:5:7 + --> $DIR/doc-spotlight.rs:4:7 | LL | #[doc(spotlight)] | ^^^^^^^^^ help: use `notable_trait` instead | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 = note: `doc(spotlight)` was renamed to `doc(notable_trait)` = note: `doc(spotlight)` is now a no-op -note: the lint level is defined here - --> $DIR/doc-spotlight.rs:2:9 - | -LL | #![deny(warnings)] - | ^^^^^^^^ - = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` + = note: `#[deny(invalid_doc_attributes)]` on by default error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.rs b/tests/rustdoc-ui/lints/doc_cfg_hide.rs index 5d8791748a0..9a8bce2a92a 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.rs +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.rs @@ -1,11 +1,7 @@ #![feature(doc_cfg_hide)] -#![deny(warnings)] #![doc(cfg_hide = "test")] //~ ERROR -//~^ WARN #![doc(cfg_hide)] //~ ERROR -//~^ WARN #[doc(cfg_hide(doc))] //~ ERROR -//~^ WARN pub fn foo() {} diff --git a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr index ca6a14a42b8..0c9d0879b0a 100644 --- a/tests/rustdoc-ui/lints/doc_cfg_hide.stderr +++ b/tests/rustdoc-ui/lints/doc_cfg_hide.stderr @@ -1,40 +1,27 @@ error: this attribute can only be applied at the crate level - --> $DIR/doc_cfg_hide.rs:9:7 + --> $DIR/doc_cfg_hide.rs:6:7 | LL | #[doc(cfg_hide(doc))] | ^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 = note: read for more information -note: the lint level is defined here - --> $DIR/doc_cfg_hide.rs:2:9 - | -LL | #![deny(warnings)] - | ^^^^^^^^ - = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` + = note: `#[deny(invalid_doc_attributes)]` on by default help: to apply to the crate, use an inner attribute | LL | #![doc(cfg_hide(doc))] | + error: `#[doc(cfg_hide(...))]` takes a list of attributes - --> $DIR/doc_cfg_hide.rs:4:8 + --> $DIR/doc_cfg_hide.rs:3:8 | LL | #![doc(cfg_hide = "test")] | ^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: `#[doc(cfg_hide(...))]` takes a list of attributes - --> $DIR/doc_cfg_hide.rs:6:8 + --> $DIR/doc_cfg_hide.rs:4:8 | LL | #![doc(cfg_hide)] | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: aborting due to 3 previous errors diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.rs b/tests/rustdoc-ui/lints/invalid-doc-attr.rs index 16b12cca5a0..e1cc08ca242 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.rs @@ -1,32 +1,25 @@ #![crate_type = "lib"] -#![deny(warnings)] #![feature(doc_masked)] #![doc(masked)] //~^ ERROR this attribute can only be applied to an `extern crate` item -//~| WARN is being phased out #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level -//~| WARN is being phased out //~| HELP to apply to the crate, use an inner attribute //~| SUGGESTION ! #[doc(inline)] //~^ ERROR can only be applied to a `use` item -//~| WARN is being phased out pub fn foo() {} pub mod bar { #![doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level - //~| WARN is being phased out #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level - //~| WARN is being phased out #[doc(inline)] //~^ ERROR can only be applied to a `use` item - //~| WARN is being phased out pub fn baz() {} } @@ -38,10 +31,8 @@ pub use bar::baz; #[doc(masked)] //~^ ERROR this attribute can only be applied to an `extern crate` item -//~| WARN is being phased out pub struct Masked; #[doc(masked)] //~^ ERROR this attribute cannot be applied to an `extern crate self` item -//~| WARN is being phased out pub extern crate self as reexport; diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr index 82ea33e1d89..7621999a8ca 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr @@ -1,48 +1,37 @@ error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:9:7 + --> $DIR/invalid-doc-attr.rs:7:7 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 = note: read for more information -note: the lint level is defined here - --> $DIR/invalid-doc-attr.rs:2:9 - | -LL | #![deny(warnings)] - | ^^^^^^^^ - = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` + = note: `#[deny(invalid_doc_attributes)]` on by default help: to apply to the crate, use an inner attribute | LL | #![doc(test(no_crate_inject))] | + error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:14:7 + --> $DIR/invalid-doc-attr.rs:11:7 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items -... +LL | LL | pub fn foo() {} | ------------ not a `use` item | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:20:12 + --> $DIR/invalid-doc-attr.rs:16:12 | LL | #![doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 = note: read for more information error: conflicting doc inlining attributes - --> $DIR/invalid-doc-attr.rs:33:7 + --> $DIR/invalid-doc-attr.rs:26:7 | LL | #[doc(inline)] | ^^^^^^ this attribute... @@ -52,61 +41,50 @@ LL | #[doc(no_inline)] = help: remove one of the conflicting attributes error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:39:7 + --> $DIR/invalid-doc-attr.rs:32:7 | LL | #[doc(masked)] | ^^^^^^ only applicable on `extern crate` items -... +LL | LL | pub struct Masked; | ----------------- not an `extern crate` item | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 = note: read for more information error: this attribute cannot be applied to an `extern crate self` item - --> $DIR/invalid-doc-attr.rs:44:7 + --> $DIR/invalid-doc-attr.rs:36:7 | LL | #[doc(masked)] | ^^^^^^ not applicable on `extern crate self` items -... +LL | LL | pub extern crate self as reexport; | --------------------------------- `extern crate self` defined here - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:5:8 + --> $DIR/invalid-doc-attr.rs:4:8 | LL | #![doc(masked)] | ^^^^^^ only applicable on `extern crate` items | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:24:11 + --> $DIR/invalid-doc-attr.rs:19:11 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 = note: read for more information error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:27:11 + --> $DIR/invalid-doc-attr.rs:21:11 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items -... +LL | LL | pub fn baz() {} | ------------ not a `use` item | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 = note: read for more information error: aborting due to 9 previous errors diff --git a/tests/ui/attributes/doc-attr.rs b/tests/ui/attributes/doc-attr.rs index 980d1c0e207..666aeb55cbe 100644 --- a/tests/ui/attributes/doc-attr.rs +++ b/tests/ui/attributes/doc-attr.rs @@ -1,25 +1,17 @@ #![crate_type = "lib"] -#![deny(warnings)] #![doc(as_ptr)] //~^ ERROR unknown `doc` attribute -//~^^ WARN #[doc(as_ptr)] //~^ ERROR unknown `doc` attribute -//~^^ WARN pub fn foo() {} #[doc(123)] //~^ ERROR invalid `doc` attribute -//~| WARN #[doc("hello", "bar")] //~^ ERROR invalid `doc` attribute -//~| WARN //~| ERROR invalid `doc` attribute -//~| WARN #[doc(foo::bar, crate::bar::baz = "bye")] //~^ ERROR unknown `doc` attribute -//~| WARN //~| ERROR unknown `doc` attribute -//~| WARN fn bar() {} diff --git a/tests/ui/attributes/doc-attr.stderr b/tests/ui/attributes/doc-attr.stderr index 68df2771fd7..091ffc20d46 100644 --- a/tests/ui/attributes/doc-attr.stderr +++ b/tests/ui/attributes/doc-attr.stderr @@ -1,71 +1,46 @@ error: unknown `doc` attribute `as_ptr` - --> $DIR/doc-attr.rs:7:7 + --> $DIR/doc-attr.rs:5:7 | LL | #[doc(as_ptr)] | ^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 -note: the lint level is defined here - --> $DIR/doc-attr.rs:2:9 - | -LL | #![deny(warnings)] - | ^^^^^^^^ - = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` + = note: `#[deny(invalid_doc_attributes)]` on by default error: invalid `doc` attribute - --> $DIR/doc-attr.rs:12:7 + --> $DIR/doc-attr.rs:9:7 | LL | #[doc(123)] | ^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: invalid `doc` attribute - --> $DIR/doc-attr.rs:15:7 + --> $DIR/doc-attr.rs:11:7 | LL | #[doc("hello", "bar")] | ^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: invalid `doc` attribute - --> $DIR/doc-attr.rs:15:16 + --> $DIR/doc-attr.rs:11:16 | LL | #[doc("hello", "bar")] | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: unknown `doc` attribute `foo::bar` - --> $DIR/doc-attr.rs:20:7 + --> $DIR/doc-attr.rs:14:7 | LL | #[doc(foo::bar, crate::bar::baz = "bye")] | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: unknown `doc` attribute `crate::bar::baz` - --> $DIR/doc-attr.rs:20:17 + --> $DIR/doc-attr.rs:14:17 | LL | #[doc(foo::bar, crate::bar::baz = "bye")] | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: unknown `doc` attribute `as_ptr` - --> $DIR/doc-attr.rs:3:8 + --> $DIR/doc-attr.rs:2:8 | LL | #![doc(as_ptr)] | ^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: aborting due to 7 previous errors diff --git a/tests/ui/attributes/doc-test-literal.rs b/tests/ui/attributes/doc-test-literal.rs index a06a1afcb3f..92fe7846f14 100644 --- a/tests/ui/attributes/doc-test-literal.rs +++ b/tests/ui/attributes/doc-test-literal.rs @@ -1,7 +1,4 @@ -#![deny(warnings)] - #![doc(test(""))] //~^ ERROR `#![doc(test(...)]` does not take a literal -//~^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn main() {} diff --git a/tests/ui/attributes/doc-test-literal.stderr b/tests/ui/attributes/doc-test-literal.stderr index ed2964825c7..39e109a76ce 100644 --- a/tests/ui/attributes/doc-test-literal.stderr +++ b/tests/ui/attributes/doc-test-literal.stderr @@ -1,17 +1,10 @@ error: `#![doc(test(...)]` does not take a literal - --> $DIR/doc-test-literal.rs:3:13 + --> $DIR/doc-test-literal.rs:1:13 | LL | #![doc(test(""))] | ^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 -note: the lint level is defined here - --> $DIR/doc-test-literal.rs:1:9 - | -LL | #![deny(warnings)] - | ^^^^^^^^ - = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` + = note: `#[deny(invalid_doc_attributes)]` on by default error: aborting due to 1 previous error diff --git a/tests/ui/future-incompatible-lint-group.rs b/tests/ui/future-incompatible-lint-group.rs index bbd0e33d719..c84538318f7 100644 --- a/tests/ui/future-incompatible-lint-group.rs +++ b/tests/ui/future-incompatible-lint-group.rs @@ -11,8 +11,7 @@ trait Tr { pub mod submodule { // Error since this is a `future_incompatible` lint #![doc(test(some_test))] - //~^ ERROR this attribute can only be applied at the crate level - //~| WARN this was previously accepted by the compiler + //~^ ERROR this attribute can only be applied at the crate level } fn main() {} diff --git a/tests/ui/future-incompatible-lint-group.stderr b/tests/ui/future-incompatible-lint-group.stderr index 161fe82e373..4e6c434fa29 100644 --- a/tests/ui/future-incompatible-lint-group.stderr +++ b/tests/ui/future-incompatible-lint-group.stderr @@ -14,15 +14,8 @@ error: this attribute can only be applied at the crate level LL | #![doc(test(some_test))] | ^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 = note: read for more information -note: the lint level is defined here - --> $DIR/future-incompatible-lint-group.rs:3:9 - | -LL | #![deny(future_incompatible)] - | ^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(future_incompatible)]` + = note: `#[deny(invalid_doc_attributes)]` on by default error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/repr/invalid_repr_list_help.rs b/tests/ui/repr/invalid_repr_list_help.rs index 785ffb1e0f4..77f2a68537b 100644 --- a/tests/ui/repr/invalid_repr_list_help.rs +++ b/tests/ui/repr/invalid_repr_list_help.rs @@ -17,6 +17,5 @@ pub enum OwO4 { } #[repr(uwu)] //~ERROR: unrecognized representation hint -#[doc(owo)] //~WARN: unknown `doc` attribute - //~^ WARN: this was previously +#[doc(owo)] //~ERROR: unknown `doc` attribute pub struct Owo5; diff --git a/tests/ui/repr/invalid_repr_list_help.stderr b/tests/ui/repr/invalid_repr_list_help.stderr index 7ffe1287eb3..e87cbd37a99 100644 --- a/tests/ui/repr/invalid_repr_list_help.stderr +++ b/tests/ui/repr/invalid_repr_list_help.stderr @@ -30,15 +30,13 @@ LL | #[repr(uwu, u8)] | = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` -warning: unknown `doc` attribute `owo` +error: unknown `doc` attribute `owo` --> $DIR/invalid_repr_list_help.rs:20:7 | LL | #[doc(owo)] | ^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 - = note: `#[warn(invalid_doc_attributes)]` on by default + = note: `#[deny(invalid_doc_attributes)]` on by default error[E0552]: unrecognized representation hint --> $DIR/invalid_repr_list_help.rs:19:8 @@ -48,6 +46,6 @@ LL | #[repr(uwu)] | = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0552`. diff --git a/tests/ui/rustdoc/deny-invalid-doc-attrs.rs b/tests/ui/rustdoc/deny-invalid-doc-attrs.rs index 02e9c67915f..15bfd723424 100644 --- a/tests/ui/rustdoc/deny-invalid-doc-attrs.rs +++ b/tests/ui/rustdoc/deny-invalid-doc-attrs.rs @@ -2,6 +2,4 @@ //~^ NOTE defined here #![doc(x)] //~^ ERROR unknown `doc` attribute `x` -//~| WARNING will become a hard error -//~| NOTE see issue #82730 fn main() {} diff --git a/tests/ui/rustdoc/deny-invalid-doc-attrs.stderr b/tests/ui/rustdoc/deny-invalid-doc-attrs.stderr index bf104f48be0..0884e9c8bb2 100644 --- a/tests/ui/rustdoc/deny-invalid-doc-attrs.stderr +++ b/tests/ui/rustdoc/deny-invalid-doc-attrs.stderr @@ -4,8 +4,6 @@ error: unknown `doc` attribute `x` LL | #![doc(x)] | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 note: the lint level is defined here --> $DIR/deny-invalid-doc-attrs.rs:1:9 | diff --git a/tests/ui/rustdoc/doc-primitive.rs b/tests/ui/rustdoc/doc-primitive.rs index 4336961e3b5..fbb1e1bc1fa 100644 --- a/tests/ui/rustdoc/doc-primitive.rs +++ b/tests/ui/rustdoc/doc-primitive.rs @@ -2,7 +2,6 @@ #[doc(primitive = "foo")] //~^ ERROR unknown `doc` attribute `primitive` -//~| WARN mod bar {} fn main() {} diff --git a/tests/ui/rustdoc/doc-primitive.stderr b/tests/ui/rustdoc/doc-primitive.stderr index 5f535206d26..8f6f330b3e5 100644 --- a/tests/ui/rustdoc/doc-primitive.stderr +++ b/tests/ui/rustdoc/doc-primitive.stderr @@ -4,8 +4,6 @@ error: unknown `doc` attribute `primitive` LL | #[doc(primitive = "foo")] | ^^^^^^^^^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 note: the lint level is defined here --> $DIR/doc-primitive.rs:1:9 | diff --git a/tests/ui/rustdoc/doc-test-attr.rs b/tests/ui/rustdoc/doc-test-attr.rs index 46178ad865a..fb3db6a80fa 100644 --- a/tests/ui/rustdoc/doc-test-attr.rs +++ b/tests/ui/rustdoc/doc-test-attr.rs @@ -3,12 +3,9 @@ #![doc(test)] //~^ ERROR `#[doc(test(...)]` takes a list of attributes -//~^^ WARN this was previously accepted by the compiler #![doc(test = "hello")] //~^ ERROR `#[doc(test(...)]` takes a list of attributes -//~^^ WARN this was previously accepted by the compiler #![doc(test(a))] //~^ ERROR unknown `doc(test)` attribute `a` -//~^^ WARN this was previously accepted by the compiler pub fn foo() {} diff --git a/tests/ui/rustdoc/doc-test-attr.stderr b/tests/ui/rustdoc/doc-test-attr.stderr index 5e6014954a4..51672314a43 100644 --- a/tests/ui/rustdoc/doc-test-attr.stderr +++ b/tests/ui/rustdoc/doc-test-attr.stderr @@ -4,8 +4,6 @@ error: `#[doc(test(...)]` takes a list of attributes LL | #![doc(test)] | ^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 note: the lint level is defined here --> $DIR/doc-test-attr.rs:2:9 | @@ -13,22 +11,16 @@ LL | #![deny(invalid_doc_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^ error: `#[doc(test(...)]` takes a list of attributes - --> $DIR/doc-test-attr.rs:7:8 + --> $DIR/doc-test-attr.rs:6:8 | LL | #![doc(test = "hello")] | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: unknown `doc(test)` attribute `a` - --> $DIR/doc-test-attr.rs:10:13 + --> $DIR/doc-test-attr.rs:8:13 | LL | #![doc(test(a))] | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #82730 error: aborting due to 3 previous errors From 6d75f54310367cc09e49967039a98fbd167034ca Mon Sep 17 00:00:00 2001 From: Ramon de C Valle Date: Thu, 29 Feb 2024 11:40:20 -0800 Subject: [PATCH 14/18] Move sanitizer ui tests to sanitizer directory Moves the sanitizer ui tests to the sanitizer directory and removes the sanitizer prefix from tests file names similarly to how the sanitizer codegen tests are organized. --- src/tools/tidy/src/issues.txt | 6 +++--- tests/ui/{sanitize => sanitizer}/address.rs | 0 tests/ui/{sanitize => sanitizer}/badfree.rs | 0 tests/ui/{sanitize => sanitizer}/cfg-kasan.rs | 0 tests/ui/{sanitize => sanitizer}/cfg.rs | 0 .../cfi-canonical-jump-tables-requires-cfi.rs} | 0 .../cfi-canonical-jump-tables-requires-cfi.stderr} | 0 .../cfi-generalize-pointers-attr-cfg.rs} | 0 .../cfi-generalize-pointers-requires-cfi.rs} | 0 .../cfi-generalize-pointers-requires-cfi.stderr} | 0 .../cfi-invalid-attr-cfi-encoding.rs} | 0 .../cfi-invalid-attr-cfi-encoding.stderr} | 2 +- .../cfi-is-incompatible-with-kcfi.aarch64.stderr} | 0 .../cfi-is-incompatible-with-kcfi.rs} | 0 .../cfi-is-incompatible-with-kcfi.x86_64.stderr} | 0 .../cfi-normalize-integers-attr-cfg.rs} | 0 .../cfi-normalize-integers-requires-cfi.rs} | 0 .../cfi-normalize-integers-requires-cfi.stderr} | 0 .../cfi-requires-lto.rs} | 0 .../cfi-requires-lto.stderr} | 0 .../cfi-with-rustc-lto-requires-single-codegen-unit.rs} | 0 .../cfi-with-rustc-lto-requires-single-codegen-unit.stderr} | 0 tests/ui/{sanitize => sanitizer}/crt-static.rs | 0 tests/ui/{sanitize => sanitizer}/crt-static.stderr | 0 tests/ui/{sanitize => sanitizer}/hwaddress.rs | 0 tests/ui/{sanitize => sanitizer}/incompatible.rs | 0 tests/ui/{sanitize => sanitizer}/incompatible.stderr | 0 tests/ui/{sanitize => sanitizer}/inline-always.rs | 0 tests/ui/{sanitize => sanitizer}/inline-always.stderr | 0 .../issue-111184-cfi-coroutine-witness.rs} | 0 .../issue-114275-cfi-const-expr-in-arry-len.rs | 0 .../issue-72154-address-lifetime-markers.rs} | 0 tests/ui/{sanitize => sanitizer}/leak.rs | 0 tests/ui/{sanitize => sanitizer}/memory-eager.rs | 0 tests/ui/{sanitize => sanitizer}/memory-passing.rs | 0 tests/ui/{sanitize => sanitizer}/memory.rs | 0 .../new-llvm-pass-manager-thin-lto.rs | 0 .../{sanitize => sanitizer}/split-lto-unit-requires-lto.rs | 0 .../split-lto-unit-requires-lto.stderr | 0 tests/ui/{sanitize => sanitizer}/thread.rs | 0 tests/ui/{sanitize => sanitizer}/unsupported-target.rs | 0 tests/ui/{sanitize => sanitizer}/unsupported-target.stderr | 0 tests/ui/{sanitize => sanitizer}/use-after-scope.rs | 0 43 files changed, 4 insertions(+), 4 deletions(-) rename tests/ui/{sanitize => sanitizer}/address.rs (100%) rename tests/ui/{sanitize => sanitizer}/badfree.rs (100%) rename tests/ui/{sanitize => sanitizer}/cfg-kasan.rs (100%) rename tests/ui/{sanitize => sanitizer}/cfg.rs (100%) rename tests/ui/{sanitize/sanitizer-cfi-canonical-jump-tables-require-cfi.rs => sanitizer/cfi-canonical-jump-tables-requires-cfi.rs} (100%) rename tests/ui/{sanitize/sanitizer-cfi-canonical-jump-tables-require-cfi.stderr => sanitizer/cfi-canonical-jump-tables-requires-cfi.stderr} (100%) rename tests/ui/{sanitize/sanitizer-cfi-generalize-pointers-attr-cfg.rs => sanitizer/cfi-generalize-pointers-attr-cfg.rs} (100%) rename tests/ui/{sanitize/sanitizer-cfi-generalize-pointers-require-cfi.rs => sanitizer/cfi-generalize-pointers-requires-cfi.rs} (100%) rename tests/ui/{sanitize/sanitizer-cfi-generalize-pointers-require-cfi.stderr => sanitizer/cfi-generalize-pointers-requires-cfi.stderr} (100%) rename tests/ui/{sanitize/sanitizer-cfi-invalid-attr-cfi-encoding.rs => sanitizer/cfi-invalid-attr-cfi-encoding.rs} (100%) rename tests/ui/{sanitize/sanitizer-cfi-invalid-attr-cfi-encoding.stderr => sanitizer/cfi-invalid-attr-cfi-encoding.stderr} (76%) rename tests/ui/{sanitize/sanitizer-cfi-is-incompatible-with-sanitizer-kcfi.aarch64.stderr => sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr} (100%) rename tests/ui/{sanitize/sanitizer-cfi-is-incompatible-with-sanitizer-kcfi.rs => sanitizer/cfi-is-incompatible-with-kcfi.rs} (100%) rename tests/ui/{sanitize/sanitizer-cfi-is-incompatible-with-sanitizer-kcfi.x86_64.stderr => sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr} (100%) rename tests/ui/{sanitize/sanitizer-cfi-normalize-integers-attr-cfg.rs => sanitizer/cfi-normalize-integers-attr-cfg.rs} (100%) rename tests/ui/{sanitize/sanitizer-cfi-normalize-integers-require-cfi.rs => sanitizer/cfi-normalize-integers-requires-cfi.rs} (100%) rename tests/ui/{sanitize/sanitizer-cfi-normalize-integers-require-cfi.stderr => sanitizer/cfi-normalize-integers-requires-cfi.stderr} (100%) rename tests/ui/{sanitize/sanitizer-cfi-requires-lto.rs => sanitizer/cfi-requires-lto.rs} (100%) rename tests/ui/{sanitize/sanitizer-cfi-requires-lto.stderr => sanitizer/cfi-requires-lto.stderr} (100%) rename tests/ui/{sanitize/sanitizer-cfi-with-rustc-lto-requires-single-codegen-unit.rs => sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.rs} (100%) rename tests/ui/{sanitize/sanitizer-cfi-with-rustc-lto-requires-single-codegen-unit.stderr => sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.stderr} (100%) rename tests/ui/{sanitize => sanitizer}/crt-static.rs (100%) rename tests/ui/{sanitize => sanitizer}/crt-static.stderr (100%) rename tests/ui/{sanitize => sanitizer}/hwaddress.rs (100%) rename tests/ui/{sanitize => sanitizer}/incompatible.rs (100%) rename tests/ui/{sanitize => sanitizer}/incompatible.stderr (100%) rename tests/ui/{sanitize => sanitizer}/inline-always.rs (100%) rename tests/ui/{sanitize => sanitizer}/inline-always.stderr (100%) rename tests/ui/{sanitize/issue-111184-coroutine-witness.rs => sanitizer/issue-111184-cfi-coroutine-witness.rs} (100%) rename tests/ui/{sanitize => sanitizer}/issue-114275-cfi-const-expr-in-arry-len.rs (100%) rename tests/ui/{sanitize/issue-72154-lifetime-markers.rs => sanitizer/issue-72154-address-lifetime-markers.rs} (100%) rename tests/ui/{sanitize => sanitizer}/leak.rs (100%) rename tests/ui/{sanitize => sanitizer}/memory-eager.rs (100%) rename tests/ui/{sanitize => sanitizer}/memory-passing.rs (100%) rename tests/ui/{sanitize => sanitizer}/memory.rs (100%) rename tests/ui/{sanitize => sanitizer}/new-llvm-pass-manager-thin-lto.rs (100%) rename tests/ui/{sanitize => sanitizer}/split-lto-unit-requires-lto.rs (100%) rename tests/ui/{sanitize => sanitizer}/split-lto-unit-requires-lto.stderr (100%) rename tests/ui/{sanitize => sanitizer}/thread.rs (100%) rename tests/ui/{sanitize => sanitizer}/unsupported-target.rs (100%) rename tests/ui/{sanitize => sanitizer}/unsupported-target.stderr (100%) rename tests/ui/{sanitize => sanitizer}/use-after-scope.rs (100%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 51af8898470..dd45d00f935 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3797,9 +3797,9 @@ "ui/rust-2018/uniform-paths/issue-56596-2.rs", "ui/rust-2018/uniform-paths/issue-56596.rs", "ui/rust-2018/uniform-paths/issue-87932.rs", -"ui/sanitize/issue-111184-coroutine-witness.rs", -"ui/sanitize/issue-114275-cfi-const-expr-in-arry-len.rs", -"ui/sanitize/issue-72154-lifetime-markers.rs", +"ui/sanitizer/issue-111184-cfi-coroutine-witness.rs", +"ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs", +"ui/sanitizer/issue-72154-address-lifetime-markers.rs", "ui/self/issue-61882-2.rs", "ui/self/issue-61882.rs", "ui/simd/intrinsic/issue-85855.rs", diff --git a/tests/ui/sanitize/address.rs b/tests/ui/sanitizer/address.rs similarity index 100% rename from tests/ui/sanitize/address.rs rename to tests/ui/sanitizer/address.rs diff --git a/tests/ui/sanitize/badfree.rs b/tests/ui/sanitizer/badfree.rs similarity index 100% rename from tests/ui/sanitize/badfree.rs rename to tests/ui/sanitizer/badfree.rs diff --git a/tests/ui/sanitize/cfg-kasan.rs b/tests/ui/sanitizer/cfg-kasan.rs similarity index 100% rename from tests/ui/sanitize/cfg-kasan.rs rename to tests/ui/sanitizer/cfg-kasan.rs diff --git a/tests/ui/sanitize/cfg.rs b/tests/ui/sanitizer/cfg.rs similarity index 100% rename from tests/ui/sanitize/cfg.rs rename to tests/ui/sanitizer/cfg.rs diff --git a/tests/ui/sanitize/sanitizer-cfi-canonical-jump-tables-require-cfi.rs b/tests/ui/sanitizer/cfi-canonical-jump-tables-requires-cfi.rs similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-canonical-jump-tables-require-cfi.rs rename to tests/ui/sanitizer/cfi-canonical-jump-tables-requires-cfi.rs diff --git a/tests/ui/sanitize/sanitizer-cfi-canonical-jump-tables-require-cfi.stderr b/tests/ui/sanitizer/cfi-canonical-jump-tables-requires-cfi.stderr similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-canonical-jump-tables-require-cfi.stderr rename to tests/ui/sanitizer/cfi-canonical-jump-tables-requires-cfi.stderr diff --git a/tests/ui/sanitize/sanitizer-cfi-generalize-pointers-attr-cfg.rs b/tests/ui/sanitizer/cfi-generalize-pointers-attr-cfg.rs similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-generalize-pointers-attr-cfg.rs rename to tests/ui/sanitizer/cfi-generalize-pointers-attr-cfg.rs diff --git a/tests/ui/sanitize/sanitizer-cfi-generalize-pointers-require-cfi.rs b/tests/ui/sanitizer/cfi-generalize-pointers-requires-cfi.rs similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-generalize-pointers-require-cfi.rs rename to tests/ui/sanitizer/cfi-generalize-pointers-requires-cfi.rs diff --git a/tests/ui/sanitize/sanitizer-cfi-generalize-pointers-require-cfi.stderr b/tests/ui/sanitizer/cfi-generalize-pointers-requires-cfi.stderr similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-generalize-pointers-require-cfi.stderr rename to tests/ui/sanitizer/cfi-generalize-pointers-requires-cfi.stderr diff --git a/tests/ui/sanitize/sanitizer-cfi-invalid-attr-cfi-encoding.rs b/tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.rs similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-invalid-attr-cfi-encoding.rs rename to tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.rs diff --git a/tests/ui/sanitize/sanitizer-cfi-invalid-attr-cfi-encoding.stderr b/tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.stderr similarity index 76% rename from tests/ui/sanitize/sanitizer-cfi-invalid-attr-cfi-encoding.stderr rename to tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.stderr index b9e9722da23..93ec134241e 100644 --- a/tests/ui/sanitize/sanitizer-cfi-invalid-attr-cfi-encoding.stderr +++ b/tests/ui/sanitizer/cfi-invalid-attr-cfi-encoding.stderr @@ -1,5 +1,5 @@ error: malformed `cfi_encoding` attribute input - --> $DIR/sanitizer-cfi-invalid-attr-cfi-encoding.rs:10:1 + --> $DIR/cfi-invalid-attr-cfi-encoding.rs:10:1 | LL | #[cfi_encoding] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]` diff --git a/tests/ui/sanitize/sanitizer-cfi-is-incompatible-with-sanitizer-kcfi.aarch64.stderr b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-is-incompatible-with-sanitizer-kcfi.aarch64.stderr rename to tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr diff --git a/tests/ui/sanitize/sanitizer-cfi-is-incompatible-with-sanitizer-kcfi.rs b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.rs similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-is-incompatible-with-sanitizer-kcfi.rs rename to tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.rs diff --git a/tests/ui/sanitize/sanitizer-cfi-is-incompatible-with-sanitizer-kcfi.x86_64.stderr b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-is-incompatible-with-sanitizer-kcfi.x86_64.stderr rename to tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr diff --git a/tests/ui/sanitize/sanitizer-cfi-normalize-integers-attr-cfg.rs b/tests/ui/sanitizer/cfi-normalize-integers-attr-cfg.rs similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-normalize-integers-attr-cfg.rs rename to tests/ui/sanitizer/cfi-normalize-integers-attr-cfg.rs diff --git a/tests/ui/sanitize/sanitizer-cfi-normalize-integers-require-cfi.rs b/tests/ui/sanitizer/cfi-normalize-integers-requires-cfi.rs similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-normalize-integers-require-cfi.rs rename to tests/ui/sanitizer/cfi-normalize-integers-requires-cfi.rs diff --git a/tests/ui/sanitize/sanitizer-cfi-normalize-integers-require-cfi.stderr b/tests/ui/sanitizer/cfi-normalize-integers-requires-cfi.stderr similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-normalize-integers-require-cfi.stderr rename to tests/ui/sanitizer/cfi-normalize-integers-requires-cfi.stderr diff --git a/tests/ui/sanitize/sanitizer-cfi-requires-lto.rs b/tests/ui/sanitizer/cfi-requires-lto.rs similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-requires-lto.rs rename to tests/ui/sanitizer/cfi-requires-lto.rs diff --git a/tests/ui/sanitize/sanitizer-cfi-requires-lto.stderr b/tests/ui/sanitizer/cfi-requires-lto.stderr similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-requires-lto.stderr rename to tests/ui/sanitizer/cfi-requires-lto.stderr diff --git a/tests/ui/sanitize/sanitizer-cfi-with-rustc-lto-requires-single-codegen-unit.rs b/tests/ui/sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.rs similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-with-rustc-lto-requires-single-codegen-unit.rs rename to tests/ui/sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.rs diff --git a/tests/ui/sanitize/sanitizer-cfi-with-rustc-lto-requires-single-codegen-unit.stderr b/tests/ui/sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.stderr similarity index 100% rename from tests/ui/sanitize/sanitizer-cfi-with-rustc-lto-requires-single-codegen-unit.stderr rename to tests/ui/sanitizer/cfi-with-rustc-lto-requires-single-codegen-unit.stderr diff --git a/tests/ui/sanitize/crt-static.rs b/tests/ui/sanitizer/crt-static.rs similarity index 100% rename from tests/ui/sanitize/crt-static.rs rename to tests/ui/sanitizer/crt-static.rs diff --git a/tests/ui/sanitize/crt-static.stderr b/tests/ui/sanitizer/crt-static.stderr similarity index 100% rename from tests/ui/sanitize/crt-static.stderr rename to tests/ui/sanitizer/crt-static.stderr diff --git a/tests/ui/sanitize/hwaddress.rs b/tests/ui/sanitizer/hwaddress.rs similarity index 100% rename from tests/ui/sanitize/hwaddress.rs rename to tests/ui/sanitizer/hwaddress.rs diff --git a/tests/ui/sanitize/incompatible.rs b/tests/ui/sanitizer/incompatible.rs similarity index 100% rename from tests/ui/sanitize/incompatible.rs rename to tests/ui/sanitizer/incompatible.rs diff --git a/tests/ui/sanitize/incompatible.stderr b/tests/ui/sanitizer/incompatible.stderr similarity index 100% rename from tests/ui/sanitize/incompatible.stderr rename to tests/ui/sanitizer/incompatible.stderr diff --git a/tests/ui/sanitize/inline-always.rs b/tests/ui/sanitizer/inline-always.rs similarity index 100% rename from tests/ui/sanitize/inline-always.rs rename to tests/ui/sanitizer/inline-always.rs diff --git a/tests/ui/sanitize/inline-always.stderr b/tests/ui/sanitizer/inline-always.stderr similarity index 100% rename from tests/ui/sanitize/inline-always.stderr rename to tests/ui/sanitizer/inline-always.stderr diff --git a/tests/ui/sanitize/issue-111184-coroutine-witness.rs b/tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs similarity index 100% rename from tests/ui/sanitize/issue-111184-coroutine-witness.rs rename to tests/ui/sanitizer/issue-111184-cfi-coroutine-witness.rs diff --git a/tests/ui/sanitize/issue-114275-cfi-const-expr-in-arry-len.rs b/tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs similarity index 100% rename from tests/ui/sanitize/issue-114275-cfi-const-expr-in-arry-len.rs rename to tests/ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs diff --git a/tests/ui/sanitize/issue-72154-lifetime-markers.rs b/tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs similarity index 100% rename from tests/ui/sanitize/issue-72154-lifetime-markers.rs rename to tests/ui/sanitizer/issue-72154-address-lifetime-markers.rs diff --git a/tests/ui/sanitize/leak.rs b/tests/ui/sanitizer/leak.rs similarity index 100% rename from tests/ui/sanitize/leak.rs rename to tests/ui/sanitizer/leak.rs diff --git a/tests/ui/sanitize/memory-eager.rs b/tests/ui/sanitizer/memory-eager.rs similarity index 100% rename from tests/ui/sanitize/memory-eager.rs rename to tests/ui/sanitizer/memory-eager.rs diff --git a/tests/ui/sanitize/memory-passing.rs b/tests/ui/sanitizer/memory-passing.rs similarity index 100% rename from tests/ui/sanitize/memory-passing.rs rename to tests/ui/sanitizer/memory-passing.rs diff --git a/tests/ui/sanitize/memory.rs b/tests/ui/sanitizer/memory.rs similarity index 100% rename from tests/ui/sanitize/memory.rs rename to tests/ui/sanitizer/memory.rs diff --git a/tests/ui/sanitize/new-llvm-pass-manager-thin-lto.rs b/tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs similarity index 100% rename from tests/ui/sanitize/new-llvm-pass-manager-thin-lto.rs rename to tests/ui/sanitizer/new-llvm-pass-manager-thin-lto.rs diff --git a/tests/ui/sanitize/split-lto-unit-requires-lto.rs b/tests/ui/sanitizer/split-lto-unit-requires-lto.rs similarity index 100% rename from tests/ui/sanitize/split-lto-unit-requires-lto.rs rename to tests/ui/sanitizer/split-lto-unit-requires-lto.rs diff --git a/tests/ui/sanitize/split-lto-unit-requires-lto.stderr b/tests/ui/sanitizer/split-lto-unit-requires-lto.stderr similarity index 100% rename from tests/ui/sanitize/split-lto-unit-requires-lto.stderr rename to tests/ui/sanitizer/split-lto-unit-requires-lto.stderr diff --git a/tests/ui/sanitize/thread.rs b/tests/ui/sanitizer/thread.rs similarity index 100% rename from tests/ui/sanitize/thread.rs rename to tests/ui/sanitizer/thread.rs diff --git a/tests/ui/sanitize/unsupported-target.rs b/tests/ui/sanitizer/unsupported-target.rs similarity index 100% rename from tests/ui/sanitize/unsupported-target.rs rename to tests/ui/sanitizer/unsupported-target.rs diff --git a/tests/ui/sanitize/unsupported-target.stderr b/tests/ui/sanitizer/unsupported-target.stderr similarity index 100% rename from tests/ui/sanitize/unsupported-target.stderr rename to tests/ui/sanitizer/unsupported-target.stderr diff --git a/tests/ui/sanitize/use-after-scope.rs b/tests/ui/sanitizer/use-after-scope.rs similarity index 100% rename from tests/ui/sanitize/use-after-scope.rs rename to tests/ui/sanitizer/use-after-scope.rs From dab3d5bb281bd4be59b68adaa6f1f003c20ea303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 28 Feb 2024 22:32:29 +0000 Subject: [PATCH 15/18] Never say "`Trait` is implemented for `{type error}`" When a trait bound error occurs, we look for alternative types that would have made the bound succeed. For some reason `{type error}` sometimes would appear as a type that would do so. We now remove `{type error}` from the list in every case to avoid nonsensical `note`s. --- .../src/traits/error_reporting/type_err_ctxt_ext.rs | 6 +++++- tests/ui/associated-consts/issue-105330.stderr | 2 -- 2 files changed, 5 insertions(+), 3 deletions(-) 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 dcbb63f00f7..de3231a0e86 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 @@ -1908,6 +1908,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), }, ); + if cand.references_error() { + return false; + } err.highlighted_help(vec![ StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())), StringPart::highlighted("is"), @@ -1932,7 +1935,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } let other = if other { "other " } else { "" }; - let report = |candidates: Vec>, err: &mut Diag<'_>| { + let report = |mut candidates: Vec>, err: &mut Diag<'_>| { + candidates.retain(|tr| !tr.references_error()); if candidates.is_empty() { return false; } diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr index 50ce69b3381..bde3675b48c 100644 --- a/tests/ui/associated-consts/issue-105330.stderr +++ b/tests/ui/associated-consts/issue-105330.stderr @@ -55,7 +55,6 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied LL | foo::()(); | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo` | - = help: the trait `TraitWAssocConst` is implemented for `{type error}` note: required by a bound in `foo` --> $DIR/issue-105330.rs:11:11 | @@ -92,7 +91,6 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied LL | foo::(); | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo` | - = help: the trait `TraitWAssocConst` is implemented for `{type error}` note: required by a bound in `foo` --> $DIR/issue-105330.rs:11:11 | From 367126d49af3237eee24889191dfbb02dfc9320c Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 26 Jan 2024 15:32:59 +0000 Subject: [PATCH 16/18] If suggestion would leave an empty line, delete it --- compiler/rustc_errors/src/json.rs | 12 ++++++- .../clippy/tests/ui/derivable_impls.fixed | 8 ----- src/tools/clippy/tests/ui/empty_drop.fixed | 2 -- src/tools/clippy/tests/ui/must_use_unit.fixed | 3 -- .../ui/single_component_path_imports.fixed | 1 - .../ui/associated-types/impl-wf-cycle-6.fixed | 1 - tests/ui/generics/generic-no-mangle.fixed | 2 -- tests/ui/imports/issue-52891.fixed | 2 -- .../imports/unused-import-issue-87973.fixed | 1 - .../leading-where-clause.fixed | 2 -- tests/ui/lint/suggestions.fixed | 1 - tests/ui/lint/unused/import_remove_line.fixed | 11 +++++++ tests/ui/lint/unused/import_remove_line.rs | 13 ++++++++ .../ui/lint/unused/import_remove_line.stderr | 32 +++++++++++++++++++ .../resolve-conflict-import-vs-import.fixed | 1 - .../extern-crate-idiomatic-in-2018.fixed | 1 - ...-54400-unused-extern-crate-attr-span.fixed | 1 - 17 files changed, 67 insertions(+), 27 deletions(-) create mode 100644 tests/ui/lint/unused/import_remove_line.fixed create mode 100644 tests/ui/lint/unused/import_remove_line.rs create mode 100644 tests/ui/lint/unused/import_remove_line.stderr diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index bc1822f83fc..af82d8092c2 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -428,7 +428,7 @@ impl DiagnosticSpan { } fn from_span_full( - span: Span, + mut span: Span, is_primary: bool, label: Option, suggestion: Option<(&String, Applicability)>, @@ -436,6 +436,16 @@ impl DiagnosticSpan { je: &JsonEmitter, ) -> DiagnosticSpan { let start = je.sm.lookup_char_pos(span.lo()); + // If this goes from the start of a line to the end and the replacement + // is an empty string, increase the length to include the newline so we don't + // leave an empty line + if start.col.0 == 0 + && suggestion.map_or(false, |(s, _)| s.is_empty()) + && let Ok(after) = je.sm.span_to_next_source(span) + && after.starts_with('\n') + { + span = span.with_hi(span.hi() + rustc_span::BytePos(1)); + } let end = je.sm.lookup_char_pos(span.hi()); let backtrace_step = backtrace.next().map(|bt| { let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je); diff --git a/src/tools/clippy/tests/ui/derivable_impls.fixed b/src/tools/clippy/tests/ui/derivable_impls.fixed index 68c5a5c5ca4..c85f384fd6e 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.fixed +++ b/src/tools/clippy/tests/ui/derivable_impls.fixed @@ -19,12 +19,10 @@ struct FooDefault<'a> { } - #[derive(Default)] struct TupleDefault(bool, i32, u64); - struct FooND1 { a: bool, } @@ -73,7 +71,6 @@ impl Default for FooNDVec { struct StrDefault<'a>(&'a str); - #[derive(Default)] struct AlreadyDerived(i32, bool); @@ -96,7 +93,6 @@ mac!(0); #[derive(Default)] struct Y(u32); - struct RustIssue26925 { a: Option, } @@ -132,12 +128,10 @@ struct WithoutSelfCurly { } - #[derive(Default)] struct WithoutSelfParan(bool); - // https://github.com/rust-lang/rust-clippy/issues/7655 pub struct SpecializedImpl2 { @@ -184,7 +178,6 @@ pub struct RepeatDefault1 { } - pub struct RepeatDefault2 { a: [i8; 33], } @@ -216,7 +209,6 @@ pub enum SimpleEnum { } - pub enum NonExhaustiveEnum { Foo, #[non_exhaustive] diff --git a/src/tools/clippy/tests/ui/empty_drop.fixed b/src/tools/clippy/tests/ui/empty_drop.fixed index 949d0d8b399..17cfdcdc9c6 100644 --- a/src/tools/clippy/tests/ui/empty_drop.fixed +++ b/src/tools/clippy/tests/ui/empty_drop.fixed @@ -5,7 +5,6 @@ struct Foo; - // shouldn't cause an error struct Bar; @@ -19,5 +18,4 @@ impl Drop for Bar { struct Baz; - fn main() {} diff --git a/src/tools/clippy/tests/ui/must_use_unit.fixed b/src/tools/clippy/tests/ui/must_use_unit.fixed index 75f91e66824..f255cb66652 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.fixed +++ b/src/tools/clippy/tests/ui/must_use_unit.fixed @@ -6,13 +6,10 @@ extern crate proc_macros; use proc_macros::external; - pub fn must_use_default() {} - pub fn must_use_unit() -> () {} - pub fn must_use_with_note() {} fn main() { diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.fixed b/src/tools/clippy/tests/ui/single_component_path_imports.fixed index fdff336c281..3e81bcd5e48 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports.fixed +++ b/src/tools/clippy/tests/ui/single_component_path_imports.fixed @@ -4,7 +4,6 @@ use core; - use serde as edres; pub use serde; diff --git a/tests/ui/associated-types/impl-wf-cycle-6.fixed b/tests/ui/associated-types/impl-wf-cycle-6.fixed index 45143be1e74..ce98b9c2f02 100644 --- a/tests/ui/associated-types/impl-wf-cycle-6.fixed +++ b/tests/ui/associated-types/impl-wf-cycle-6.fixed @@ -21,7 +21,6 @@ impl Grault for () { impl Grault for (T,) //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` - { type A = (); type B = bool; diff --git a/tests/ui/generics/generic-no-mangle.fixed b/tests/ui/generics/generic-no-mangle.fixed index f20ea0edaa6..69db712f9dc 100644 --- a/tests/ui/generics/generic-no-mangle.fixed +++ b/tests/ui/generics/generic-no-mangle.fixed @@ -2,10 +2,8 @@ #![allow(dead_code)] #![deny(no_mangle_generic_items)] - pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled - pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled #[no_mangle] diff --git a/tests/ui/imports/issue-52891.fixed b/tests/ui/imports/issue-52891.fixed index 9faef1703ac..0382960db2f 100644 --- a/tests/ui/imports/issue-52891.fixed +++ b/tests/ui/imports/issue-52891.fixed @@ -27,10 +27,8 @@ use issue_52891::{l, use issue_52891::a::inner; use issue_52891::b::inner as other_inner; //~ ERROR `inner` is defined multiple times - //~^ ERROR `issue_52891` is defined multiple times - #[macro_use] use issue_52891::n; //~ ERROR `n` is defined multiple times diff --git a/tests/ui/imports/unused-import-issue-87973.fixed b/tests/ui/imports/unused-import-issue-87973.fixed index 96508fa3ea2..d1167d7d486 100644 --- a/tests/ui/imports/unused-import-issue-87973.fixed +++ b/tests/ui/imports/unused-import-issue-87973.fixed @@ -2,7 +2,6 @@ #![deny(unused_imports)] // Check that attributes get removed too. See #87973. - //~^ ERROR unused import fn main() {} diff --git a/tests/ui/lazy-type-alias/leading-where-clause.fixed b/tests/ui/lazy-type-alias/leading-where-clause.fixed index ca0ab7b5c7d..003eaa6c54e 100644 --- a/tests/ui/lazy-type-alias/leading-where-clause.fixed +++ b/tests/ui/lazy-type-alias/leading-where-clause.fixed @@ -7,11 +7,9 @@ // Check that we *reject* leading where-clauses on lazy type aliases. pub type Leading0 - = T where String: From; pub type Leading1 - = (T, U) where U: Copy, String: From; diff --git a/tests/ui/lint/suggestions.fixed b/tests/ui/lint/suggestions.fixed index b017438a8bd..66d097b121f 100644 --- a/tests/ui/lint/suggestions.fixed +++ b/tests/ui/lint/suggestions.fixed @@ -7,7 +7,6 @@ //~^ ERROR const items should never be `#[no_mangle]` //~| HELP try a static value - //~^ HELP remove this attribute pub fn defiant(_t: T) {} //~^ WARN functions generic over types or consts must be mangled diff --git a/tests/ui/lint/unused/import_remove_line.fixed b/tests/ui/lint/unused/import_remove_line.fixed new file mode 100644 index 00000000000..45876cd4ebc --- /dev/null +++ b/tests/ui/lint/unused/import_remove_line.fixed @@ -0,0 +1,11 @@ +//@ run-rustfix +//@ check-pass + +#![crate_type = "lib"] +#![warn(unused_imports)] + +//~^ WARN unused imports +//~^ WARN unused import + +//~^ WARN unused import +//~| WARN unused import diff --git a/tests/ui/lint/unused/import_remove_line.rs b/tests/ui/lint/unused/import_remove_line.rs new file mode 100644 index 00000000000..fd45f04eb80 --- /dev/null +++ b/tests/ui/lint/unused/import_remove_line.rs @@ -0,0 +1,13 @@ +//@ run-rustfix +//@ check-pass + +#![crate_type = "lib"] +#![warn(unused_imports)] + +use std::time::{Duration, Instant}; +//~^ WARN unused imports +use std::time::SystemTime; +//~^ WARN unused import +use std::time::SystemTimeError;use std::time::TryFromFloatSecsError; +//~^ WARN unused import +//~| WARN unused import diff --git a/tests/ui/lint/unused/import_remove_line.stderr b/tests/ui/lint/unused/import_remove_line.stderr new file mode 100644 index 00000000000..0e8c5de3558 --- /dev/null +++ b/tests/ui/lint/unused/import_remove_line.stderr @@ -0,0 +1,32 @@ +warning: unused imports: `Duration`, `Instant` + --> $DIR/import_remove_line.rs:7:17 + | +LL | use std::time::{Duration, Instant}; + | ^^^^^^^^ ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/import_remove_line.rs:5:9 + | +LL | #![warn(unused_imports)] + | ^^^^^^^^^^^^^^ + +warning: unused import: `std::time::SystemTime` + --> $DIR/import_remove_line.rs:9:5 + | +LL | use std::time::SystemTime; + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: unused import: `std::time::SystemTimeError` + --> $DIR/import_remove_line.rs:11:5 + | +LL | use std::time::SystemTimeError;use std::time::TryFromFloatSecsError; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused import: `std::time::TryFromFloatSecsError` + --> $DIR/import_remove_line.rs:11:36 + | +LL | use std::time::SystemTimeError;use std::time::TryFromFloatSecsError; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 4 warnings emitted + diff --git a/tests/ui/resolve/resolve-conflict-import-vs-import.fixed b/tests/ui/resolve/resolve-conflict-import-vs-import.fixed index 2ebf2a194b8..d981d629c46 100644 --- a/tests/ui/resolve/resolve-conflict-import-vs-import.fixed +++ b/tests/ui/resolve/resolve-conflict-import-vs-import.fixed @@ -2,7 +2,6 @@ #[allow(unused_imports)] use std::mem::transmute; - //~^ ERROR the name `transmute` is defined multiple times fn main() { diff --git a/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed b/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed index fcab56ac819..ca8422c03a3 100644 --- a/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed +++ b/tests/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed @@ -9,7 +9,6 @@ #![deny(rust_2018_idioms)] #![allow(dead_code)] - //~^ ERROR unused extern crate // Shouldn't suggest changing to `use`, as `bar` diff --git a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed index 2625cdc8b48..75b3918be1d 100644 --- a/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed +++ b/tests/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.fixed @@ -8,7 +8,6 @@ // The suggestion span should include the attribute. - //~^ ERROR unused extern crate fn main() {} From e3ac2c68b89c95e01440c1ab5fc7897e93a35c41 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 29 Feb 2024 15:23:44 -0800 Subject: [PATCH 17/18] Implement missing ABI structures in StableMIR --- .../rustc_smir/src/rustc_smir/convert/abi.rs | 68 +++++++- compiler/stable_mir/src/abi.rs | 159 +++++++++++++++++- compiler/stable_mir/src/error.rs | 11 +- compiler/stable_mir/src/target.rs | 10 +- compiler/stable_mir/src/ty.rs | 7 +- tests/ui-fulldeps/stable-mir/check_abi.rs | 45 ++++- 6 files changed, 274 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 088a836c901..071c02e0381 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -6,11 +6,12 @@ use crate::rustc_smir::{Stable, Tables}; use rustc_middle::ty; use rustc_target::abi::call::Conv; use stable_mir::abi::{ - ArgAbi, CallConvention, FieldsShape, FnAbi, Layout, LayoutShape, PassMode, TagEncoding, - TyAndLayout, ValueAbi, VariantsShape, + AddressSpace, ArgAbi, CallConvention, FieldsShape, FnAbi, IntegerLength, Layout, LayoutShape, + PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape, WrappingRange, }; -use stable_mir::ty::{Align, IndexedVal, Size, VariantIdx}; -use stable_mir::{opaque, Opaque}; +use stable_mir::opaque; +use stable_mir::target::MachineSize as Size; +use stable_mir::ty::{Align, IndexedVal, VariantIdx}; impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx { type T = VariantIdx; @@ -220,7 +221,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Size { type T = Size; fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { - self.bytes_usize() + Size::from_bits(self.bits_usize()) } } @@ -233,9 +234,60 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Align { } impl<'tcx> Stable<'tcx> for rustc_abi::Scalar { - type T = Opaque; + type T = Scalar; - fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { - opaque(self) + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + match self { + rustc_abi::Scalar::Initialized { value, valid_range } => Scalar::Initialized { + value: value.stable(tables), + valid_range: valid_range.stable(tables), + }, + rustc_abi::Scalar::Union { value } => Scalar::Union { value: value.stable(tables) }, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Primitive { + type T = Primitive; + + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + match self { + rustc_abi::Primitive::Int(length, signed) => { + Primitive::Int { length: length.stable(tables), signed: *signed } + } + rustc_abi::Primitive::F32 => Primitive::F32, + rustc_abi::Primitive::F64 => Primitive::F64, + rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables)), + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::AddressSpace { + type T = AddressSpace; + + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { + AddressSpace(self.0) + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::Integer { + type T = IntegerLength; + + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { + match self { + rustc_abi::Integer::I8 => IntegerLength::I8, + rustc_abi::Integer::I16 => IntegerLength::I16, + rustc_abi::Integer::I32 => IntegerLength::I32, + rustc_abi::Integer::I64 => IntegerLength::I64, + rustc_abi::Integer::I128 => IntegerLength::I128, + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange { + type T = WrappingRange; + + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { + WrappingRange { start: self.start, end: self.end } } } diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index a15fd3e0999..1c5e3275673 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -1,7 +1,11 @@ use crate::compiler_interface::with; +use crate::error; use crate::mir::FieldIdx; -use crate::ty::{Align, IndexedVal, Size, Ty, VariantIdx}; +use crate::target::{MachineInfo, MachineSize as Size}; +use crate::ty::{Align, IndexedVal, Ty, VariantIdx}; +use crate::Error; use crate::Opaque; +use std::fmt::{self, Debug}; use std::num::NonZeroUsize; use std::ops::RangeInclusive; @@ -100,7 +104,7 @@ impl LayoutShape { /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). pub fn is_1zst(&self) -> bool { - self.is_sized() && self.size == 0 && self.abi_align == 1 + self.is_sized() && self.size.bits() == 0 && self.abi_align == 1 } } @@ -245,8 +249,155 @@ impl ValueAbi { } } -/// We currently do not support `Scalar`, and use opaque instead. -type Scalar = Opaque; +/// Information about one scalar component of a Rust type. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum Scalar { + Initialized { + /// The primitive type used to represent this value. + value: Primitive, + /// The range that represents valid values. + /// The range must be valid for the `primitive` size. + valid_range: WrappingRange, + }, + Union { + /// Unions never have niches, so there is no `valid_range`. + /// Even for unions, we need to use the correct registers for the kind of + /// values inside the union, so we keep the `Primitive` type around. + /// It is also used to compute the size of the scalar. + value: Primitive, + }, +} + +impl Scalar { + pub fn has_niche(&self, target: &MachineInfo) -> bool { + match self { + Scalar::Initialized { value, valid_range } => { + !valid_range.is_full(value.size(target)).unwrap() + } + Scalar::Union { .. } => false, + } + } +} + +/// Fundamental unit of memory access and layout. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum Primitive { + /// The `bool` is the signedness of the `Integer` type. + /// + /// One would think we would not care about such details this low down, + /// but some ABIs are described in terms of C types and ISAs where the + /// integer arithmetic is done on {sign,zero}-extended registers, e.g. + /// a negative integer passed by zero-extension will appear positive in + /// the callee, and most operations on it will produce the wrong values. + Int { + length: IntegerLength, + signed: bool, + }, + F32, + F64, + Pointer(AddressSpace), +} + +impl Primitive { + pub fn size(self, target: &MachineInfo) -> Size { + match self { + Primitive::Int { length, .. } => Size::from_bits(length.bits()), + Primitive::F32 => Size::from_bits(32), + Primitive::F64 => Size::from_bits(64), + Primitive::Pointer(_) => target.pointer_width, + } + } +} + +/// Enum representing the existing integer lengths. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum IntegerLength { + I8, + I16, + I32, + I64, + I128, +} + +impl IntegerLength { + pub fn bits(self) -> usize { + match self { + IntegerLength::I8 => 8, + IntegerLength::I16 => 16, + IntegerLength::I32 => 32, + IntegerLength::I64 => 64, + IntegerLength::I128 => 128, + } + } +} + +/// An identifier that specifies the address space that some operation +/// should operate on. Special address spaces have an effect on code generation, +/// depending on the target and the address spaces it implements. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct AddressSpace(pub u32); + +impl AddressSpace { + /// The default address space, corresponding to data space. + pub const DATA: Self = AddressSpace(0); +} + +/// Inclusive wrap-around range of valid values (bitwise representation), that is, if +/// start > end, it represents `start..=MAX`, followed by `0..=end`. +/// +/// That is, for an i8 primitive, a range of `254..=2` means following +/// sequence: +/// +/// 254 (-2), 255 (-1), 0, 1, 2 +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct WrappingRange { + pub start: u128, + pub end: u128, +} + +impl WrappingRange { + /// Returns `true` if `size` completely fills the range. + #[inline] + pub fn is_full(&self, size: Size) -> Result { + let Some(max_value) = size.unsigned_int_max() else { + return Err(error!("Expected size <= 128 bits, but found {} instead", size.bits())); + }; + if self.start <= max_value && self.end <= max_value { + Ok(self.start == 0 && max_value == self.end) + } else { + Err(error!("Range `{self:?}` out of bounds for size `{}` bits.", size.bits())) + } + } + + /// Returns `true` if `v` is contained in the range. + #[inline(always)] + pub fn contains(&self, v: u128) -> bool { + if self.wraps_around() { + self.start <= v || v <= self.end + } else { + self.start <= v && v <= self.end + } + } + + /// Returns `true` if the range wraps around. + /// I.e., the range represents the union of `self.start..=MAX` and `0..=self.end`. + /// Returns `false` if this is a non-wrapping range, i.e.: `self.start..=self.end`. + #[inline] + pub fn wraps_around(&self) -> bool { + self.start > self.end + } +} + +impl Debug for WrappingRange { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.start > self.end { + write!(fmt, "(..={}) | ({}..)", self.end, self.start)?; + } else { + write!(fmt, "{}..={}", self.start, self.end)?; + } + Ok(()) + } +} /// General language calling conventions. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs index 9e3f4936944..050752e41eb 100644 --- a/compiler/stable_mir/src/error.rs +++ b/compiler/stable_mir/src/error.rs @@ -5,12 +5,14 @@ //! - [Error]: Generic error that represents the reason why a request that could not be fulfilled. use std::fmt::{Debug, Display, Formatter}; -use std::{error, fmt, io}; +use std::{fmt, io}; macro_rules! error { ($fmt: literal $(,)?) => { Error(format!($fmt)) }; ($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg)*)) }; - } +} + +pub(crate) use error; /// An error type used to represent an error that has already been reported by the compiler. #[derive(Clone, Copy, PartialEq, Eq)] @@ -72,8 +74,9 @@ where } } -impl error::Error for Error {} -impl error::Error for CompilerError where T: Display + Debug {} +impl std::error::Error for Error {} + +impl std::error::Error for CompilerError where T: Display + Debug {} impl From for Error { fn from(value: io::Error) -> Self { diff --git a/compiler/stable_mir/src/target.rs b/compiler/stable_mir/src/target.rs index 41ec205cfc7..3a9011a2ffe 100644 --- a/compiler/stable_mir/src/target.rs +++ b/compiler/stable_mir/src/target.rs @@ -30,21 +30,29 @@ pub enum Endian { } /// Represent the size of a component. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub struct MachineSize { num_bits: usize, } impl MachineSize { + #[inline(always)] pub fn bytes(self) -> usize { self.num_bits / 8 } + #[inline(always)] pub fn bits(self) -> usize { self.num_bits } + #[inline(always)] pub fn from_bits(num_bits: usize) -> MachineSize { MachineSize { num_bits } } + + #[inline] + pub fn unsigned_int_max(self) -> Option { + (self.num_bits <= 128).then(|| u128::MAX >> (128 - self.bits())) + } } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index ed4a4290246..86cc748eaec 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -324,7 +324,9 @@ impl TyKind { #[inline] pub fn is_cstr(&self) -> bool { - let TyKind::RigidTy(RigidTy::Adt(def, _)) = self else { return false }; + let TyKind::RigidTy(RigidTy::Adt(def, _)) = self else { + return false; + }; with(|cx| cx.adt_is_cstr(*def)) } @@ -1032,10 +1034,13 @@ pub struct BoundTy { } pub type Bytes = Vec>; + +/// Size in bytes. pub type Size = usize; #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub struct Prov(pub AllocId); + pub type Align = u64; pub type Promoted = u32; pub type InitMaskMaterialized = Vec; diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index c345987955e..74801e007c4 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -19,8 +19,12 @@ extern crate rustc_interface; extern crate stable_mir; use rustc_smir::rustc_internal; -use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape}; +use stable_mir::abi::{ + ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi, + VariantsShape, +}; use stable_mir::mir::mono::Instance; +use stable_mir::target::MachineInfo; use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind}; use std::assert_matches::assert_matches; use std::convert::TryFrom; @@ -39,11 +43,12 @@ fn test_stable_mir() -> ControlFlow<()> { let instance = Instance::try_from(target_fn).unwrap(); let fn_abi = instance.fn_abi().unwrap(); assert_eq!(fn_abi.conv, CallConvention::Rust); - assert_eq!(fn_abi.args.len(), 2); + assert_eq!(fn_abi.args.len(), 3); check_ignore(&fn_abi.args[0]); check_primitive(&fn_abi.args[1]); - check_result(fn_abi.ret); + check_niche(&fn_abi.args[2]); + check_result(&fn_abi.ret); // Test variadic function. let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap(); @@ -85,7 +90,7 @@ fn check_primitive(abi: &ArgAbi) { } /// Check the return value: `Result`. -fn check_result(abi: ArgAbi) { +fn check_result(abi: &ArgAbi) { assert!(abi.ty.kind().is_enum()); assert_matches!(abi.mode, PassMode::Indirect { .. }); let layout = abi.layout.shape(); @@ -94,6 +99,25 @@ fn check_result(abi: ArgAbi) { assert_matches!(layout.variants, VariantsShape::Multiple { .. }) } +/// Check the niche information about: `NonZeroU8` +fn check_niche(abi: &ArgAbi) { + assert!(abi.ty.kind().is_struct()); + assert_matches!(abi.mode, PassMode::Direct { .. }); + let layout = abi.layout.shape(); + assert!(layout.is_sized()); + assert_eq!(layout.size.bytes(), 1); + + let ValueAbi::Scalar(scalar) = layout.abi else { unreachable!() }; + assert!(scalar.has_niche(&MachineInfo::target()), "Opps: {:?}", scalar); + + let Scalar::Initialized { value, valid_range } = scalar else { unreachable!() }; + assert_matches!(value, Primitive::Int { length: IntegerLength::I8, signed: false }); + assert_eq!(valid_range.start, 1); + assert_eq!(valid_range.end, u8::MAX.into()); + assert!(!valid_range.contains(0)); + assert!(!valid_range.wraps_around()); +} + fn get_item<'a>( items: &'a CrateItems, item: (ItemKind, &str), @@ -126,11 +150,16 @@ fn generate_input(path: &str) -> std::io::Result<()> { #![feature(c_variadic)] #![allow(unused_variables)] - pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result {{ - // We only care about the signature. - todo!() - }} + use std::num::NonZeroU8; + pub fn fn_abi( + ignore: [u8; 0], + primitive: char, + niche: NonZeroU8, + ) -> Result {{ + // We only care about the signature. + todo!() + }} pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{ 0 From 056716293375ec9ed2e431655d2860afb67f6780 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Fri, 1 Mar 2024 11:16:35 -0800 Subject: [PATCH 18/18] Add support to new float types --- .../rustc_smir/src/rustc_smir/convert/abi.rs | 11 +++++--- compiler/stable_mir/src/abi.rs | 28 ++++++++++++++++--- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 071c02e0381..6fb1560ac6c 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -6,8 +6,9 @@ use crate::rustc_smir::{Stable, Tables}; use rustc_middle::ty; use rustc_target::abi::call::Conv; use stable_mir::abi::{ - AddressSpace, ArgAbi, CallConvention, FieldsShape, FnAbi, IntegerLength, Layout, LayoutShape, - PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape, WrappingRange, + AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout, + LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape, + WrappingRange, }; use stable_mir::opaque; use stable_mir::target::MachineSize as Size; @@ -255,8 +256,10 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Primitive { rustc_abi::Primitive::Int(length, signed) => { Primitive::Int { length: length.stable(tables), signed: *signed } } - rustc_abi::Primitive::F32 => Primitive::F32, - rustc_abi::Primitive::F64 => Primitive::F64, + rustc_abi::Primitive::F16 => Primitive::Float { length: FloatLength::F16 }, + rustc_abi::Primitive::F32 => Primitive::Float { length: FloatLength::F32 }, + rustc_abi::Primitive::F64 => Primitive::Float { length: FloatLength::F64 }, + rustc_abi::Primitive::F128 => Primitive::Float { length: FloatLength::F128 }, rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables)), } } diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index 1c5e3275673..7fda9ceb79a 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -293,8 +293,9 @@ pub enum Primitive { length: IntegerLength, signed: bool, }, - F32, - F64, + Float { + length: FloatLength, + }, Pointer(AddressSpace), } @@ -302,8 +303,7 @@ impl Primitive { pub fn size(self, target: &MachineInfo) -> Size { match self { Primitive::Int { length, .. } => Size::from_bits(length.bits()), - Primitive::F32 => Size::from_bits(32), - Primitive::F64 => Size::from_bits(64), + Primitive::Float { length } => Size::from_bits(length.bits()), Primitive::Pointer(_) => target.pointer_width, } } @@ -319,6 +319,15 @@ pub enum IntegerLength { I128, } +/// Enum representing the existing float lengths. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum FloatLength { + F16, + F32, + F64, + F128, +} + impl IntegerLength { pub fn bits(self) -> usize { match self { @@ -331,6 +340,17 @@ impl IntegerLength { } } +impl FloatLength { + pub fn bits(self) -> usize { + match self { + FloatLength::F16 => 16, + FloatLength::F32 => 32, + FloatLength::F64 => 64, + FloatLength::F128 => 128, + } + } +} + /// An identifier that specifies the address space that some operation /// should operate on. Special address spaces have an effect on code generation, /// depending on the target and the address spaces it implements.