From 465e373542b529055cd1302849f79db13a617a98 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 Sep 2025 07:55:43 +0200 Subject: [PATCH 01/18] add regression test --- tests/ui/methods/overflow-if-subtyping.rs | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/ui/methods/overflow-if-subtyping.rs diff --git a/tests/ui/methods/overflow-if-subtyping.rs b/tests/ui/methods/overflow-if-subtyping.rs new file mode 100644 index 0000000000000..a97f29f1f6dfc --- /dev/null +++ b/tests/ui/methods/overflow-if-subtyping.rs @@ -0,0 +1,30 @@ +//@ check-pass + +// Regression test for #128887. +#![allow(unconditional_recursion)] +trait Mappable { + type Output; +} + +trait Bound {} +// Deleting this impl made it compile on beta +impl Bound for T {} + +trait Generic {} + +// Deleting the `: Mappable` already made it error on stable. +struct IndexWithIter, T>(I, M, T); + +impl IndexWithIter +where + >::Output: Bound, + // Flipping these where bounds causes this to succeed, even when removing + // the where-clause on the struct definition. + M: Mappable, + I: Generic, +{ + fn new(x: I) { + IndexWithIter::<_, _, _>::new(x); + } +} +fn main() {} From 4acea466e42758468e6cd1de7c6173eabcd5f1b3 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 24 Sep 2025 13:26:53 +0000 Subject: [PATCH 02/18] simplify setup_constraining_predicates, and note it is potentially cubic --- .../src/constrained_generic_params.rs | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 366b3943a0589..44d7f3a5e8bc2 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -167,15 +167,20 @@ pub(crate) fn setup_constraining_predicates<'tcx>( // which is `O(nt)` where `t` is the depth of type-parameter constraints, // remembering that `t` should be less than 7 in practice. // + // FIXME(hkBst): the big-O bound above would be accurate for the number + // of calls to `parameters_for`, which itself is some O(complexity of type). + // That would make this potentially cubic instead of merely quadratic... + // ...unless we cache those `parameters_for` calls. + // // Basically, I iterate over all projections and swap every // "ready" projection to the start of the list, such that // all of the projections before `i` are topologically sorted // and constrain all the parameters in `input_parameters`. // - // In the example, `input_parameters` starts by containing `U` - which - // is constrained by the trait-ref - and so on the first pass we + // In the first example, `input_parameters` starts by containing `U`, + // which is constrained by the self type `U`. Then, on the first pass we // observe that `::Item = T` is a "ready" projection that - // constrains `T` and swap it to front. As it is the sole projection, + // constrains `T` and swap it to the front. As it is the sole projection, // no more swaps can take place afterwards, with the result being // * ::Item = T // * T: Debug @@ -193,33 +198,28 @@ pub(crate) fn setup_constraining_predicates<'tcx>( for j in i..predicates.len() { // Note that we don't have to care about binders here, // as the impl trait ref never contains any late-bound regions. - if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() { - // Special case: watch out for some kind of sneaky attempt - // to project out an associated type defined by this very - // trait. - let unbound_trait_ref = projection.projection_term.trait_ref(tcx); - if Some(unbound_trait_ref) == impl_trait_ref { - continue; - } - - // A projection depends on its input types and determines its output - // type. For example, if we have - // `<::Baz as Iterator>::Output = ::Output` - // Then the projection only applies if `T` is known, but it still - // does not determine `U`. + if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() && + + // Special case: watch out for some kind of sneaky attempt to + // project out an associated type defined by this very trait. + !impl_trait_ref.is_some_and(|t| t == projection.projection_term.trait_ref(tcx)) && + + // A projection depends on its input types and determines its output + // type. For example, if we have + // `<::Baz as Iterator>::Output = ::Output` + // then the projection only applies if `T` is known, but it still + // does not determine `U`. + { let inputs = parameters_for(tcx, projection.projection_term, true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p)); - if !relies_only_on_inputs { - continue; - } + relies_only_on_inputs + } { input_parameters.extend(parameters_for(tcx, projection.term, false)); - } else { - continue; + + predicates.swap(i, j); + i += 1; + changed = true; } - // fancy control flow to bypass borrow checker - predicates.swap(i, j); - i += 1; - changed = true; } debug!( "setup_constraining_predicates: predicates={:?} \ From 1a16755ea02e36828b1a235c3051a8f8341a741d Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 29 Sep 2025 15:55:38 +0000 Subject: [PATCH 03/18] flatten conditional block --- .../rustc_hir_analysis/src/constrained_generic_params.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 44d7f3a5e8bc2..6bcf06399e06e 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -209,11 +209,8 @@ pub(crate) fn setup_constraining_predicates<'tcx>( // `<::Baz as Iterator>::Output = ::Output` // then the projection only applies if `T` is known, but it still // does not determine `U`. + parameters_for(tcx, projection.projection_term, true).iter().all(|p| input_parameters.contains(p)) { - let inputs = parameters_for(tcx, projection.projection_term, true); - let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p)); - relies_only_on_inputs - } { input_parameters.extend(parameters_for(tcx, projection.term, false)); predicates.swap(i, j); From 505a2084e683662e1521b3ba64e23e9271f8e192 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 29 Sep 2025 22:57:14 +1000 Subject: [PATCH 04/18] Split off a separate name/value parser for debuginfo test commands --- src/tools/compiletest/src/directives.rs | 2 +- src/tools/compiletest/src/runtest/debugger.rs | 27 ++++++++++--------- .../compiletest/src/runtest/debuginfo.rs | 6 ++--- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index e84a22787668d..e864594ade2e8 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -1121,7 +1121,7 @@ impl Config { line.starts_with("no-") && self.parse_name_directive(&line[3..], directive) } - pub fn parse_name_value_directive( + fn parse_name_value_directive( &self, line: &str, directive: &str, diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index ba824124e875d..3d439e98eb7e1 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -4,7 +4,6 @@ use std::io::{BufRead, BufReader}; use camino::{Utf8Path, Utf8PathBuf}; -use crate::common::Config; use crate::runtest::ProcRes; /// Representation of information to invoke a debugger and check its output @@ -20,11 +19,7 @@ pub(super) struct DebuggerCommands { } impl DebuggerCommands { - pub fn parse_from( - file: &Utf8Path, - config: &Config, - debugger_prefix: &str, - ) -> Result { + pub fn parse_from(file: &Utf8Path, debugger_prefix: &str) -> Result { let command_directive = format!("{debugger_prefix}-command"); let check_directive = format!("{debugger_prefix}-check"); @@ -47,14 +42,10 @@ impl DebuggerCommands { continue; }; - if let Some(command) = - config.parse_name_value_directive(&line, &command_directive, file, line_no) - { + if let Some(command) = parse_name_value(&line, &command_directive) { commands.push(command); } - if let Some(pattern) = - config.parse_name_value_directive(&line, &check_directive, file, line_no) - { + if let Some(pattern) = parse_name_value(&line, &check_directive) { check_lines.push((line_no, pattern)); } } @@ -114,6 +105,18 @@ impl DebuggerCommands { } } +/// Split off from the main `parse_name_value_directive`, so that improvements +/// to directive handling aren't held back by debuginfo test commands. +fn parse_name_value(line: &str, name: &str) -> Option { + if let Some(after_name) = line.strip_prefix(name) + && let Some(value) = after_name.strip_prefix(':') + { + Some(value.to_owned()) + } else { + None + } +} + /// Check that the pattern in `check_line` applies to `line`. Returns `true` if they do match. fn check_single_line(line: &str, check_line: &str) -> bool { // Allow check lines to leave parts unspecified (e.g., uninitialized diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 071c0863b7e9f..9175a38ffa5c9 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -59,7 +59,7 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "cdb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb") .unwrap_or_else(|e| self.fatal(&e)); // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands @@ -130,7 +130,7 @@ impl TestCx<'_> { } fn run_debuginfo_gdb_test_no_opt(&self) { - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "gdb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb") .unwrap_or_else(|e| self.fatal(&e)); let mut cmds = dbg_cmds.commands.join("\n"); @@ -397,7 +397,7 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "lldb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb") .unwrap_or_else(|e| self.fatal(&e)); // Write debugger script: From ffaf607cf2743f1206a739e02f7b194a4767f9a8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 30 Sep 2025 12:20:42 +1000 Subject: [PATCH 05/18] Remove `parse_negative_name_directive` This isn't actually used for anything, and its presence complicates the migration to `DirectiveLine`. --- src/tools/compiletest/src/directives.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index e864594ade2e8..01a663b016f7d 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -1117,10 +1117,6 @@ impl Config { && matches!(line.as_bytes().get(directive.len()), None | Some(&b' ') | Some(&b':')) } - fn parse_negative_name_directive(&self, line: &str, directive: &str) -> bool { - line.starts_with("no-") && self.parse_name_directive(&line[3..], directive) - } - fn parse_name_value_directive( &self, line: &str, @@ -1149,18 +1145,8 @@ impl Config { } fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) { - match value { - true => { - if self.parse_negative_name_directive(line, directive) { - *value = false; - } - } - false => { - if self.parse_name_directive(line, directive) { - *value = true; - } - } - } + // If the flag is already true, don't bother looking at the directive. + *value = *value || self.parse_name_directive(line, directive); } fn set_name_value_directive( From e491056ac5722bd404dd6c326c76f457eb08b467 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 29 Sep 2025 22:25:23 +1000 Subject: [PATCH 06/18] Pass around `DirectiveLine` instead of bare strings --- src/tools/compiletest/src/directives.rs | 197 +++++++----------- .../compiletest/src/directives/auxiliary.rs | 35 ++-- src/tools/compiletest/src/directives/cfg.rs | 14 +- src/tools/compiletest/src/directives/needs.rs | 6 +- 4 files changed, 107 insertions(+), 145 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 01a663b016f7d..e6916610190e6 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -63,9 +63,10 @@ impl EarlyProps { &mut poisoned, testfile, rdr, - &mut |DirectiveLine { line_number, raw_directive: ln, .. }| { - parse_and_update_aux(config, ln, testfile, line_number, &mut props.aux); - config.parse_and_update_revisions(testfile, line_number, ln, &mut props.revisions); + // (dummy comment to force args into vertical layout) + &mut |ref ln: DirectiveLine<'_>| { + parse_and_update_aux(config, ln, testfile, &mut props.aux); + config.parse_and_update_revisions(testfile, ln, &mut props.revisions); }, ); @@ -367,8 +368,8 @@ impl TestProps { &mut poisoned, testfile, file, - &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| { - if !directive.applies_to_test_revision(test_revision) { + &mut |ref ln: DirectiveLine<'_>| { + if !ln.applies_to_test_revision(test_revision) { return; } @@ -378,7 +379,6 @@ impl TestProps { ln, ERROR_PATTERN, testfile, - line_number, &mut self.error_patterns, |r| r, ); @@ -386,7 +386,6 @@ impl TestProps { ln, REGEX_ERROR_PATTERN, testfile, - line_number, &mut self.regex_error_patterns, |r| r, ); @@ -395,7 +394,6 @@ impl TestProps { ln, DOC_FLAGS, testfile, - line_number, &mut self.doc_flags, |r| r, ); @@ -414,7 +412,7 @@ impl TestProps { } if let Some(flags) = - config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile, line_number) + config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile) { let flags = split_flags(&flags); for flag in &flags { @@ -425,39 +423,28 @@ impl TestProps { self.compile_flags.extend(flags); } if config - .parse_name_value_directive( - ln, - INCORRECT_COMPILER_FLAGS, - testfile, - line_number, - ) + .parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS, testfile) .is_some() { panic!("`compiler-flags` directive should be spelled `compile-flags`"); } - if let Some(edition) = config.parse_edition(ln, testfile, line_number) { + if let Some(edition) = config.parse_edition(ln, testfile) { // The edition is added at the start, since flags from //@compile-flags must // be passed to rustc last. self.compile_flags.insert(0, format!("--edition={}", edition.trim())); has_edition = true; } - config.parse_and_update_revisions( - testfile, - line_number, - ln, - &mut self.revisions, - ); + config.parse_and_update_revisions(testfile, ln, &mut self.revisions); - if let Some(flags) = - config.parse_name_value_directive(ln, RUN_FLAGS, testfile, line_number) + if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS, testfile) { self.run_flags.extend(split_flags(&flags)); } if self.pp_exact.is_none() { - self.pp_exact = config.parse_pp_exact(ln, testfile, line_number); + self.pp_exact = config.parse_pp_exact(ln, testfile); } config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice); @@ -479,9 +466,7 @@ impl TestProps { ); config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic); - if let Some(m) = - config.parse_name_value_directive(ln, PRETTY_MODE, testfile, line_number) - { + if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE, testfile) { self.pretty_mode = m; } @@ -492,13 +477,12 @@ impl TestProps { ); // Call a helper method to deal with aux-related directives. - parse_and_update_aux(config, ln, testfile, line_number, &mut self.aux); + parse_and_update_aux(config, ln, testfile, &mut self.aux); config.push_name_value_directive( ln, EXEC_ENV, testfile, - line_number, &mut self.exec_env, Config::parse_env, ); @@ -506,7 +490,6 @@ impl TestProps { ln, UNSET_EXEC_ENV, testfile, - line_number, &mut self.unset_exec_env, |r| r.trim().to_owned(), ); @@ -514,7 +497,6 @@ impl TestProps { ln, RUSTC_ENV, testfile, - line_number, &mut self.rustc_env, Config::parse_env, ); @@ -522,7 +504,6 @@ impl TestProps { ln, UNSET_RUSTC_ENV, testfile, - line_number, &mut self.unset_rustc_env, |r| r.trim().to_owned(), ); @@ -530,7 +511,6 @@ impl TestProps { ln, FORBID_OUTPUT, testfile, - line_number, &mut self.forbid_output, |r| r, ); @@ -566,7 +546,7 @@ impl TestProps { } if let Some(code) = config - .parse_name_value_directive(ln, FAILURE_STATUS, testfile, line_number) + .parse_name_value_directive(ln, FAILURE_STATUS, testfile) .and_then(|code| code.trim().parse::().ok()) { self.failure_status = Some(code); @@ -588,7 +568,6 @@ impl TestProps { ln, ASSEMBLY_OUTPUT, testfile, - line_number, &mut self.assembly_output, |r| r.trim().to_string(), ); @@ -602,7 +581,7 @@ impl TestProps { // Unlike the other `name_value_directive`s this needs to be handled manually, // because it sets a `bool` flag. if let Some(known_bug) = - config.parse_name_value_directive(ln, KNOWN_BUG, testfile, line_number) + config.parse_name_value_directive(ln, KNOWN_BUG, testfile) { let known_bug = known_bug.trim(); if known_bug == "unknown" @@ -632,24 +611,20 @@ impl TestProps { ln, TEST_MIR_PASS, testfile, - line_number, &mut self.mir_unit_test, |s| s.trim().to_string(), ); config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base); if let Some(flags) = - config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile, line_number) + config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile) { self.llvm_cov_flags.extend(split_flags(&flags)); } - if let Some(flags) = config.parse_name_value_directive( - ln, - FILECHECK_FLAGS, - testfile, - line_number, - ) { + if let Some(flags) = + config.parse_name_value_directive(ln, FILECHECK_FLAGS, testfile) + { self.filecheck_flags.extend(split_flags(&flags)); } @@ -661,7 +636,6 @@ impl TestProps { ln, directives::CORE_STUBS_COMPILE_FLAGS, testfile, - line_number, ) { let flags = split_flags(&flags); for flag in &flags { @@ -672,12 +646,9 @@ impl TestProps { self.core_stubs_compile_flags.extend(flags); } - if let Some(err_kind) = config.parse_name_value_directive( - ln, - DONT_REQUIRE_ANNOTATIONS, - testfile, - line_number, - ) { + if let Some(err_kind) = + config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS, testfile) + { self.dont_require_annotations .insert(ErrorKind::expect_from_user_str(err_kind.trim())); } @@ -734,7 +705,7 @@ impl TestProps { } } - fn update_fail_mode(&mut self, ln: &str, config: &Config) { + fn update_fail_mode(&mut self, ln: &DirectiveLine<'_>, config: &Config) { let check_ui = |mode: &str| { // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows if config.mode != TestMode::Ui && config.mode != TestMode::Crashes { @@ -769,7 +740,12 @@ impl TestProps { } } - fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) { + fn update_pass_mode( + &mut self, + ln: &DirectiveLine<'_>, + revision: Option<&str>, + config: &Config, + ) { let check_no_run = |s| match (config.mode, s) { (TestMode::Ui, _) => (), (TestMode::Crashes, _) => (), @@ -814,7 +790,7 @@ impl TestProps { self.pass_mode } - pub fn update_add_core_stubs(&mut self, ln: &str, config: &Config) { + fn update_add_core_stubs(&mut self, ln: &DirectiveLine<'_>, config: &Config) { let add_core_stubs = config.parse_name_directive(ln, directives::ADD_CORE_STUBS); if add_core_stubs { if !matches!(config.mode, TestMode::Ui | TestMode::Codegen | TestMode::Assembly) { @@ -905,10 +881,12 @@ pub(crate) struct CheckDirectiveResult<'ln> { trailing_directive: Option<&'ln str>, } -pub(crate) fn check_directive<'a>( - directive_ln: &'a str, +fn check_directive<'a>( + directive_ln: &DirectiveLine<'a>, mode: TestMode, ) -> CheckDirectiveResult<'a> { + let &DirectiveLine { raw_directive: directive_ln, .. } = directive_ln; + let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, "")); let is_known_directive = KNOWN_DIRECTIVE_NAMES.contains(&directive_name) @@ -980,7 +958,7 @@ fn iter_directives( // Perform unknown directive check on Rust files. if testfile.extension() == Some("rs") { let CheckDirectiveResult { is_known_directive, trailing_directive } = - check_directive(directive_line.raw_directive, mode); + check_directive(&directive_line, mode); if !is_known_directive { *poisoned = true; @@ -1014,8 +992,7 @@ impl Config { fn parse_and_update_revisions( &self, testfile: &Utf8Path, - line_number: usize, - line: &str, + line: &DirectiveLine<'_>, existing: &mut Vec, ) { const FORBIDDEN_REVISION_NAMES: [&str; 2] = [ @@ -1028,8 +1005,7 @@ impl Config { const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] = ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"]; - if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile, line_number) - { + if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile) { if self.mode == TestMode::RunMake { panic!("`run-make` mode tests do not support revisions: {}", testfile); } @@ -1074,13 +1050,8 @@ impl Config { (name.to_owned(), value.to_owned()) } - fn parse_pp_exact( - &self, - line: &str, - testfile: &Utf8Path, - line_number: usize, - ) -> Option { - if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile, line_number) { + fn parse_pp_exact(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option { + if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile) { Some(Utf8PathBuf::from(&s)) } else if self.parse_name_directive(line, "pp-exact") { testfile.file_name().map(Utf8PathBuf::from) @@ -1089,7 +1060,9 @@ impl Config { } } - fn parse_custom_normalization(&self, raw_directive: &str) -> Option { + fn parse_custom_normalization(&self, line: &DirectiveLine<'_>) -> Option { + let &DirectiveLine { raw_directive, .. } = line; + // FIXME(Zalathar): Integrate name/value splitting into `DirectiveLine` // instead of doing it here. let (directive_name, raw_value) = raw_directive.split_once(':')?; @@ -1110,7 +1083,9 @@ impl Config { Some(NormalizeRule { kind, regex, replacement }) } - fn parse_name_directive(&self, line: &str, directive: &str) -> bool { + fn parse_name_directive(&self, line: &DirectiveLine<'_>, directive: &str) -> bool { + let &DirectiveLine { raw_directive: line, .. } = line; + // Ensure the directive is a whole word. Do not match "ignore-x86" when // the line says "ignore-x86_64". line.starts_with(directive) @@ -1119,11 +1094,12 @@ impl Config { fn parse_name_value_directive( &self, - line: &str, + line: &DirectiveLine<'_>, directive: &str, testfile: &Utf8Path, - line_number: usize, ) -> Option { + let &DirectiveLine { line_number, raw_directive: line, .. } = line; + let colon = directive.len(); if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') { let value = line[(colon + 1)..].to_owned(); @@ -1140,42 +1116,37 @@ impl Config { } } - fn parse_edition(&self, line: &str, testfile: &Utf8Path, line_number: usize) -> Option { - self.parse_name_value_directive(line, "edition", testfile, line_number) + fn parse_edition(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option { + self.parse_name_value_directive(line, "edition", testfile) } - fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) { + fn set_name_directive(&self, line: &DirectiveLine<'_>, directive: &str, value: &mut bool) { // If the flag is already true, don't bother looking at the directive. *value = *value || self.parse_name_directive(line, directive); } fn set_name_value_directive( &self, - line: &str, + line: &DirectiveLine<'_>, directive: &str, testfile: &Utf8Path, - line_number: usize, value: &mut Option, parse: impl FnOnce(String) -> T, ) { if value.is_none() { - *value = - self.parse_name_value_directive(line, directive, testfile, line_number).map(parse); + *value = self.parse_name_value_directive(line, directive, testfile).map(parse); } } fn push_name_value_directive( &self, - line: &str, + line: &DirectiveLine<'_>, directive: &str, testfile: &Utf8Path, - line_number: usize, values: &mut Vec, parse: impl FnOnce(String) -> T, ) { - if let Some(value) = - self.parse_name_value_directive(line, directive, testfile, line_number).map(parse) - { + if let Some(value) = self.parse_name_value_directive(line, directive, testfile).map(parse) { values.push(value); } } @@ -1468,8 +1439,8 @@ pub(crate) fn make_test_description( &mut local_poisoned, path, src, - &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| { - if !directive.applies_to_test_revision(test_revision) { + &mut |ref ln @ DirectiveLine { line_number, .. }| { + if !ln.applies_to_test_revision(test_revision) { return; } @@ -1493,9 +1464,9 @@ pub(crate) fn make_test_description( decision!(cfg::handle_ignore(config, ln)); decision!(cfg::handle_only(config, ln)); decision!(needs::handle_needs(&cache.needs, config, ln)); - decision!(ignore_llvm(config, path, ln, line_number)); - decision!(ignore_backends(config, path, ln, line_number)); - decision!(needs_backends(config, path, ln, line_number)); + decision!(ignore_llvm(config, path, ln)); + decision!(ignore_backends(config, path, ln)); + decision!(needs_backends(config, path, ln)); decision!(ignore_cdb(config, ln)); decision!(ignore_gdb(config, ln)); decision!(ignore_lldb(config, ln)); @@ -1535,7 +1506,9 @@ pub(crate) fn make_test_description( } } -fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision { +fn ignore_cdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { + let &DirectiveLine { raw_directive: line, .. } = line; + if config.debugger != Some(Debugger::Cdb) { return IgnoreDecision::Continue; } @@ -1558,7 +1531,9 @@ fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision { IgnoreDecision::Continue } -fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision { +fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { + let &DirectiveLine { raw_directive: line, .. } = line; + if config.debugger != Some(Debugger::Gdb) { return IgnoreDecision::Continue; } @@ -1606,7 +1581,9 @@ fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision { IgnoreDecision::Continue } -fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { +fn ignore_lldb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { + let &DirectiveLine { raw_directive: line, .. } = line; + if config.debugger != Some(Debugger::Lldb) { return IgnoreDecision::Continue; } @@ -1628,14 +1605,9 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { IgnoreDecision::Continue } -fn ignore_backends( - config: &Config, - path: &Utf8Path, - line: &str, - line_number: usize, -) -> IgnoreDecision { +fn ignore_backends(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision { if let Some(backends_to_ignore) = - config.parse_name_value_directive(line, "ignore-backends", path, line_number) + config.parse_name_value_directive(line, "ignore-backends", path) { for backend in backends_to_ignore.split_whitespace().map(|backend| { match CodegenBackend::try_from(backend) { @@ -1655,15 +1627,8 @@ fn ignore_backends( IgnoreDecision::Continue } -fn needs_backends( - config: &Config, - path: &Utf8Path, - line: &str, - line_number: usize, -) -> IgnoreDecision { - if let Some(needed_backends) = - config.parse_name_value_directive(line, "needs-backends", path, line_number) - { +fn needs_backends(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision { + if let Some(needed_backends) = config.parse_name_value_directive(line, "needs-backends", path) { if !needed_backends .split_whitespace() .map(|backend| match CodegenBackend::try_from(backend) { @@ -1685,9 +1650,9 @@ fn needs_backends( IgnoreDecision::Continue } -fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) -> IgnoreDecision { +fn ignore_llvm(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision { if let Some(needed_components) = - config.parse_name_value_directive(line, "needs-llvm-components", path, line_number) + config.parse_name_value_directive(line, "needs-llvm-components", path) { let components: HashSet<_> = config.llvm_components.split_whitespace().collect(); if let Some(missing_component) = needed_components @@ -1709,7 +1674,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) // Note that these `min` versions will check for not just major versions. if let Some(version_string) = - config.parse_name_value_directive(line, "min-llvm-version", path, line_number) + config.parse_name_value_directive(line, "min-llvm-version", path) { let min_version = extract_llvm_version(&version_string); // Ignore if actual version is smaller than the minimum required version. @@ -1721,7 +1686,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) }; } } else if let Some(version_string) = - config.parse_name_value_directive(line, "max-llvm-major-version", path, line_number) + config.parse_name_value_directive(line, "max-llvm-major-version", path) { let max_version = extract_llvm_version(&version_string); // Ignore if actual major version is larger than the maximum required major version. @@ -1735,7 +1700,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) }; } } else if let Some(version_string) = - config.parse_name_value_directive(line, "min-system-llvm-version", path, line_number) + config.parse_name_value_directive(line, "min-system-llvm-version", path) { let min_version = extract_llvm_version(&version_string); // Ignore if using system LLVM and actual version @@ -1748,7 +1713,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) }; } } else if let Some(version_range) = - config.parse_name_value_directive(line, "ignore-llvm-version", path, line_number) + config.parse_name_value_directive(line, "ignore-llvm-version", path) { // Syntax is: "ignore-llvm-version: [- ]" let (v_min, v_max) = @@ -1774,7 +1739,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) } } } else if let Some(version_string) = - config.parse_name_value_directive(line, "exact-llvm-major-version", path, line_number) + config.parse_name_value_directive(line, "exact-llvm-major-version", path) { // Syntax is "exact-llvm-major-version: " let version = extract_llvm_version(&version_string); diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs index 7c1ed2e700624..0675a6feac3f0 100644 --- a/src/tools/compiletest/src/directives/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -7,6 +7,7 @@ use camino::Utf8Path; use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO}; use crate::common::Config; +use crate::directives::DirectiveLine; /// Properties parsed from `aux-*` test directives. #[derive(Clone, Debug, Default)] @@ -45,40 +46,28 @@ impl AuxProps { /// and update [`AuxProps`] accordingly. pub(super) fn parse_and_update_aux( config: &Config, - ln: &str, + directive_line: &DirectiveLine<'_>, testfile: &Utf8Path, - line_number: usize, aux: &mut AuxProps, ) { + let &DirectiveLine { raw_directive: ln, .. } = directive_line; + if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) { return; } - config.push_name_value_directive(ln, AUX_BUILD, testfile, line_number, &mut aux.builds, |r| { + let ln = directive_line; + + config.push_name_value_directive(ln, AUX_BUILD, testfile, &mut aux.builds, |r| { r.trim().to_string() }); - config.push_name_value_directive(ln, AUX_BIN, testfile, line_number, &mut aux.bins, |r| { + config + .push_name_value_directive(ln, AUX_BIN, testfile, &mut aux.bins, |r| r.trim().to_string()); + config.push_name_value_directive(ln, AUX_CRATE, testfile, &mut aux.crates, parse_aux_crate); + config.push_name_value_directive(ln, PROC_MACRO, testfile, &mut aux.proc_macros, |r| { r.trim().to_string() }); - config.push_name_value_directive( - ln, - AUX_CRATE, - testfile, - line_number, - &mut aux.crates, - parse_aux_crate, - ); - config.push_name_value_directive( - ln, - PROC_MACRO, - testfile, - line_number, - &mut aux.proc_macros, - |r| r.trim().to_string(), - ); - if let Some(r) = - config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile, line_number) - { + if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile) { aux.codegen_backend = Some(r.trim().to_owned()); } } diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index 802a1d63d1f20..62a4b88a33a6e 100644 --- a/src/tools/compiletest/src/directives/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -1,12 +1,14 @@ use std::collections::HashSet; use crate::common::{CompareMode, Config, Debugger}; -use crate::directives::IgnoreDecision; +use crate::directives::{DirectiveLine, IgnoreDecision}; const EXTRA_ARCHS: &[&str] = &["spirv"]; -pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision { +pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { let parsed = parse_cfg_name_directive(config, line, "ignore"); + let &DirectiveLine { raw_directive: line, .. } = line; + match parsed.outcome { MatchOutcome::NoMatch => IgnoreDecision::Continue, MatchOutcome::Match => IgnoreDecision::Ignore { @@ -21,8 +23,10 @@ pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision { } } -pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision { +pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision { let parsed = parse_cfg_name_directive(config, line, "only"); + let &DirectiveLine { raw_directive: line, .. } = line; + match parsed.outcome { MatchOutcome::Match => IgnoreDecision::Continue, MatchOutcome::NoMatch => IgnoreDecision::Ignore { @@ -43,9 +47,11 @@ pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision { /// or `only-windows`. fn parse_cfg_name_directive<'a>( config: &Config, - line: &'a str, + line: &'a DirectiveLine<'a>, prefix: &str, ) -> ParsedNameDirective<'a> { + let &DirectiveLine { raw_directive: line, .. } = line; + if !line.as_bytes().starts_with(prefix.as_bytes()) { return ParsedNameDirective::not_a_directive(); } diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index 3b7a9478717f4..c8a729d8aab68 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -1,10 +1,10 @@ use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer}; -use crate::directives::{IgnoreDecision, llvm_has_libzstd}; +use crate::directives::{DirectiveLine, IgnoreDecision, llvm_has_libzstd}; pub(super) fn handle_needs( cache: &CachedNeedsConditions, config: &Config, - ln: &str, + ln: &DirectiveLine<'_>, ) -> IgnoreDecision { // Note that we intentionally still put the needs- prefix here to make the file show up when // grepping for a directive name, even though we could technically strip that. @@ -181,6 +181,8 @@ pub(super) fn handle_needs( }, ]; + let &DirectiveLine { raw_directive: ln, .. } = ln; + let (name, rest) = match ln.split_once([':', ' ']) { Some((name, rest)) => (name, Some(rest)), None => (ln, None), From 5139facb365c40e5b0ddedf221cd62347a2a4504 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 30 Sep 2025 12:02:43 +0200 Subject: [PATCH 07/18] add tests --- .../src/solve/assembly/mod.rs | 5 +- .../ui/indexing/ambiguity-after-deref-step.rs | 9 +++ .../ambiguity-after-deref-step.stderr | 17 ++++++ .../forced-ambiguity-typenum-ice.rs | 60 +++++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 tests/ui/indexing/ambiguity-after-deref-step.rs create mode 100644 tests/ui/indexing/ambiguity-after-deref-step.stderr create mode 100644 tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index a2e6ef6f0fe8b..d58c264841c85 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -473,7 +473,10 @@ where // fails to reach a fixpoint but ends up getting an error after // running for some additional step. // - // cc trait-system-refactor-initiative#105 + // FIXME(@lcnr): While I believe an error here to be possible, we + // currently don't have any test which actually triggers it. @lqd + // created a minimization for an ICE in typenum, but that one no + // longer fails here. cc trait-system-refactor-initiative#105. let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc); let certainty = Certainty::Maybe { cause, opaque_types_jank: OpaqueTypesJank::AllGood }; self.probe_trait_candidate(source) diff --git a/tests/ui/indexing/ambiguity-after-deref-step.rs b/tests/ui/indexing/ambiguity-after-deref-step.rs new file mode 100644 index 0000000000000..2dd95eed097ca --- /dev/null +++ b/tests/ui/indexing/ambiguity-after-deref-step.rs @@ -0,0 +1,9 @@ +// Regression test making sure that indexing fails with an ambiguity +// error if one of the deref-steps encounters an inference variable. + +fn main() { + let x = &Default::default(); + //~^ ERROR type annotations needed for `&_` + x[1]; + let _: &Vec<()> = x; +} diff --git a/tests/ui/indexing/ambiguity-after-deref-step.stderr b/tests/ui/indexing/ambiguity-after-deref-step.stderr new file mode 100644 index 0000000000000..c7ddd4731c7cb --- /dev/null +++ b/tests/ui/indexing/ambiguity-after-deref-step.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `&_` + --> $DIR/ambiguity-after-deref-step.rs:5:9 + | +LL | let x = &Default::default(); + | ^ +LL | +LL | x[1]; + | - type must be known at this point + | +help: consider giving `x` an explicit type, where the placeholders `_` are specified + | +LL | let x: &_ = &Default::default(); + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs b/tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs new file mode 100644 index 0000000000000..679d6b1fb165a --- /dev/null +++ b/tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs @@ -0,0 +1,60 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#105. We previously encountered +// an ICE in typenum as `forced_ambiguity` failed. While this test no longer causes +// `forced_ambiguity` to error, we still want to use it as a regression test. + +pub struct UInt { + _msb: U, + _lsb: B, +} +pub struct B1; +pub trait Sub { + type Output; +} +impl Sub for UInt, B1> { + type Output = (); +} +impl Sub for UInt +where + U: Sub, + U::Output: Send, +{ + type Output = (); +} + +pub trait Op { + fn op(&self) { + unimplemented!() + } +} +trait OpIf {} + +impl Op, I> for () +where + N: Sub, + (): OpIf, N::Output>, I>, +{ +} +impl OpIf> for () +where + UInt: Sub, + (): Op as Sub>::Output>, +{ +} +impl OpIf for () where R: Sub {} + +pub trait Compute { + type Output; +} + +pub fn repro() +where + UInt: Compute, + as Compute>::Output: Sub, + (): Op, (), ()>, +{ + ().op(); +} +fn main() {} From 5f54d8bfd8e5921dc5eb5bbe0799907ed4ca1916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 30 Sep 2025 16:08:48 +0200 Subject: [PATCH 08/18] Remove usage of `compiletest-use-stage0-libtest` from CI --- src/bootstrap/defaults/bootstrap.dist.toml | 2 -- src/ci/citool/tests/test-jobs.yml | 2 +- src/ci/docker/host-x86_64/pr-check-1/Dockerfile | 1 - src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml index b111a20f8d868..bb0592ce947ab 100644 --- a/src/bootstrap/defaults/bootstrap.dist.toml +++ b/src/bootstrap/defaults/bootstrap.dist.toml @@ -7,8 +7,6 @@ test-stage = 2 doc-stage = 2 # When compiling from source, you usually want all tools. extended = true -# Use libtest built from the source tree instead of the precompiled one from stage 0. -compiletest-use-stage0-libtest = false # Most users installing from source want to build all parts of the project from source. [llvm] diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index d82b3e7648e17..512c806285746 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -27,7 +27,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. diff --git a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile index 04ac0f33daf05..776bbb12e445b 100644 --- a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile +++ b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile @@ -43,7 +43,6 @@ ENV SCRIPT \ python3 ../x.py check bootstrap && \ /scripts/check-default-config-profiles.sh && \ python3 ../x.py build src/tools/build-manifest && \ - python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python3 ../x.py check --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ /scripts/validate-toolstate.sh && \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 95357d229374c..278e40eb71fac 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -90,5 +90,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ ENV SCRIPT /tmp/checktools.sh ../x.py && \ - python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" From 6edf05b740070429e57ec18e5c027167dbb17ab4 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 30 Sep 2025 00:14:03 +0300 Subject: [PATCH 09/18] Add `#[bench]` for librustdoc's syntax highlighter --- src/bootstrap/src/core/builder/mod.rs | 2 +- src/librustdoc/html/highlight/tests.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 006dea4b98d13..fc06db8f80b9d 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1145,7 +1145,7 @@ impl<'a> Builder<'a> { test::RunMakeCargo, ), Kind::Miri => describe!(test::Crate), - Kind::Bench => describe!(test::Crate, test::CrateLibrustc), + Kind::Bench => describe!(test::Crate, test::CrateLibrustc, test::CrateRustdoc), Kind::Doc => describe!( doc::UnstableBook, doc::UnstableBookGen, diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 2603e887bead5..4d1bee9b3a1b3 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,6 +1,7 @@ use expect_test::expect_file; use rustc_data_structures::fx::FxIndexMap; use rustc_span::create_default_session_globals_then; +use test::Bencher; use super::{DecorationInfo, write_code}; @@ -81,3 +82,16 @@ let a = 4;"; expect_file!["fixtures/decorations.html"].assert_eq(&html); }); } + +#[bench] +fn bench_html_highlighting(b: &mut Bencher) { + let src = include_str!("../../../../compiler/rustc_ast/src/visit.rs"); + + create_default_session_globals_then(|| { + b.iter(|| { + let mut out = String::new(); + write_code(&mut out, src, None, None, None); + out + }); + }); +} From 2d03ab1486c11f2c5f8a19ae040b94edc090b279 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Tue, 30 Sep 2025 17:12:31 +0300 Subject: [PATCH 10/18] Replace `rustc_span::Span` with a stripped down version for librustdoc's highlighter --- src/librustdoc/html/highlight.rs | 3 +- src/librustdoc/html/render/context.rs | 3 +- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/render/span_map.rs | 68 ++++++++++++++++++++------ src/librustdoc/html/sources.rs | 7 ++- 5 files changed, 65 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index fad15573cde0c..1dcb4dcc3ff83 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -12,15 +12,16 @@ use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind}; +use rustc_span::BytePos; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; -use rustc_span::{BytePos, DUMMY_SP, Span}; use super::format; use crate::clean::PrimitiveType; use crate::display::Joined as _; use crate::html::escape::EscapeBodyText; use crate::html::macro_expansion::ExpandedCode; +use crate::html::render::span_map::{DUMMY_SP, Span}; use crate::html::render::{Context, LinkFromSrc}; /// This type is needed in case we want to render links on items to allow to go to their definition. diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 5f92ab2fada9c..4c06d0da47013 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -30,6 +30,7 @@ use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::macro_expansion::ExpandedCode; use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary}; +use crate::html::render::span_map::Span; use crate::html::render::write_shared::write_shared; use crate::html::url_parts_builder::UrlPartsBuilder; use crate::html::{layout, sources, static_files}; @@ -139,7 +140,7 @@ pub(crate) struct SharedContext<'tcx> { /// Correspondence map used to link types used in the source code pages to allow to click on /// links to jump to the type's definition. - pub(crate) span_correspondence_map: FxHashMap, + pub(crate) span_correspondence_map: FxHashMap, pub(crate) expanded_codes: FxHashMap>, /// The [`Cache`] used during rendering. pub(crate) cache: Cache, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 97dcaf57cdfa6..d6371e4dbab3e 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -36,7 +36,7 @@ mod ordered_json; mod print_item; pub(crate) mod sidebar; mod sorted_template; -mod span_map; +pub(crate) mod span_map; mod type_layout; mod write_shared; diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index ef7ce33298d91..bc9417b1bb1de 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -8,11 +8,48 @@ use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, QPath}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::MacroKind; -use rustc_span::{BytePos, ExpnKind, Span}; +use rustc_span::{BytePos, ExpnKind}; use crate::clean::{self, PrimitiveType, rustc_span}; use crate::html::sources; +/// This is a stripped down version of [`rustc_span::Span`] that only contains the start and end byte positions of the span. +/// +/// Profiling showed that the `Span` interner was taking up a lot of the run-time when highlighting, and since we +/// never actually use the context and parent that are stored in a normal `Span`, we can replace its usages with this +/// one, which is much cheaper to construct. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Span { + lo: BytePos, + hi: BytePos, +} + +impl From for Span { + fn from(value: rustc_span::Span) -> Self { + Self { lo: value.lo(), hi: value.hi() } + } +} + +impl Span { + pub(crate) fn lo(self) -> BytePos { + self.lo + } + + pub(crate) fn hi(self) -> BytePos { + self.hi + } + + pub(crate) fn with_lo(self, lo: BytePos) -> Self { + Self { lo, hi: self.hi() } + } + + pub(crate) fn with_hi(self, hi: BytePos) -> Self { + Self { lo: self.lo(), hi } + } +} + +pub(crate) const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0) }; + /// This enum allows us to store two different kinds of information: /// /// In case the `span` definition comes from the same crate, we can simply get the `span` and use @@ -96,7 +133,7 @@ impl SpanMapVisitor<'_> { }) .unwrap_or(path.span) }; - self.matches.insert(span, link); + self.matches.insert(span.into(), link); } Res::Local(_) if let Some(span) = self.tcx.hir_res_span(path.res) => { let path_span = if only_use_last_segment @@ -106,11 +143,12 @@ impl SpanMapVisitor<'_> { } else { path.span }; - self.matches.insert(path_span, LinkFromSrc::Local(clean::Span::new(span))); + self.matches.insert(path_span.into(), LinkFromSrc::Local(clean::Span::new(span))); } Res::PrimTy(p) => { // FIXME: Doesn't handle "path-like" primitives like arrays or tuples. - self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p))); + self.matches + .insert(path.span.into(), LinkFromSrc::Primitive(PrimitiveType::from(p))); } Res::Err => {} _ => {} @@ -127,7 +165,7 @@ impl SpanMapVisitor<'_> { if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE { return; } - self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id())); + self.matches.insert(span.into(), LinkFromSrc::Doc(item.owner_id.to_def_id())); } } @@ -138,7 +176,7 @@ impl SpanMapVisitor<'_> { /// so, we loop until we find the macro definition by using `outer_expn_data` in a loop. /// Finally, we get the information about the macro itself (`span` if "local", `DefId` /// otherwise) and store it inside the span map. - fn handle_macro(&mut self, span: Span) -> bool { + fn handle_macro(&mut self, span: rustc_span::Span) -> bool { if !span.from_expansion() { return false; } @@ -176,7 +214,7 @@ impl SpanMapVisitor<'_> { // The "call_site" includes the whole macro with its "arguments". We only want // the macro name. let new_span = new_span.with_hi(new_span.lo() + BytePos(macro_name.len() as u32)); - self.matches.insert(new_span, link_from_src); + self.matches.insert(new_span.into(), link_from_src); true } @@ -233,7 +271,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { intravisit::walk_path(self, path); } - fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: Span) { + fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: rustc_span::Span) { match *qpath { QPath::TypeRelative(qself, path) => { if matches!(path.res, Res::Err) { @@ -249,7 +287,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { self.handle_path(&path, false); } } else { - self.infer_id(path.hir_id, Some(id), path.ident.span); + self.infer_id(path.hir_id, Some(id), path.ident.span.into()); } rustc_ast::visit::try_visit!(self.visit_ty_unambig(qself)); @@ -267,7 +305,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { } } - fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) { + fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: rustc_span::Span, id: HirId) { // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another // file, we want to link to it. Otherwise no need to create a link. if !span.overlaps(m.spans.inner_span) { @@ -275,8 +313,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { // name only and not all the "mod foo;". if let Node::Item(item) = self.tcx.hir_node(id) { let (ident, _) = item.expect_mod(); - self.matches - .insert(ident.span, LinkFromSrc::Local(clean::Span::new(m.spans.inner_span))); + self.matches.insert( + ident.span.into(), + LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)), + ); } } else { // If it's a "mod foo {}", we want to look to its documentation page. @@ -288,9 +328,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { match expr.kind { ExprKind::MethodCall(segment, ..) => { - self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span) + self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span.into()) } - ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span), + ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span.into()), _ => { if self.handle_macro(expr.span) { // We don't want to go deeper into the macro. diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 9c5518a780e44..c79f63fbc2032 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -348,7 +348,12 @@ pub(crate) fn print_src( highlight::write_code( fmt, s, - Some(highlight::HrefContext { context, file_span, root_path, current_href }), + Some(highlight::HrefContext { + context, + file_span: file_span.into(), + root_path, + current_href, + }), Some(decoration_info), Some(line_info), ); From bdebd479acb692319ace3f88bf874ea365503199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 30 Sep 2025 14:01:05 +0200 Subject: [PATCH 11/18] remove outdated context (inner) infctx --- compiler/rustc_infer/src/infer/mod.rs | 17 ----------------- compiler/rustc_trait_selection/src/regions.rs | 2 ++ 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c9fc124d3bf8d..f3ebfde06ab6b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -131,23 +131,6 @@ pub struct InferCtxtInner<'tcx> { /// `$0: 'static`. This will get checked later by regionck. (We /// can't generally check these things right away because we have /// to wait until types are resolved.) - /// - /// These are stored in a map keyed to the id of the innermost - /// enclosing fn body / static initializer expression. This is - /// because the location where the obligation was incurred can be - /// relevant with respect to which sublifetime assumptions are in - /// place. The reason that we store under the fn-id, and not - /// something more fine-grained, is so that it is easier for - /// regionck to be sure that it has found *all* the region - /// obligations (otherwise, it's easy to fail to walk to a - /// particular node-id). - /// - /// Before running `resolve_regions_and_report_errors`, the creator - /// of the inference context is expected to invoke - /// [`InferCtxt::process_registered_region_obligations`] - /// for each body-id in this map, which will process the - /// obligations within. This is expected to be done 'late enough' - /// that all type inference variables have been bound and so forth. region_obligations: Vec>, /// The outlives bounds that we assume must hold about placeholders that diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 2b33b8ac9f86c..debc4fda15a56 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -77,6 +77,8 @@ impl<'tcx> InferCtxt<'tcx> { /// /// Prefer this method over `resolve_regions_with_normalize`, unless you are /// doing something specific for normalization. + /// + /// This function assumes that all infer variables are already constrained. fn resolve_regions( &self, body_id: LocalDefId, From ddbaca521edf274b1462fced5b50ee6983fb8d01 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 30 Sep 2025 17:56:12 -0400 Subject: [PATCH 12/18] fix void and empty struct ret --- compiler/rustc_codegen_llvm/src/builder/autodiff.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index c3485f563916f..4a749642265df 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -378,5 +378,12 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None); - builder.store_to_place(call, dest.val); + let fn_ret_ty = builder.cx.val_ty(call); + if fn_ret_ty != builder.cx.type_void() && fn_ret_ty != builder.cx.type_struct(&[], false) { + // If we return void or an empty struct, then our caller (due to how we generated it) + // does not expect a return value. As such, we have no pointer (or place) into which + // we could store our value, and would store into an undef, which would cause UB. + // As such, we just ignore the return value in those cases. + builder.store_to_place(call, dest.val); + } } From 28ffbab35382164167a5f101bb0181d7f77bffc2 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 30 Sep 2025 17:56:26 -0400 Subject: [PATCH 13/18] add empty struct ret testcase --- tests/codegen-llvm/autodiff/void_ret.rs | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/codegen-llvm/autodiff/void_ret.rs diff --git a/tests/codegen-llvm/autodiff/void_ret.rs b/tests/codegen-llvm/autodiff/void_ret.rs new file mode 100644 index 0000000000000..98c6b98eef4e3 --- /dev/null +++ b/tests/codegen-llvm/autodiff/void_ret.rs @@ -0,0 +1,41 @@ +//@ compile-flags: -Zautodiff=Enable,NoTT,NoPostopt -C no-prepopulate-passes -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme + +#![feature(autodiff)] +use std::autodiff::*; + +// Usually we would store the return value of the differentiated function. +// However, if the return type is void or an empty struct, +// we don't need to store anything. Verify this, since it caused a bug. + +// CHECK:; void_ret::main +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define internal +// CHECK-NOT: store {} undef, ptr undef +// CHECK: ret void + +#[autodiff_reverse(bar, Duplicated, Duplicated)] +pub fn foo(r: &[f64; 10], res: &mut f64) { + let mut output = [0.0; 10]; + output[0] = r[0]; + output[1] = r[1] * r[2]; + output[2] = r[4] * r[5]; + output[3] = r[2] * r[6]; + output[4] = r[1] * r[7]; + output[5] = r[2] * r[8]; + output[6] = r[1] * r[9]; + output[7] = r[5] * r[6]; + output[8] = r[5] * r[7]; + output[9] = r[4] * r[8]; + *res = output.iter().sum(); +} +fn main() { + let inputs = Box::new([3.1; 10]); + let mut d_inputs = Box::new([0.0; 10]); + let mut res = Box::new(0.0); + let mut d_res = Box::new(1.0); + + bar(&inputs, &mut d_inputs, &mut res, &mut d_res); + dbg!(&d_inputs); +} From de189fa982ad8830c326fac443ab830728567aff Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Sun, 28 Sep 2025 19:45:12 -0400 Subject: [PATCH 14/18] updating tests to not break from new typetree metadata --- tests/codegen-llvm/autodiff/abi_handling.rs | 4 ++-- tests/codegen-llvm/autodiff/batched.rs | 2 +- tests/codegen-llvm/autodiff/scalar.rs | 2 +- tests/codegen-llvm/autodiff/sret.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/codegen-llvm/autodiff/abi_handling.rs b/tests/codegen-llvm/autodiff/abi_handling.rs index 454ec698b917c..5c8126898a8d7 100644 --- a/tests/codegen-llvm/autodiff/abi_handling.rs +++ b/tests/codegen-llvm/autodiff/abi_handling.rs @@ -1,7 +1,7 @@ //@ revisions: debug release -//@[debug] compile-flags: -Zautodiff=Enable -C opt-level=0 -Clto=fat -//@[release] compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@[debug] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=0 -Clto=fat +//@[release] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat //@ no-prefer-dynamic //@ needs-enzyme diff --git a/tests/codegen-llvm/autodiff/batched.rs b/tests/codegen-llvm/autodiff/batched.rs index 306a6ed9d1f4f..dc82403212fb0 100644 --- a/tests/codegen-llvm/autodiff/batched.rs +++ b/tests/codegen-llvm/autodiff/batched.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat //@ no-prefer-dynamic //@ needs-enzyme // diff --git a/tests/codegen-llvm/autodiff/scalar.rs b/tests/codegen-llvm/autodiff/scalar.rs index 55b989f920da3..53672a89230ab 100644 --- a/tests/codegen-llvm/autodiff/scalar.rs +++ b/tests/codegen-llvm/autodiff/scalar.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat //@ no-prefer-dynamic //@ needs-enzyme #![feature(autodiff)] diff --git a/tests/codegen-llvm/autodiff/sret.rs b/tests/codegen-llvm/autodiff/sret.rs index dbc253ce89434..498cd3fea012d 100644 --- a/tests/codegen-llvm/autodiff/sret.rs +++ b/tests/codegen-llvm/autodiff/sret.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat //@ no-prefer-dynamic //@ needs-enzyme From ec893d1a646bc0a1e09511ca80d71141da3b6997 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 1 Oct 2025 13:31:42 +0800 Subject: [PATCH 15/18] tests: remove `no-remap-src-base` Previously in the `//`-compiletest-directive times, this was implemented as a special `no-*` directive parsing. In the migration from `//` -> `//@`, the `// no-remap-src-base` directive was lost, most likely because it had no effect -- the default is not remapping `src-base`. So remove occurrences of `no-remap-src-base`, as these are not valid directives. --- tests/ui-fulldeps/mod_dir_path_canonicalized.rs | 1 - tests/ui/errors/auxiliary/remapped_dep.rs | 2 +- tests/ui/errors/remap-path-prefix-reverse.local-self.stderr | 2 +- tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr | 2 +- tests/ui/errors/remap-path-prefix-reverse.rs | 1 - tests/ui/errors/remap-path-prefix.rs | 2 +- tests/ui/proc-macro/expand-expr.rs | 2 +- tests/ui/proc-macro/pretty-print-hack-show.rs | 1 - 8 files changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs index df5f29e35fe69..86f2d5f5954a4 100644 --- a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -2,7 +2,6 @@ // Testing that a librustc_ast can parse modules with canonicalized base path //@ ignore-cross-compile //@ ignore-remote -// no-remap-src-base: Reading `file!()` (expectedly) fails when enabled. #![feature(rustc_private)] diff --git a/tests/ui/errors/auxiliary/remapped_dep.rs b/tests/ui/errors/auxiliary/remapped_dep.rs index 36d4699a30600..997118f822c33 100644 --- a/tests/ui/errors/auxiliary/remapped_dep.rs +++ b/tests/ui/errors/auxiliary/remapped_dep.rs @@ -1,4 +1,4 @@ //@ compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux -// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file. +// Manually remap, so the remapped path remains in .stderr file. pub struct SomeStruct {} // This line should be show as part of the error. diff --git a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr index b4f83f6bfc0a6..b2651f3e03a6d 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr +++ b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr @@ -1,5 +1,5 @@ error[E0423]: expected value, found struct `remapped_dep::SomeStruct` - --> $DIR/remap-path-prefix-reverse.rs:16:13 + --> $DIR/remap-path-prefix-reverse.rs:15:13 | LL | let _ = remapped_dep::SomeStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` diff --git a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr index b4f83f6bfc0a6..b2651f3e03a6d 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr +++ b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr @@ -1,5 +1,5 @@ error[E0423]: expected value, found struct `remapped_dep::SomeStruct` - --> $DIR/remap-path-prefix-reverse.rs:16:13 + --> $DIR/remap-path-prefix-reverse.rs:15:13 | LL | let _ = remapped_dep::SomeStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` diff --git a/tests/ui/errors/remap-path-prefix-reverse.rs b/tests/ui/errors/remap-path-prefix-reverse.rs index 28fdabb8f4df1..562e44690f768 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.rs +++ b/tests/ui/errors/remap-path-prefix-reverse.rs @@ -2,7 +2,6 @@ //@ compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux //@ revisions: local-self remapped-self -// [local-self] no-remap-src-base: The hack should work regardless of remapping. //@ [remapped-self] remap-src-base // Verify that the expected source code is shown. diff --git a/tests/ui/errors/remap-path-prefix.rs b/tests/ui/errors/remap-path-prefix.rs index 7e38e16280f51..de18aa8cc204b 100644 --- a/tests/ui/errors/remap-path-prefix.rs +++ b/tests/ui/errors/remap-path-prefix.rs @@ -2,7 +2,7 @@ //@ compile-flags: --remap-path-prefix={{src-base}}=remapped //@ [with-diagnostic-scope]compile-flags: -Zremap-path-scope=diagnostics //@ [without-diagnostic-scope]compile-flags: -Zremap-path-scope=object -// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file. +// Manually remap, so the remapped path remains in .stderr file. // The remapped paths are not normalized by compiletest. //@ normalize-stderr: "\\(errors)" -> "/$1" diff --git a/tests/ui/proc-macro/expand-expr.rs b/tests/ui/proc-macro/expand-expr.rs index 1e058abe3bc1b..c3dddd8e45940 100644 --- a/tests/ui/proc-macro/expand-expr.rs +++ b/tests/ui/proc-macro/expand-expr.rs @@ -1,6 +1,6 @@ //@ proc-macro: expand-expr.rs //@ ignore-backends: gcc -// no-remap-src-base: check_expand_expr_file!() fails when enabled. +// No `remap-src-base`, since `check_expand_expr_file!()` fails when enabled. #![feature(concat_bytes)] extern crate expand_expr; diff --git a/tests/ui/proc-macro/pretty-print-hack-show.rs b/tests/ui/proc-macro/pretty-print-hack-show.rs index 70f0d5f6ea975..08e26c8114276 100644 --- a/tests/ui/proc-macro/pretty-print-hack-show.rs +++ b/tests/ui/proc-macro/pretty-print-hack-show.rs @@ -1,7 +1,6 @@ //@ proc-macro: test-macros.rs //@ compile-flags: -Z span-debug //@ revisions: local remapped -// [local] no-remap-src-base: The hack should work regardless of remapping. //@ [remapped] remap-src-base #![no_std] // Don't load unnecessary hygiene information from std From 3186902bfca12d492ebbac70e2a41b15f0fb2b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 1 Oct 2025 09:05:30 +0200 Subject: [PATCH 16/18] Remove mention of `compiletest-use-stage0-libtest` from the bootstrap example config --- bootstrap.example.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 0a39c6d8f247d..f623a3db0029d 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -476,9 +476,6 @@ # when the stage 0 compiler is actually built from in-tree sources. #build.compiletest-allow-stage0 = false -# Whether to use the precompiled stage0 libtest with compiletest. -#build.compiletest-use-stage0-libtest = true - # Default value for the `--extra-checks` flag of tidy. # # See `./x test tidy --help` for details. From b1c212f8502e8e7fcb66da0e8da98db770cb7c02 Mon Sep 17 00:00:00 2001 From: ivmarkov Date: Wed, 1 Oct 2025 08:12:44 +0000 Subject: [PATCH 17/18] Fix broken STD build for ESP-IDF --- library/std/src/sys/net/hostname/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/net/hostname/mod.rs b/library/std/src/sys/net/hostname/mod.rs index a4b5b76059d30..8ffe4894d7181 100644 --- a/library/std/src/sys/net/hostname/mod.rs +++ b/library/std/src/sys/net/hostname/mod.rs @@ -1,5 +1,5 @@ cfg_select! { - target_family = "unix" => { + all(target_family = "unix", not(target_os = "espidf")) => { mod unix; pub use unix::hostname; } From e6429c74548aa2a5e20b78dca51c5f74ad59dea8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 1 Oct 2025 21:05:28 +1000 Subject: [PATCH 18/18] Don't create a top-level `true` directory when running UI tests --- .../cmse-nonsecure-call/undeclared-lifetime.rs | 5 +++-- .../cmse-nonsecure-call/undeclared-lifetime.stderr | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs index 5fa5b74c0c0b9..0a0dca804ef35 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs @@ -1,5 +1,6 @@ //@ add-core-stubs -//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Cincremental=true +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ incremental (required to trigger the bug) //@ needs-llvm-components: arm #![feature(abi_cmse_nonsecure_call, no_core)] #![no_core] @@ -8,7 +9,7 @@ extern crate minicore; use minicore::*; // A regression test for https://github.com/rust-lang/rust/issues/131639. -// NOTE: -Cincremental=true was required for triggering the bug. +// NOTE: `-Cincremental` was required for triggering the bug. fn foo() { id::(PhantomData); diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr index 4aca17e73544d..7300bdb72cdda 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/undeclared-lifetime.rs:14:43 + --> $DIR/undeclared-lifetime.rs:15:43 | LL | id::(PhantomData); | ^^ undeclared lifetime