From 5a9807742b1cf626ef730df1f9ca53097aa14b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 28 Feb 2026 20:50:05 +0100 Subject: [PATCH 01/18] Mention `@bors squash` in squashing documentation --- src/doc/rustc-dev-guide/src/git.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index bf31e79a9a154..34e419fa52259 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -383,6 +383,11 @@ Both the upside and downside of this is that it simplifies the history. On the one hand, you lose track of the steps in which changes were made, but the history becomes easier to work with. +The easiest way to squash your commits in a PR on the `rust-lang/rust` repository is to use the `@bors squash` command in a comment on the PR. By default, [bors] combines all commit messages of the PR into the squashed commit message. To customize the commit message, use `@bors squash msg=`. + + +If you want to squash commits using local git operations, read on below. + If there are no conflicts and you are just squashing to clean up the history, use `git rebase --interactive --keep-base main`. This keeps the fork point of your PR the same, making it easier to review the diff of what happened @@ -410,11 +415,6 @@ because they only represent "fixups" and not real changes. For example, `git rebase --interactive HEAD~2` will allow you to edit the two commits only. -For pull requests in `rust-lang/rust`, you can ask [bors] to squash by commenting -`@bors squash` on the PR. -By default, [bors] combines all commit messages in the PR. -To customize the commit message, use `@bors squash [msg|message=]`. - [bors]: https://github.com/rust-lang/bors ### `git range-diff` From 0b9fb671d8cef497beff74766ce1d14acedd6968 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 2 Mar 2026 04:40:37 +0000 Subject: [PATCH 02/18] Prepare for merging from rust-lang/rust This updates the rust-version file to e7d90c695a39426baf5ae705de2f9570a72229de. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index b6e1b2bc55df4..4dedd81b00666 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -c78a29473a68f07012904af11c92ecffa68fcc75 +e7d90c695a39426baf5ae705de2f9570a72229de From 1f94e979fb9b09f4df5483ce549fb96574be1e6e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 22 Oct 2025 14:28:05 +1100 Subject: [PATCH 03/18] Fix some comments about dataflow analysis. Mostly in the examples in `initialized.rs`. In particular, the `EverInitializedPlaces` example currently doesn't cover how it's initialization sites that are tracked, rather than local variables (that's the `b_0`/`b_1` distinction in the example.) --- compiler/rustc_middle/src/mir/basic_blocks.rs | 2 +- .../src/impls/initialized.rs | 54 ++++++++++--------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index aae815c0be046..bd8c022ef42a6 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -65,7 +65,7 @@ impl<'tcx> BasicBlocks<'tcx> { /// Returns basic blocks in a reverse postorder. /// - /// See [`traversal::reverse_postorder`]'s docs to learn what is preorder traversal. + /// See [`traversal::reverse_postorder`]'s docs to learn what is postorder traversal. /// /// [`traversal::reverse_postorder`]: crate::mir::traversal::reverse_postorder #[inline] diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 6a0881ec2bcb8..f83ea0c8be61d 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -108,21 +108,21 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> { /// ```rust /// struct S; /// #[rustfmt::skip] -/// fn foo(pred: bool) { // maybe-init: -/// // {} -/// let a = S; let mut b = S; let c; let d; // {a, b} +/// fn foo(p: bool) { // maybe-init: +/// // {p} +/// let a = S; let mut b = S; let c; let d; // {p, a, b} /// -/// if pred { -/// drop(a); // { b} -/// b = S; // { b} +/// if p { +/// drop(a); // {p, b} +/// b = S; // {p, b} /// /// } else { -/// drop(b); // {a} -/// d = S; // {a, d} +/// drop(b); // {p, a} +/// d = S; // {p, a, d} /// -/// } // {a, b, d} +/// } // {p, a, b, d} /// -/// c = S; // {a, b, c, d} +/// c = S; // {p, a, b, c, d} /// } /// ``` /// @@ -198,11 +198,11 @@ impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { /// ```rust /// struct S; /// #[rustfmt::skip] -/// fn foo(pred: bool) { // maybe-uninit: +/// fn foo(p: bool) { // maybe-uninit: /// // {a, b, c, d} /// let a = S; let mut b = S; let c; let d; // { c, d} /// -/// if pred { +/// if p { /// drop(a); // {a, c, d} /// b = S; // {a, c, d} /// @@ -278,34 +278,36 @@ impl<'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } } -/// `EverInitializedPlaces` tracks all places that might have ever been -/// initialized upon reaching a particular point in the control flow -/// for a function, without an intervening `StorageDead`. +/// `EverInitializedPlaces` tracks all initializations that may have occurred +/// upon reaching a particular point in the control flow for a function, +/// without an intervening `StorageDead`. /// /// This dataflow is used to determine if an immutable local variable may /// be assigned to. /// /// For example, in code like the following, we have corresponding -/// dataflow information shown in the right-hand comments. +/// dataflow information shown in the right-hand comments. Underscored indices +/// are used to distinguish between multiple initializations of the same local +/// variable, e.g. `b_0` and `b_1`. /// /// ```rust /// struct S; /// #[rustfmt::skip] -/// fn foo(pred: bool) { // ever-init: -/// // { } -/// let a = S; let mut b = S; let c; let d; // {a, b } +/// fn foo(p: bool) { // ever-init: +/// // {p, } +/// let a = S; let mut b = S; let c; let d; // {p, a, b_0, } /// -/// if pred { -/// drop(a); // {a, b, } -/// b = S; // {a, b, } +/// if p { +/// drop(a); // {p, a, b_0, } +/// b = S; // {p, a, b_0, b_1, } /// /// } else { -/// drop(b); // {a, b, } -/// d = S; // {a, b, d } +/// drop(b); // {p, a, b_0, b_1, } +/// d = S; // {p, a, b_0, b_1, d} /// -/// } // {a, b, d } +/// } // {p, a, b_0, b_1, d} /// -/// c = S; // {a, b, c, d } +/// c = S; // {p, a, b_0, b_1, c, d} /// } /// ``` pub struct EverInitializedPlaces<'a, 'tcx> { From aabb3d8fff4dd5a2e413cd981b426096900f1799 Mon Sep 17 00:00:00 2001 From: Redddy Date: Sun, 8 Mar 2026 10:56:57 +0900 Subject: [PATCH 04/18] Update query documentation to reflect QueryKey changes --- src/doc/rustc-dev-guide/src/query.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 5ab2ab428e811..1621d79db247a 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -90,7 +90,7 @@ dependencies of the local crate) Note that what determines the crate that a query is targeting is not the *kind* of query, but the *key*. For example, when you invoke `tcx.type_of(def_id)`, that could be a local query or an external query, depending on what crate the `def_id` -is referring to (see the [`self::keys::Key`][Key] trait for more information on how that works). +is referring to (see the [`self::keys::QueryKey`][QueryKey] trait for more information on how that works). Providers always have the same signature: @@ -308,7 +308,7 @@ Let's go over these elements one by one: Also used as the name of a struct (`ty::queries::type_of`) that will be generated to represent this query. - **Query key type:** the type of the argument to this query. - This type must implement the [`ty::query::keys::Key`][Key] trait, which + This type must implement the [`ty::query::keys::QueryKey`][QueryKey] trait, which defines (for example) how to map it to a crate, and so forth. - **Result type of query:** the type produced by this query. This type should (a) not use `RefCell` or other interior mutability and (b) be @@ -317,7 +317,7 @@ Let's go over these elements one by one: - **Query modifiers:** various flags and options that customize how the query is processed (mostly with respect to [incremental compilation][incrcomp]). -[Key]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/keys/trait.Key.html +[QueryKey]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/keys/trait.QueryKey.html [incrcomp]: queries/incremental-compilation-in-detail.html#query-modifiers So, to add a query: From bf4004a24a352182d784db642a8e43b8c1e05396 Mon Sep 17 00:00:00 2001 From: Redddy Date: Sun, 8 Mar 2026 10:37:47 +0900 Subject: [PATCH 05/18] Update conventions for TODO and FIXME comments --- src/doc/rustc-dev-guide/src/conventions.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index 0e08ef9042d1e..0440fb0c5e736 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -139,6 +139,8 @@ if foo { } ``` +If you want to leave a note in the codebase, use `// FIXME` instead. + ## Using crates from crates.io From c15947596f521dcf3f3d90515fee2dd2e8435587 Mon Sep 17 00:00:00 2001 From: Redddy Date: Mon, 9 Mar 2026 10:11:42 +0900 Subject: [PATCH 06/18] Fix typo in feature gate check --- src/doc/rustc-dev-guide/src/feature-gate-check.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/feature-gate-check.md b/src/doc/rustc-dev-guide/src/feature-gate-check.md index 59e50837c52e2..038a14ac070e1 100644 --- a/src/doc/rustc-dev-guide/src/feature-gate-check.md +++ b/src/doc/rustc-dev-guide/src/feature-gate-check.md @@ -8,7 +8,7 @@ nightly-only `#![feature(...)]` opt-in. This chapter documents the implementation of feature gating: where gates are defined, how they are enabled, and how usage is verified. - + ## Feature Definitions From 91c3763234b547a20fa868330030f905da894a02 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 9 Mar 2026 04:46:28 +0000 Subject: [PATCH 07/18] Prepare for merging from rust-lang/rust This updates the rust-version file to eda4fc7733ee89e484d7120cafbd80dcb2fce66e. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 4dedd81b00666..db9492636f6ac 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -e7d90c695a39426baf5ae705de2f9570a72229de +eda4fc7733ee89e484d7120cafbd80dcb2fce66e From 752f75dd977b48f67d264248ad126eb816319cbe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2026 21:09:34 +0100 Subject: [PATCH 08/18] document that older LLVM versions come with increased risk --- src/doc/rustc-dev-guide/src/backend/updating-llvm.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md index 3d0e130b6aaa6..fb340342502a0 100644 --- a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md +++ b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md @@ -6,7 +6,10 @@ Rust supports building against multiple LLVM versions: * Tip-of-tree for the current LLVM development branch is usually supported within a few days. PRs for such fixes are tagged with `llvm-main`. * The latest released major version is always supported. -* The one or two preceding major versions are usually supported. +* The one or two preceding major versions are usually supported in the sense that they are expected + to build successfully and pass most tests. However, fixes for miscompilations often do not get + backported to past LLVM versions, so using rustc with older versions of LLVM comes with an + increased risk of soundness bugs. We strongly recommend using the latest version of LLVM. By default, Rust uses its own fork in the [rust-lang/llvm-project repository]. This fork is based on a `release/$N.x` branch of the upstream project, where From a5f88c783eb7090d3c154a58a0d260a99fef8791 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 10 Mar 2026 00:48:27 -0400 Subject: [PATCH 09/18] add autodiff download instructions --- .../src/autodiff/installation.md | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index e05fdc1160f2f..6b66a9dcb2d5f 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -1,6 +1,50 @@ # Installation -In the near future, `std::autodiff` should become available in nightly builds for users. As a contributor however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you successfully build this project on a tier2/tier3 target. +In the near future, `std::autodiff` should become available for users via rustup. As a rustc/enzyme/autodiff contributor however, you will still need to build rustc from source. +For the meantime, you can download up-to-date builds to enable `std::autodiff` on your latest nightly toolchain, if you are using either of: +**Linux**, with `x86_64-unknown-linux-gnu` or `aarch64-unknown-linux-gnu` +**Windows**, with `x86_64-llvm-mingw` or `aarch64-llvm-mingw` + +You can also download slightly outdated builds for **Apple** (aarch64-apple), which should generally work for now. + +If you need any other platform, you can build rustc including autodiff from source. Please open an issue if you want to help enabling automatic builds for your prefered target. + +## Installation guide + +If you want to use `std::autodiff` and don't plan to contribute PR's to the project, then we recommend to just use your existing nightly installation and download the missing component. In the future, rustup will be able to do it for you. +For now, you'll have to manually download and copy it. + +1) On our github repository, find the last merged PR: [`Repo`] +2) Scroll down to the lower end of the PR, where you'll find a rust-bors message saying `Test successful` with a `CI` link. +3) Click on the `CI` link, and grep for your target. E.g. `dist-x86_64-linux` or `dist-aarch64-llvm-mingw` and click `Load summary`. +4) Under the `CI artifacts` section, find the `enzyme-nightly` artifact, download, and unpack it. +5) Copy the artifact (libEnzyme-22.so for linux, libEnzyme-22.dylib for apple, etc.), which should be in a folder named `enzyme-preview`, to your rust toolchain directory. E.g. for linux: `cp ~/Downloads/enzyme-nightly-x86_64-unknown-linux-gnu/enzyme-preview/lib/rustlib/x86_64-unknown-linux-gnu/lib/libEnzyme-22.so ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib` + +Apple support was temporarily reverted, due to downstream breakages. If you want to download autodiff for apple, please look at the artifacts from this [`run`]. + +## Installation guide for Nix user. + +This setup was recommended by a nix and autodiff user. It uses [`Overlay`]. Please verify for yourself if you are comfortable using that repository. +In that case you might use the following nix configuration to get a rustc that supports `std::autodiff`. +```nix +{ + enzymeLib = pkgs.fetchzip { + url = "https://ci-artifacts.rust-lang.org/rustc-builds/ec818fda361ca216eb186f5cf45131bd9c776bb4/enzyme-nightly-x86_64-unknown-linux-gnu.tar.xz"; + sha256 = "sha256-Rnrop44vzS+qmYNaRoMNNMFyAc3YsMnwdNGYMXpZ5VY="; + }; + + rustToolchain = pkgs.symlinkJoin { + name = "rust-with-enzyme"; + paths = [pkgs.rust-bin.nightly.latest.default]; + nativeBuildInputs = [pkgs.makeWrapper]; + postBuild = '' + libdir=$out/lib/rustlib/x86_64-unknown-linux-gnu/lib + cp ${enzymeLib}/enzyme-preview/lib/rustlib/x86_64-unknown-linux-gnu/lib/libEnzyme-22.so $libdir/ + wrapProgram $out/bin/rustc --add-flags "--sysroot $out" + ''; + }; +} +``` ## Build instructions @@ -87,3 +131,6 @@ ninja ``` This will build Enzyme, and you can find it in `Enzyme/enzyme/build/lib/Enzyme.so`. (Endings might differ based on your OS). +[`Repo`]: https://github.com/rust-lang/rust/ +[`run`]: https://github.com/rust-lang/rust/pull/153026#issuecomment-3950046599 +[`Overlay`]: https://github.com/oxalica/rust-overlay From 4bd7718430143cd3bc071ed33fbfec12eac4a0f9 Mon Sep 17 00:00:00 2001 From: Redddy Date: Tue, 10 Mar 2026 16:01:31 +0900 Subject: [PATCH 10/18] Remove emoji :) --- src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index fc8fe402bfa9e..317b7c2564cbc 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -110,7 +110,6 @@ Also, using `x` rather than `x.py` is recommended as: Notice that this is not absolute. For instance, using Nushell in VSCode on Win10, typing `x` or `./x` still opens `x.py` in an editor rather than invoking the program. -:) In the rest of this guide, we use `x` rather than `x.py` directly. The following command: From db26b5b8e01a621417e08a7609f4216b6768ad43 Mon Sep 17 00:00:00 2001 From: binarycat Date: Wed, 11 Mar 2026 18:07:27 -0500 Subject: [PATCH 11/18] editorconfig: css uses tabs --- .editorconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.editorconfig b/.editorconfig index 6c8560aa1f543..d2d788d2172f7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,6 +12,9 @@ trim_trailing_whitespace = true indent_style = space indent_size = 4 +[*.css] +indent_style = tab + # some tests need trailing whitespace in output snapshots [tests/**] trim_trailing_whitespace = false From 59b37bb56988e63b9f7527dd80ada1a40038b657 Mon Sep 17 00:00:00 2001 From: arferreira Date: Fri, 27 Feb 2026 09:54:43 -0500 Subject: [PATCH 12/18] Fix relative extern URL depth on source pages --- src/librustdoc/html/format.rs | 80 ++++++++++++------- src/librustdoc/html/highlight.rs | 30 ++++--- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/sources.rs | 28 +++---- .../passes/collect_intra_doc_links.rs | 2 +- .../extern/extern-html-root-url-relative.rs | 6 +- 6 files changed, 89 insertions(+), 59 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 7eff0b5402b48..3e7b79eec4287 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -360,11 +360,11 @@ pub(crate) struct HrefInfo { } /// This function is to get the external macro path because they are not in the cache used in -/// `href_with_root_path`. +/// `href_with_jump_to_def_path_depth`. fn generate_macro_def_id_path( def_id: DefId, cx: &Context<'_>, - root_path: Option<&str>, + jump_to_def_path_depth: Option, ) -> Result { let tcx = cx.tcx(); let crate_name = tcx.crate_name(def_id.krate); @@ -400,16 +400,16 @@ fn generate_macro_def_id_path( let url = match cache.extern_locations[&def_id.krate] { ExternalLocation::Remote { ref url, is_absolute } => { - let mut prefix = remote_url_prefix(url, is_absolute, cx.current.len()); + let depth = jump_to_def_path_depth.unwrap_or(cx.current.len()); + let mut prefix = remote_url_prefix(url, is_absolute, depth); prefix.extend(module_path.iter().copied()); prefix.push_fmt(format_args!("{}.{last}.html", item_type.as_str())); prefix.finish() } ExternalLocation::Local => { - // `root_path` always end with a `/`. format!( "{root_path}{path}/{item_type}.{last}.html", - root_path = root_path.unwrap_or(""), + root_path = "../".repeat(jump_to_def_path_depth.unwrap_or(0)), path = fmt::from_fn(|f| module_path.iter().joined("/", f)), item_type = item_type.as_str(), ) @@ -426,7 +426,7 @@ fn generate_item_def_id_path( mut def_id: DefId, original_def_id: DefId, cx: &Context<'_>, - root_path: Option<&str>, + jump_to_def_path_depth: Option, ) -> Result { use rustc_middle::traits::ObligationCause; use rustc_trait_selection::infer::TyCtxtInferExt; @@ -455,8 +455,9 @@ fn generate_item_def_id_path( let shortty = ItemType::from_def_id(def_id, tcx); let module_fqp = to_module_fqp(shortty, &fqp); - let (parts, is_absolute) = url_parts(cx.cache(), def_id, module_fqp, &cx.current)?; - let mut url = make_href(root_path, shortty, parts, &fqp, is_absolute); + let (parts, is_remote) = + url_parts(cx.cache(), def_id, module_fqp, &cx.current, jump_to_def_path_depth)?; + let mut url = make_href(jump_to_def_path_depth, shortty, parts, &fqp, is_remote); if def_id != original_def_id { let kind = ItemType::from_def_id(original_def_id, tcx); @@ -501,17 +502,33 @@ fn remote_url_prefix(url: &str, is_absolute: bool, depth: usize) -> UrlPartsBuil } } +/// Returns `(url_parts, is_remote)` where `is_remote` indicates the URL points to an +/// external location and should not use relative URLs. +/// +/// This function tries to generate minimal, relative URLs. When generating an intra-doc +/// link from one item page to another, it compares the paths of both items and generates +/// exactly the right number of "../"'s to reach the deepest common parent, then fills in +/// the rest of the path. This is done by comparing `module_fqp` with `relative_to`. +/// +/// When generating a link for jump-to-def across crates, that won't work, because sources are +/// stored under "src/[crate]/[path].rs". When linking jump-to-def for another crate, we just +/// write enough "../"'s to reach the doc root, then generate the entire path for `module_fqp`. +/// The right number of "../"'s is stored in `jump_to_def_path_depth`. fn url_parts( cache: &Cache, def_id: DefId, module_fqp: &[Symbol], relative_to: &[Symbol], + jump_to_def_path_depth: Option, ) -> Result<(UrlPartsBuilder, bool), HrefError> { match cache.extern_locations[&def_id.krate] { ExternalLocation::Remote { ref url, is_absolute } => { - let mut builder = remote_url_prefix(url, is_absolute, relative_to.len()); + let depth = jump_to_def_path_depth.unwrap_or(relative_to.len()); + let mut builder = remote_url_prefix(url, is_absolute, depth); builder.extend(module_fqp.iter().copied()); - Ok((builder, is_absolute)) + // Remote URLs (both absolute and relative) already encode the correct path; + // no additional depth prefix should be applied. + Ok((builder, true)) } ExternalLocation::Local => Ok((href_relative_parts(module_fqp, relative_to), false)), ExternalLocation::Unknown => Err(HrefError::DocumentationNotBuilt), @@ -519,16 +536,16 @@ fn url_parts( } fn make_href( - root_path: Option<&str>, + jump_to_def_path_depth: Option, shortty: ItemType, mut url_parts: UrlPartsBuilder, fqp: &[Symbol], - is_absolute: bool, + is_remote: bool, ) -> String { - // FIXME: relative extern URLs may break when prefixed with root_path - if !is_absolute && let Some(root_path) = root_path { - let root = root_path.trim_end_matches('/'); - url_parts.push_front(root); + // Remote URLs already have the correct depth via `remote_url_prefix`; + // only local items need `jump_to_def_path_depth` to bridge from source pages to the doc tree. + if !is_remote && let Some(depth) = jump_to_def_path_depth { + url_parts.push_front(&iter::repeat_n("..", depth).join("/")); } debug!(?url_parts); match shortty { @@ -543,10 +560,10 @@ fn make_href( url_parts.finish() } -pub(crate) fn href_with_root_path( +pub(crate) fn href_with_jump_to_def_path_depth( original_did: DefId, cx: &Context<'_>, - root_path: Option<&str>, + jump_to_def_path_depth: Option, ) -> Result { let tcx = cx.tcx(); let def_kind = tcx.def_kind(original_did); @@ -557,7 +574,13 @@ pub(crate) fn href_with_root_path( } // If this a constructor, we get the parent (either a struct or a variant) and then // generate the link for this item. - DefKind::Ctor(..) => return href_with_root_path(tcx.parent(original_did), cx, root_path), + DefKind::Ctor(..) => { + return href_with_jump_to_def_path_depth( + tcx.parent(original_did), + cx, + jump_to_def_path_depth, + ); + } DefKind::ExternCrate => { // Link to the crate itself, not the `extern crate` item. if let Some(local_did) = original_did.as_local() { @@ -577,7 +600,7 @@ pub(crate) fn href_with_root_path( if !original_did.is_local() { // If we are generating an href for the "jump to def" feature, then the only case we want // to ignore is if the item is `doc(hidden)` because we can't link to it. - if root_path.is_some() { + if jump_to_def_path_depth.is_some() { if tcx.is_doc_hidden(original_did) { return Err(HrefError::Private); } @@ -589,7 +612,7 @@ pub(crate) fn href_with_root_path( } } - let (fqp, shortty, url_parts, is_absolute) = match cache.paths.get(&did) { + let (fqp, shortty, url_parts, is_remote) = match cache.paths.get(&did) { Some(&(ref fqp, shortty)) => ( fqp, shortty, @@ -604,29 +627,30 @@ pub(crate) fn href_with_root_path( // Associated items are handled differently with "jump to def". The anchor is generated // directly here whereas for intra-doc links, we have some extra computation being // performed there. - let def_id_to_get = if root_path.is_some() { original_did } else { did }; + let def_id_to_get = if jump_to_def_path_depth.is_some() { original_did } else { did }; if let Some(&(ref fqp, shortty)) = cache.external_paths.get(&def_id_to_get) { let module_fqp = to_module_fqp(shortty, fqp); - let (parts, is_absolute) = url_parts(cache, did, module_fqp, relative_to)?; - (fqp, shortty, parts, is_absolute) + let (parts, is_remote) = + url_parts(cache, did, module_fqp, relative_to, jump_to_def_path_depth)?; + (fqp, shortty, parts, is_remote) } else if matches!(def_kind, DefKind::Macro(_)) { - return generate_macro_def_id_path(did, cx, root_path); + return generate_macro_def_id_path(did, cx, jump_to_def_path_depth); } else if did.is_local() { return Err(HrefError::Private); } else { - return generate_item_def_id_path(did, original_did, cx, root_path); + return generate_item_def_id_path(did, original_did, cx, jump_to_def_path_depth); } } }; Ok(HrefInfo { - url: make_href(root_path, shortty, url_parts, fqp, is_absolute), + url: make_href(jump_to_def_path_depth, shortty, url_parts, fqp, is_remote), kind: shortty, rust_path: fqp.clone(), }) } pub(crate) fn href(did: DefId, cx: &Context<'_>) -> Result { - href_with_root_path(did, cx, None) + href_with_jump_to_def_path_depth(did, cx, None) } /// Both paths should only be modules. diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 1c162a79c4c44..bb5f3fe7f97df 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -33,7 +33,7 @@ pub(crate) struct HrefContext<'a, 'tcx> { pub(crate) file_span: Span, /// This field is used to know "how far" from the top of the directory we are to link to either /// documentation pages or other source pages. - pub(crate) root_path: &'a str, + pub(crate) jump_to_def_path_depth: usize, /// This field is used to calculate precise local URLs. pub(crate) current_href: String, } @@ -1396,23 +1396,27 @@ fn generate_link_to_def( LinkFromSrc::Local(span) => { context.href_from_span_relative(*span, &href_context.current_href) } - LinkFromSrc::External(def_id) => { - format::href_with_root_path(*def_id, context, Some(href_context.root_path)) - .ok() - .map(|HrefInfo { url, .. }| url) - } - LinkFromSrc::Primitive(prim) => format::href_with_root_path( + LinkFromSrc::External(def_id) => format::href_with_jump_to_def_path_depth( + *def_id, + context, + Some(href_context.jump_to_def_path_depth), + ) + .ok() + .map(|HrefInfo { url, .. }| url), + LinkFromSrc::Primitive(prim) => format::href_with_jump_to_def_path_depth( PrimitiveType::primitive_locations(context.tcx())[prim], context, - Some(href_context.root_path), + Some(href_context.jump_to_def_path_depth), + ) + .ok() + .map(|HrefInfo { url, .. }| url), + LinkFromSrc::Doc(def_id) => format::href_with_jump_to_def_path_depth( + *def_id, + context, + Some(href_context.jump_to_def_path_depth), ) .ok() .map(|HrefInfo { url, .. }| url), - LinkFromSrc::Doc(def_id) => { - format::href_with_root_path(*def_id, context, Some(href_context.root_path)) - .ok() - .map(|HrefInfo { url, .. }| url) - } } }) { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 556d383a0e9fb..f3fdc01c728f7 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2802,7 +2802,7 @@ fn render_call_locations( contents_subset, file_span, cx, - &cx.root_path(), + cx.current.len(), &highlight::DecorationInfo(decoration_info), &sources::SourceContext::Embedded(sources::ScrapedInfo { needs_expansion, diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index dda9b7c55351c..f66abad61dcbe 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -1,4 +1,4 @@ -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::ffi::OsStr; use std::path::{Component, Path, PathBuf}; use std::{fmt, fs}; @@ -193,31 +193,28 @@ impl SourceCollector<'_, '_> { let shared = &self.cx.shared; // Create the intermediate directories let cur = RefCell::new(PathBuf::new()); - let root_path = RefCell::new(PathBuf::new()); + // Tracks the extra directory depth accumulated during path traversal. + // Starts at 0; `PathBuf::pop()` on empty is a no-op, so we mirror that + // with `saturating_sub`. The base depth of 2 (for `src//`) is added after. + let extra_depth = Cell::new(0usize); clean_path( &shared.src_root, &p, |component| { cur.borrow_mut().push(component); - root_path.borrow_mut().push(".."); + extra_depth.set(extra_depth.get() + 1); }, || { cur.borrow_mut().pop(); - root_path.borrow_mut().pop(); + extra_depth.set(extra_depth.get().saturating_sub(1)); }, ); + let jump_to_def_path_depth = 2 + extra_depth.get(); + let src_fname = p.file_name().expect("source has no filename").to_os_string(); let mut fname = src_fname.clone(); - - let root_path = PathBuf::from("../../").join(root_path.into_inner()); - let mut root_path = root_path.to_string_lossy(); - if let Some(c) = root_path.as_bytes().last() - && *c != b'/' - { - root_path += "/"; - } let mut file_path = Path::new(&self.crate_name).join(&*cur.borrow()); file_path.push(&fname); fname.push(".html"); @@ -228,6 +225,7 @@ impl SourceCollector<'_, '_> { let title = format!("{} - source", src_fname.to_string_lossy()); let desc = format!("Source of the Rust file `{}`.", p.to_string_lossy()); + let root_path = "../".repeat(jump_to_def_path_depth); let page = layout::Page { title: &title, short_title: &src_fname.to_string_lossy(), @@ -251,7 +249,7 @@ impl SourceCollector<'_, '_> { contents, file_span, self.cx, - &root_path, + jump_to_def_path_depth, &highlight::DecorationInfo::default(), &source_context, ) @@ -330,7 +328,7 @@ pub(crate) fn print_src( s: &str, file_span: rustc_span::Span, context: &Context<'_>, - root_path: &str, + jump_to_def_path_depth: usize, decoration_info: &highlight::DecorationInfo, source_context: &SourceContext<'_>, ) -> fmt::Result { @@ -359,7 +357,7 @@ pub(crate) fn print_src( Some(highlight::HrefContext { context, file_span: file_span.into(), - root_path, + jump_to_def_path_depth, current_href, }), Some(decoration_info), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3e68ed950ce16..d7932e965d38a 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1204,7 +1204,7 @@ impl LinkCollector<'_, '_> { /// Returns `true` if a link could be generated from the given intra-doc information. /// - /// This is a very light version of `format::href_with_root_path` since we're only interested + /// This is a very light version of `format::href_with_jump_to_def_path_depth` since we're only interested /// about whether we can generate a link to an item or not. /// /// * If `original_did` is local, then we check if the item is reexported or public. diff --git a/tests/rustdoc-html/extern/extern-html-root-url-relative.rs b/tests/rustdoc-html/extern/extern-html-root-url-relative.rs index ba2b50c6bf222..dedc0819ed577 100644 --- a/tests/rustdoc-html/extern/extern-html-root-url-relative.rs +++ b/tests/rustdoc-html/extern/extern-html-root-url-relative.rs @@ -21,7 +21,11 @@ pub mod nested { pub mod intra_doc_link { } -// link-to-definition +// link-to-definition: source pages live under src// so they need +// ../../ to reach the doc root. Previously these links were incorrectly generated +// as ../../../ (one level too deep) which passed the `has` check by substring match. //@ has src/extern_html_root_url_relative/extern-html-root-url-relative.rs.html //@ has - '//a/@href' '../../core/iter/index.html' //@ has - '//a/@href' '../../core/future/index.html' +//@ !has - '//a/@href' '../../../core/iter/index.html' +//@ !has - '//a/@href' '../../../core/future/index.html' From 5e305ab74dee728f17b833d620cc7832685c4804 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 12 Mar 2026 02:05:08 +0100 Subject: [PATCH 13/18] sembr src/backend/updating-llvm.md --- src/doc/rustc-dev-guide/src/backend/updating-llvm.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md index fb340342502a0..56fa49ef2a2e4 100644 --- a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md +++ b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md @@ -7,9 +7,11 @@ Rust supports building against multiple LLVM versions: PRs for such fixes are tagged with `llvm-main`. * The latest released major version is always supported. * The one or two preceding major versions are usually supported in the sense that they are expected - to build successfully and pass most tests. However, fixes for miscompilations often do not get + to build successfully and pass most tests. + However, fixes for miscompilations often do not get backported to past LLVM versions, so using rustc with older versions of LLVM comes with an - increased risk of soundness bugs. We strongly recommend using the latest version of LLVM. + increased risk of soundness bugs. + We strongly recommend using the latest version of LLVM. By default, Rust uses its own fork in the [rust-lang/llvm-project repository]. This fork is based on a `release/$N.x` branch of the upstream project, where From 5de87cd04af71d5f8893f14f88a2baf8358cacef Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 12 Mar 2026 02:08:20 +0100 Subject: [PATCH 14/18] sembr src/diagnostics/translation.md --- src/doc/rustc-dev-guide/src/diagnostics/translation.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics/translation.md b/src/doc/rustc-dev-guide/src/diagnostics/translation.md index cf95727e2a673..a22ede5e9c3ba 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/translation.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/translation.md @@ -31,8 +31,7 @@ There are two ways of writing translatable diagnostics: ("Simple" diagnostics being those that don't require a lot of logic in deciding to emit subdiagnostics and can therefore be represented as diagnostic structs). See [the diagnostic and subdiagnostic structs documentation](./diagnostic-structs.md). -2. Using typed identifiers with `Diag` APIs (in - `Diagnostic` or `Subdiagnostic` implementations). +2. Using typed identifiers with `Diag` APIs (in `Diagnostic` or `Subdiagnostic` implementations). When adding or changing a translatable diagnostic, you don't need to worry about the translations. From 7963b55d9a163103f60b67dd7db453f9a39fc24e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 12 Mar 2026 02:09:02 +0100 Subject: [PATCH 15/18] sembr src/git.md --- src/doc/rustc-dev-guide/src/git.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index 34e419fa52259..faa2d8f2a3a21 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -383,7 +383,9 @@ Both the upside and downside of this is that it simplifies the history. On the one hand, you lose track of the steps in which changes were made, but the history becomes easier to work with. -The easiest way to squash your commits in a PR on the `rust-lang/rust` repository is to use the `@bors squash` command in a comment on the PR. By default, [bors] combines all commit messages of the PR into the squashed commit message. To customize the commit message, use `@bors squash msg=`. +The easiest way to squash your commits in a PR on the `rust-lang/rust` repository is to use the `@bors squash` command in a comment on the PR. +By default, [bors] combines all commit messages of the PR into the squashed commit message. +To customize the commit message, use `@bors squash msg=`. If you want to squash commits using local git operations, read on below. From 751562faf55a0734d27ebb17281926338b632829 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 12 Mar 2026 02:10:03 +0100 Subject: [PATCH 16/18] sembr src/tracing.md --- src/doc/rustc-dev-guide/src/tracing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tracing.md b/src/doc/rustc-dev-guide/src/tracing.md index 151670d089970..78a0fe4af2ff2 100644 --- a/src/doc/rustc-dev-guide/src/tracing.md +++ b/src/doc/rustc-dev-guide/src/tracing.md @@ -14,8 +14,8 @@ of `tracing-subscriber`](https://docs.rs/tracing-subscriber/0.2.24/tracing_subsc ## Environment variables -This is an overview of the environment variables rustc accepts to customize -its tracing output. The definition of these can mostly be found in `compiler/rustc_log/src/lib.rs`. +This is an overview of the environment variables rustc accepts to customize its tracing output. +The definition of these can mostly be found in `compiler/rustc_log/src/lib.rs`. | Name | Usage | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------- | From cfcbcb715c5120e481b2d1303b590a5eb2417e55 Mon Sep 17 00:00:00 2001 From: Tony Kan Date: Wed, 11 Mar 2026 15:10:45 -0700 Subject: [PATCH 17/18] fix(query): Pass query key to value_from_cycle_error Co-authored-by: Daria Sukhonina Co-authored-by: Nicholas Nethercote --- compiler/rustc_middle/src/query/plumbing.rs | 8 ++++-- compiler/rustc_query_impl/src/execution.rs | 12 +++++---- .../rustc_query_impl/src/from_cycle_error.rs | 25 ++++++++----------- compiler/rustc_query_impl/src/plumbing.rs | 2 +- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 72330eab30d58..33c38adcef058 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -136,8 +136,12 @@ pub struct QueryVTable<'tcx, C: QueryCache> { /// For `no_hash` queries, this function pointer is None. pub hash_value_fn: Option, &C::Value) -> Fingerprint>, - pub value_from_cycle_error: - fn(tcx: TyCtxt<'tcx>, cycle_error: CycleError, guar: ErrorGuaranteed) -> C::Value, + pub value_from_cycle_error: fn( + tcx: TyCtxt<'tcx>, + key: C::Key, + cycle_error: CycleError, + guar: ErrorGuaranteed, + ) -> C::Value, pub format_value: fn(&C::Value) -> String, /// Formats a human-readable description of this query and its key, as diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index a892958d6a810..d8dc004f1cf7a 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -125,17 +125,18 @@ where fn mk_cycle<'tcx, C: QueryCache>( query: &'tcx QueryVTable<'tcx, C>, tcx: TyCtxt<'tcx>, + key: C::Key, cycle_error: CycleError, ) -> C::Value { let error = report_cycle(tcx.sess, &cycle_error); match query.cycle_error_handling { CycleErrorHandling::Error => { let guar = error.emit(); - (query.value_from_cycle_error)(tcx, cycle_error, guar) + (query.value_from_cycle_error)(tcx, key, cycle_error, guar) } CycleErrorHandling::DelayBug => { let guar = error.delay_as_bug(); - (query.value_from_cycle_error)(tcx, cycle_error, guar) + (query.value_from_cycle_error)(tcx, key, cycle_error, guar) } } } @@ -219,6 +220,7 @@ where fn cycle_error<'tcx, C: QueryCache>( query: &'tcx QueryVTable<'tcx, C>, tcx: TyCtxt<'tcx>, + key: C::Key, try_execute: QueryJobId, span: Span, ) -> (C::Value, Option) { @@ -229,7 +231,7 @@ fn cycle_error<'tcx, C: QueryCache>( .expect("failed to collect active queries"); let error = find_cycle_in_stack(try_execute, job_map, ¤t_query_job(), span); - (mk_cycle(query, tcx, error.lift()), None) + (mk_cycle(query, tcx, key, error.lift()), None) } #[inline(always)] @@ -274,7 +276,7 @@ fn wait_for_query<'tcx, C: QueryCache>( (v, Some(index)) } - Err(cycle) => (mk_cycle(query, tcx, cycle.lift()), None), + Err(cycle) => (mk_cycle(query, tcx, key, cycle.lift()), None), } } @@ -337,7 +339,7 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>( // If we are single-threaded we know that we have cycle error, // so we just return the error. - cycle_error(query, tcx, id, span) + cycle_error(query, tcx, key, id, span) } } ActiveKeyStatus::Poisoned => FatalError.raise(), diff --git a/compiler/rustc_query_impl/src/from_cycle_error.rs b/compiler/rustc_query_impl/src/from_cycle_error.rs index 0b7f69765823f..c69d3eb9a0f05 100644 --- a/compiler/rustc_query_impl/src/from_cycle_error.rs +++ b/compiler/rustc_query_impl/src/from_cycle_error.rs @@ -15,34 +15,34 @@ use rustc_middle::query::erase::erase_val; use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::LocalDefId; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{ErrorGuaranteed, Span}; use crate::job::report_cycle; pub(crate) fn specialize_query_vtables<'tcx>(vtables: &mut QueryVTables<'tcx>) { vtables.type_of.value_from_cycle_error = - |tcx, _, guar| erase_val(ty::EarlyBinder::bind(Ty::new_error(tcx, guar))); + |tcx, _, _, guar| erase_val(ty::EarlyBinder::bind(Ty::new_error(tcx, guar))); vtables.type_of_opaque_hir_typeck.value_from_cycle_error = - |tcx, _, guar| erase_val(ty::EarlyBinder::bind(Ty::new_error(tcx, guar))); + |tcx, _, _, guar| erase_val(ty::EarlyBinder::bind(Ty::new_error(tcx, guar))); vtables.erase_and_anonymize_regions_ty.value_from_cycle_error = - |tcx, _, guar| erase_val(Ty::new_error(tcx, guar)); + |tcx, _, _, guar| erase_val(Ty::new_error(tcx, guar)); - vtables.fn_sig.value_from_cycle_error = |tcx, cycle, guar| erase_val(fn_sig(tcx, cycle, guar)); + vtables.fn_sig.value_from_cycle_error = |tcx, key, _, guar| erase_val(fn_sig(tcx, key, guar)); vtables.check_representability.value_from_cycle_error = - |tcx, cycle, guar| check_representability(tcx, cycle, guar); + |tcx, _, cycle, guar| check_representability(tcx, cycle, guar); vtables.check_representability_adt_ty.value_from_cycle_error = - |tcx, cycle, guar| check_representability(tcx, cycle, guar); + |tcx, _, cycle, guar| check_representability(tcx, cycle, guar); vtables.variances_of.value_from_cycle_error = - |tcx, cycle, guar| erase_val(variances_of(tcx, cycle, guar)); + |tcx, _, cycle, guar| erase_val(variances_of(tcx, cycle, guar)); vtables.layout_of.value_from_cycle_error = - |tcx, cycle, guar| erase_val(layout_of(tcx, cycle, guar)); + |tcx, _, cycle, guar| erase_val(layout_of(tcx, cycle, guar)); } pub(crate) fn default<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError, query_name: &str) -> ! { @@ -57,15 +57,12 @@ pub(crate) fn default<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError, query_na fn fn_sig<'tcx>( tcx: TyCtxt<'tcx>, - cycle_error: CycleError, + def_id: DefId, guar: ErrorGuaranteed, ) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> { let err = Ty::new_error(tcx, guar); - let arity = if let Some(info) = cycle_error.cycle.get(0) - && info.frame.dep_kind == DepKind::fn_sig - && let Some(def_id) = info.frame.def_id - && let Some(node) = tcx.hir_get_if_local(def_id) + let arity = if let Some(node) = tcx.hir_get_if_local(def_id) && let Some(sig) = node.fn_sig() { sig.decl.inputs.len() diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index ddce892345907..78d5fd3de1f00 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -487,7 +487,7 @@ macro_rules! define_queries { #[cfg(not($cache_on_disk))] is_loadable_from_disk_fn: |_tcx, _key, _index| false, - value_from_cycle_error: |tcx, cycle, _| { + value_from_cycle_error: |tcx, _, cycle, _| { $crate::from_cycle_error::default(tcx, cycle, stringify!($name)) }, From 3464048bc49281f0f947178081f4d41993d253e1 Mon Sep 17 00:00:00 2001 From: Tony Kan Date: Wed, 11 Mar 2026 15:10:55 -0700 Subject: [PATCH 18/18] test(parallel): Add regression test for #153391 Co-authored-by: Daria Sukhonina --- .../parallel-rustc/fn-sig-cycle-ice-153391.rs | 18 +++++++++++ .../fn-sig-cycle-ice-153391.stderr | 31 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.rs create mode 100644 tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.stderr diff --git a/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.rs b/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.rs new file mode 100644 index 0000000000000..0108ada8c08c3 --- /dev/null +++ b/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.rs @@ -0,0 +1,18 @@ +// Regression test for #153391. +// +//@ edition:2024 +//@ compile-flags: -Z threads=16 +//@ compare-output-by-lines +//@ ignore-test (#142063) + +trait A { + fn g() -> B; + //~^ ERROR expected a type, found a trait +} + +trait B { + fn bar(&self, x: &A); + //~^ ERROR expected a type, found a trait +} + +fn main() {} diff --git a/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.stderr b/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.stderr new file mode 100644 index 0000000000000..4d348cf22f4ef --- /dev/null +++ b/tests/ui/parallel-rustc/fn-sig-cycle-ice-153391.stderr @@ -0,0 +1,31 @@ +error[E0782]: expected a type, found a trait + --> $DIR/fn-sig-cycle-ice-153391.rs:8:15 + | +LL | fn g() -> B; + | ^ + | +help: `B` is dyn-incompatible, use `impl B` to return an opaque type, as long as you return a single underlying type + | +LL | fn g() -> impl B; + | ++++ + +error[E0782]: expected a type, found a trait + --> $DIR/fn-sig-cycle-ice-153391.rs:13:23 + | +LL | fn bar(&self, x: &A); + | ^ + | + = note: `A` is dyn-incompatible, otherwise a trait object could be used +help: use a new generic type parameter, constrained by `A` + | +LL - fn bar(&self, x: &A); +LL + fn bar(&self, x: &T); + | +help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference + | +LL | fn bar(&self, x: &impl A); + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0782`.