From 186ea6e1e6cbd0edf35ae6aca4abf441856f168f Mon Sep 17 00:00:00 2001 From: Jakub Beránek Date: Thu, 7 Aug 2025 10:41:43 +0200 Subject: Only run the pull workflow once per week --- src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml index 04d6469aeaa..5ff3118960d 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml @@ -3,8 +3,8 @@ name: rustc-pull on: workflow_dispatch: schedule: - # Run at 04:00 UTC every Monday and Thursday - - cron: '0 4 * * 1,4' + # Run at 04:00 UTC every Monday + - cron: '0 4 * * 1' jobs: pull: -- cgit 1.4.1-3-g733a5 From 9ade653e956e25c7a41d156d22b0de2cdd9ecb71 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Fri, 8 Aug 2025 15:58:53 -0700 Subject: Remove mentions of Discord. The official Discord server is no longer active (cannot be posted to). --- src/doc/rustc-dev-guide/src/about-this-guide.md | 1 - src/doc/rustc-dev-guide/src/diagnostics/error-codes.md | 2 +- src/doc/rustc-dev-guide/src/getting-started.md | 17 +++++++---------- 3 files changed, 8 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index 057e4a4ccee..f3957724967 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -74,7 +74,6 @@ You might also find the following sites useful: of the team procedures, active working groups, and the team calendar. - [std-dev-guide] -- a similar guide for developing the standard library. - [The t-compiler zulip][z] -- `#contribute` and `#wg-rustup` on [Discord](https://discord.gg/rust-lang). - The [Rust Internals forum][rif], a place to ask questions and discuss Rust's internals - The [Rust reference][rr], even though it doesn't specifically talk about diff --git a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md index 1b6b87e4c8d..1693432b90d 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md @@ -20,7 +20,7 @@ explanations should help users understand why their code cannot be accepted by the compiler. Rust prides itself on helpful error messages and long-form explanations are no exception. However, before error explanations are overhauled[^new-explanations] it is a bit open as to how exactly they should be -written, as always: ask your reviewer or ask around on the Rust Discord or Zulip. +written, as always: ask your reviewer or ask around on the Rust Zulip. [^new-explanations]: See the draft RFC [here][new-explanations-rfc]. diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index 04d2e37732f..a4272a401d1 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -11,7 +11,6 @@ quick guide for the most useful things. For more information, [see this chapter on how to build and run the compiler](./building/how-to-build-and-run.md). [internals]: https://internals.rust-lang.org -[rust-discord]: http://discord.gg/rust-lang [rust-zulip]: https://rust-lang.zulipchat.com [coc]: https://www.rust-lang.org/policies/code-of-conduct [walkthrough]: ./walkthrough.md @@ -20,8 +19,7 @@ chapter on how to build and run the compiler](./building/how-to-build-and-run.md ## Asking Questions If you have questions, please make a post on the [Rust Zulip server][rust-zulip] or -[internals.rust-lang.org][internals]. If you are contributing to Rustup, be aware they are not on -Zulip - you can ask questions in `#wg-rustup` [on Discord][rust-discord]. +[internals.rust-lang.org][internals]. See the [list of teams and working groups][governance] and [the Community page][community] on the official website for more resources. @@ -30,10 +28,12 @@ official website for more resources. As a reminder, all contributors are expected to follow our [Code of Conduct][coc]. -The compiler team (or `t-compiler`) usually hangs out in Zulip [in this -"stream"][z]; it will be easiest to get questions answered there. +The compiler team (or `t-compiler`) usually hangs out in Zulip in +[the #t-compiler channel][z-t-compiler]; +questions about how the compiler works can go in [#t-compiler/help][z-help]. -[z]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler +[z-t-compiler]: https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler +[z-help]: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp **Please ask questions!** A lot of people report feeling that they are "wasting expert time", but nobody on `t-compiler` feels this way. Contributors are @@ -162,15 +162,12 @@ incredibly helpful: - [Triaging issues][triage]: categorizing, replicating, and minimizing issues is very helpful to the Rust maintainers. - [Working groups][wg]: there are a bunch of working groups on a wide variety of rust-related things. -- Answer questions in the _Get Help!_ channels on the [Rust Discord - server][rust-discord], on [users.rust-lang.org][users], or on - [StackOverflow][so]. +- Answer questions on [users.rust-lang.org][users], or on [Stack Overflow][so]. - Participate in the [RFC process](https://github.com/rust-lang/rfcs). - Find a [requested community library][community-library], build it, and publish it to [Crates.io](http://crates.io). Easier said than done, but very, very valuable! -[rust-discord]: https://discord.gg/rust-lang [users]: https://users.rust-lang.org/ [so]: http://stackoverflow.com/questions/tagged/rust [community-library]: https://github.com/rust-lang/rfcs/labels/A-community-library -- cgit 1.4.1-3-g733a5 From c12f83e3acf3873876f0efdc4897d6012988a879 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 11 Aug 2025 10:41:00 +0800 Subject: add a tip for english writing --- src/doc/rustc-dev-guide/src/getting-started.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index a4272a401d1..87e26d37968 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -36,13 +36,15 @@ questions about how the compiler works can go in [#t-compiler/help][z-help]. [z-help]: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp **Please ask questions!** A lot of people report feeling that they are "wasting -expert time", but nobody on `t-compiler` feels this way. Contributors are +expert's time", but nobody on `t-compiler` feels this way. Contributors are important to us. Also, if you feel comfortable, prefer public topics, as this means others can see the questions and answers, and perhaps even integrate them back into this guide :) +**Tip**: If you're not a native English speaker and feel unsure about writing, try using a translator to help. But avoid using LLM tools that generate long, complex words. In daily teamwork, **simple and clear words** are best for easy understanding. Even small typos or grammar mistakes can make you seem more human, and people connect better with humans. + ### Experts Not all `t-compiler` members are experts on all parts of `rustc`; it's a -- cgit 1.4.1-3-g733a5 From 97564bd0707fb6928cea73ed7c61ffda87d1fb3a Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 11 Aug 2025 09:15:33 +0200 Subject: place link on the more suitable text Also, remove redundant word --- src/doc/rustc-dev-guide/src/git.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index 447c6fd4546..687830a7237 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -338,7 +338,7 @@ your fork with `git push --force-with-lease`. ### Keeping things up to date -The above section on [Rebasing](#rebasing) is a specific +The [above section](#rebasing) is a specific guide on rebasing work and dealing with merge conflicts. Here is some general advice about how to keep your local repo up-to-date with upstream changes: -- cgit 1.4.1-3-g733a5 From 538299a6f5fb34239bd4992786a19e5bd728737c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 11 Aug 2025 09:20:01 +0200 Subject: fix grammar --- src/doc/rustc-dev-guide/src/git.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index 687830a7237..8f0511a4548 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -344,7 +344,7 @@ Here is some general advice about how to keep your local repo up-to-date with upstream changes: Using `git pull upstream master` while on your local master branch regularly -will keep it up-to-date. You will also want to rebase your feature branches +will keep it up-to-date. You will also want to keep your feature branches up-to-date as well. After pulling, you can checkout the feature branches and rebase them: -- cgit 1.4.1-3-g733a5 From e17989edc7dfcf923626964cb8d59a570f32c8bf Mon Sep 17 00:00:00 2001 From: ywxt Date: Fri, 15 Aug 2025 14:16:32 +0800 Subject: Add the directive `compare-output-by-lines` --- src/doc/rustc-dev-guide/src/tests/directives.md | 1 + src/doc/rustc-dev-guide/src/tests/ui.md | 1 + src/tools/compiletest/src/directives.rs | 9 +++++++++ .../compiletest/src/directives/directive_names.rs | 1 + src/tools/compiletest/src/runtest.rs | 6 +++++- .../parallel-rustc/cache-after-waiting-issue-111528.rs | 14 ++++++++------ .../cache-after-waiting-issue-111528.stderr | 2 +- tests/ui/parallel-rustc/cycle_crash-issue-135870.rs | 8 ++++++++ .../ui/parallel-rustc/cycle_crash-issue-135870.stderr | 18 ++++++++++++++++++ tests/ui/parallel-rustc/cycle_crash.rs | 5 ----- tests/ui/parallel-rustc/cycle_crash.stderr | 18 ------------------ .../export-symbols-deadlock-issue-118205-2.rs | 4 ++++ .../export-symbols-deadlock-issue-118205.rs | 3 +++ tests/ui/parallel-rustc/hello_world.rs | 3 +++ .../parallel-rustc/read-stolen-value-issue-111520.rs | 11 +++++++---- 15 files changed, 69 insertions(+), 35 deletions(-) create mode 100644 tests/ui/parallel-rustc/cycle_crash-issue-135870.rs create mode 100644 tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr delete mode 100644 tests/ui/parallel-rustc/cycle_crash.rs delete mode 100644 tests/ui/parallel-rustc/cycle_crash.stderr (limited to 'src') diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index f4ba9a044e6..fbbeb7e97d3 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -111,6 +111,7 @@ for more details. | `forbid-output` | A pattern which must not appear in stderr/`cfail` output | `ui`, `incremental` | Regex pattern | | `run-flags` | Flags passed to the test executable | `ui` | Arbitrary flags | | `known-bug` | No error annotation needed due to known bug | `ui`, `crashes`, `incremental` | Issue number `#123456` | +| `compare-output-by-lines` | Compare the output by lines, rather than as a single string | All | N/A | [^check_stdout]: presently this has a weird quirk where the test binary's stdout and stderr gets concatenated and then diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 25dd5814cf6..d3a2c406402 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -95,6 +95,7 @@ will check for output files: [Normalization](#normalization)). - `dont-check-compiler-stderr` — Ignores stderr from the compiler. - `dont-check-compiler-stdout` — Ignores stdout from the compiler. +- `compare-output-by-lines` — Some tests have non-deterministic orders of output, so we need to compare by lines. UI tests run with `-Zdeduplicate-diagnostics=no` flag which disables rustc's built-in diagnostic deduplication mechanism. This means you may see some diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 13e694b7f03..027ee063a49 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -205,6 +205,8 @@ pub struct TestProps { pub dont_require_annotations: HashSet, /// Whether pretty printers should be disabled in gdb. pub disable_gdb_pretty_printers: bool, + /// Compare the output by lines, rather than as a single string. + pub compare_output_by_lines: bool, } mod directives { @@ -254,6 +256,7 @@ mod directives { // This isn't a real directive, just one that is probably mistyped often pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags"; pub const DISABLE_GDB_PRETTY_PRINTERS: &'static str = "disable-gdb-pretty-printers"; + pub const COMPARE_OUTPUT_BY_LINES: &'static str = "compare-output-by-lines"; } impl TestProps { @@ -310,6 +313,7 @@ impl TestProps { add_core_stubs: false, dont_require_annotations: Default::default(), disable_gdb_pretty_printers: false, + compare_output_by_lines: false, } } @@ -664,6 +668,11 @@ impl TestProps { DISABLE_GDB_PRETTY_PRINTERS, &mut self.disable_gdb_pretty_printers, ); + config.set_name_directive( + ln, + COMPARE_OUTPUT_BY_LINES, + &mut self.compare_output_by_lines, + ); }, ); diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index f7955429d83..9bdd8e9fa11 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -17,6 +17,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "check-run-results", "check-stdout", "check-test-line-numbers-match", + "compare-output-by-lines", "compile-flags", "disable-gdb-pretty-printers", "doc-flags", diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index be4663fffbe..af35302b55b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2749,7 +2749,11 @@ impl<'test> TestCx<'test> { // Wrapper tools set by `runner` might provide extra output on failure, // for example a WebAssembly runtime might print the stack trace of an // `unreachable` instruction by default. - let compare_output_by_lines = self.config.runner.is_some(); + // + // Also, some tests like `ui/parallel-rustc` have non-deterministic + // orders of output, so we need to compare by lines. + let compare_output_by_lines = + self.props.compare_output_by_lines || self.config.runner.is_some(); let tmp; let (expected, actual): (&str, &str) = if compare_output_by_lines { diff --git a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs index 73d173022f6..a357040a4e4 100644 --- a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs +++ b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs @@ -1,16 +1,18 @@ +// Test for #111528, the ice issue cause waiting on a query that panicked +// //@ compile-flags: -Z threads=16 //@ build-fail +//@ compare-output-by-lines -#![crate_type="rlib"] +#![crate_type = "rlib"] #![allow(warnings)] -#[export_name="fail"] -pub fn a() { -} +#[export_name = "fail"] +pub fn a() {} -#[export_name="fail"] +#[export_name = "fail"] pub fn b() { -//~^ ERROR symbol `fail` is already defined + //~^ ERROR symbol `fail` is already defined } fn main() {} diff --git a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr index 7963165e31b..80f63733fb3 100644 --- a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr +++ b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.stderr @@ -1,5 +1,5 @@ error: symbol `fail` is already defined - --> $DIR/cache-after-waiting-issue-111528.rs:12:1 + --> $DIR/cache-after-waiting-issue-111528.rs:14:1 | LL | pub fn b() { | ^^^^^^^^^^ diff --git a/tests/ui/parallel-rustc/cycle_crash-issue-135870.rs b/tests/ui/parallel-rustc/cycle_crash-issue-135870.rs new file mode 100644 index 00000000000..4407e3aca80 --- /dev/null +++ b/tests/ui/parallel-rustc/cycle_crash-issue-135870.rs @@ -0,0 +1,8 @@ +// Test for #135870, which causes a deadlock bug +// +//@ compile-flags: -Z threads=2 +//@ compare-output-by-lines + +const FOO: usize = FOO; //~ ERROR cycle detected when simplifying constant for the type system `FOO` + +fn main() {} diff --git a/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr b/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr new file mode 100644 index 00000000000..6e588d1f894 --- /dev/null +++ b/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr @@ -0,0 +1,18 @@ +error[E0391]: cycle detected when simplifying constant for the type system `FOO` + --> $DIR/cycle_crash-issue-135870.rs:6:1 + | +LL | const FOO: usize = FOO; + | ^^^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `FOO`... + --> $DIR/cycle_crash-issue-135870.rs:6:20 + | +LL | const FOO: usize = FOO; + | ^^^ + = note: ...which again requires simplifying constant for the type system `FOO`, completing the cycle + = note: cycle used when running analysis passes on this crate + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/parallel-rustc/cycle_crash.rs b/tests/ui/parallel-rustc/cycle_crash.rs deleted file mode 100644 index 94ae11aef39..00000000000 --- a/tests/ui/parallel-rustc/cycle_crash.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ compile-flags: -Z threads=2 - -const FOO: usize = FOO; //~ERROR cycle detected when simplifying constant for the type system `FOO` - -fn main() {} diff --git a/tests/ui/parallel-rustc/cycle_crash.stderr b/tests/ui/parallel-rustc/cycle_crash.stderr deleted file mode 100644 index 7af3b8ee532..00000000000 --- a/tests/ui/parallel-rustc/cycle_crash.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0391]: cycle detected when simplifying constant for the type system `FOO` - --> $DIR/cycle_crash.rs:3:1 - | -LL | const FOO: usize = FOO; - | ^^^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `FOO`... - --> $DIR/cycle_crash.rs:3:20 - | -LL | const FOO: usize = FOO; - | ^^^ - = note: ...which again requires simplifying constant for the type system `FOO`, completing the cycle - = note: cycle used when running analysis passes on this crate - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs index 024df728736..523b1b2d1f3 100644 --- a/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs +++ b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205-2.rs @@ -1,6 +1,10 @@ +// Test for #118205, which causes a deadlock bug +// //@ compile-flags:-C extra-filename=-1 -Z threads=16 //@ no-prefer-dynamic //@ build-pass +//@ compare-output-by-lines + #![crate_name = "crateresolve1"] #![crate_type = "lib"] diff --git a/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs index 3ccc1ea5f10..65f99c30643 100644 --- a/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs +++ b/tests/ui/parallel-rustc/export-symbols-deadlock-issue-118205.rs @@ -1,5 +1,8 @@ +// Test for #118205, which causes a deadlock bug +// //@ compile-flags: -Z threads=16 //@ build-pass +//@ compare-output-by-lines pub static GLOBAL: isize = 3; diff --git a/tests/ui/parallel-rustc/hello_world.rs b/tests/ui/parallel-rustc/hello_world.rs index 56698fe2489..57891b92da0 100644 --- a/tests/ui/parallel-rustc/hello_world.rs +++ b/tests/ui/parallel-rustc/hello_world.rs @@ -1,5 +1,8 @@ +// Test for the basic function of parallel front end +// //@ compile-flags: -Z threads=8 //@ run-pass +//@ compare-output-by-lines fn main() { println!("Hello world!"); diff --git a/tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs b/tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs index ea8ecb67859..a6b37e62913 100644 --- a/tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs +++ b/tests/ui/parallel-rustc/read-stolen-value-issue-111520.rs @@ -1,18 +1,21 @@ +// Test for #111520, which causes an ice bug cause of reading stolen value +// //@ compile-flags: -Z threads=16 //@ run-pass +//@ compare-output-by-lines #[repr(transparent)] struct Sched { i: i32, } impl Sched { - extern "C" fn get(self) -> i32 { self.i } + extern "C" fn get(self) -> i32 { + self.i + } } fn main() { let s = Sched { i: 4 }; - let f = || -> i32 { - s.get() - }; + let f = || -> i32 { s.get() }; println!("f: {}", f()); } -- cgit 1.4.1-3-g733a5 From a3510c7199806c153f927f25e2bff2c095aa60df Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 18 Aug 2025 04:22:18 +0000 Subject: Prepare for merging from rust-lang/rust This updates the rust-version file to 425a9c0a0e365c0b8c6cfd00c2ded83a73bed9a0. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 6ec700b9b4d..a399b5cd77e 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -6bcdcc73bd11568fd85f5a38b58e1eda054ad1cd +425a9c0a0e365c0b8c6cfd00c2ded83a73bed9a0 -- cgit 1.4.1-3-g733a5 From ba3099f60b25437b7a871a3dfe7aa71bf867cd90 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 14 Feb 2025 17:34:29 +0100 Subject: Add support for macro expansion in rustdoc source code pages --- src/librustdoc/html/highlight.rs | 222 +++++++++++++++++++++++------ src/librustdoc/html/render/context.rs | 7 +- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/render/span_map.rs | 114 ++++++++++++++- src/librustdoc/html/static/css/rustdoc.css | 57 ++++++-- 5 files changed, 339 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 272180fb990..165b0c587b0 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -5,6 +5,7 @@ //! //! Use the `render_with_highlighting` to highlight some rust code. +use std::borrow::Cow; use std::collections::VecDeque; use std::fmt::{self, Display, Write}; @@ -17,7 +18,7 @@ use rustc_span::{BytePos, DUMMY_SP, Span}; use super::format::{self, write_str}; use crate::clean::PrimitiveType; use crate::html::escape::EscapeBodyText; -use crate::html::render::{Context, LinkFromSrc}; +use crate::html::render::{Context, ExpandedCode, LinkFromSrc}; /// This type is needed in case we want to render links on items to allow to go to their definition. pub(crate) struct HrefContext<'a, 'tcx> { @@ -163,7 +164,7 @@ struct TokenHandler<'a, 'tcx, F: Write> { current_class: Option, /// We need to keep the `Class` for each element because it could contain a `Span` which is /// used to generate links. - pending_elems: Vec<(&'a str, Option)>, + pending_elems: Vec<(Cow<'a, str>, Option)>, href_context: Option>, write_line_number: fn(&mut F, u32, &'static str), } @@ -271,6 +272,62 @@ fn empty_line_number(out: &mut impl Write, _: u32, extra: &'static str) { out.write_str(extra).unwrap(); } +fn get_expansion<'a, W: Write>( + token_handler: &mut TokenHandler<'_, '_, W>, + expanded_codes: Option<&'a Vec>, + line: u32, +) -> Option<&'a ExpandedCode> { + if let Some(expanded_codes) = expanded_codes + && let Some(expanded_code) = expanded_codes.iter().find(|code| code.start_line == line) + { + let (closing, reopening) = if let Some(current_class) = token_handler.current_class + && let class = current_class.as_html() + && !class.is_empty() + { + ("", format!("")) + } else { + ("", String::new()) + }; + let id = format!("expand-{line}"); + token_handler.pending_elems.push(( + Cow::Owned(format!( + "{closing}\ +\ + \ + {reopening}", + )), + Some(Class::Expansion), + )); + Some(expanded_code) + } else { + None + } +} + +fn start_expansion(out: &mut Vec<(Cow<'_, str>, Option)>, expanded_code: &ExpandedCode) { + out.push(( + Cow::Owned(format!( + "{}", + expanded_code.code, + )), + Some(Class::Expansion), + )); +} + +fn end_expansion(token_handler: &mut TokenHandler<'_, '_, W>, level: usize) { + if level == 0 { + token_handler.pending_elems.push((Cow::Borrowed(""), Some(Class::Expansion))); + return; + } + let mut out = String::new(); + let mut end = String::new(); + for (tag, class) in token_handler.closing_tags.iter().skip(token_handler.closing_tags.len() - level) { + out.push_str(tag); + end.push_str(&format!("", class.as_html())); + } + token_handler.pending_elems.push((Cow::Owned(format!("{out}{end}")), Some(Class::Expansion))); +} + #[derive(Clone, Copy)] pub(super) struct LineInfo { pub(super) start_line: u32, @@ -317,7 +374,7 @@ pub(super) fn write_code( closing_tags: Vec::new(), pending_exit_span: None, current_class: None, - pending_elems: Vec::new(), + pending_elems: Vec::with_capacity(20), href_context, write_line_number: match line_info { Some(line_info) => { @@ -338,12 +395,21 @@ pub(super) fn write_code( (0, u32::MAX) }; + let expanded_codes = token_handler + .href_context + .as_ref() + .and_then(|c| c.context.shared.expanded_codes.get(&c.file_span.lo())); + let mut current_expansion = + get_expansion(&mut token_handler, expanded_codes, line); + token_handler.write_pending_elems(None); + let mut level = 0; + Classifier::new( &src, token_handler.href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP), decoration_info, ) - .highlight(&mut |highlight| { + .highlight(&mut |span, highlight| { match highlight { Highlight::Token { text, class } => { // If we received a `ExitSpan` event and then have a non-compatible `Class`, we @@ -369,10 +435,32 @@ pub(super) fn write_code( if text == "\n" { line += 1; if line < max_lines { - token_handler.pending_elems.push((text, Some(Class::Backline(line)))); + token_handler + .pending_elems + .push((Cow::Borrowed(text), Some(Class::Backline(line)))); + } + if current_expansion.is_none() { + current_expansion = + get_expansion(&mut token_handler, expanded_codes, line); } } else { - token_handler.pending_elems.push((text, class)); + token_handler.pending_elems.push((Cow::Borrowed(text), class)); + + let mut need_end = false; + if let Some(ref current_expansion) = current_expansion { + if current_expansion.span.lo() == span.hi() { + start_expansion(&mut token_handler.pending_elems, current_expansion); + } else if current_expansion.end_line == line + && span.hi() >= current_expansion.span.hi() + { + need_end = true; + } + } + if need_end { + end_expansion(&mut token_handler, level); + current_expansion = None; + level = 0; + } } } Highlight::EnterSpan { class } => { @@ -392,6 +480,9 @@ pub(super) fn write_code( if should_add { let closing_tag = enter_span(token_handler.out, class, &token_handler.href_context); + if current_expansion.is_some() { + level += 1; + } token_handler.closing_tags.push((closing_tag, class)); } @@ -400,6 +491,9 @@ pub(super) fn write_code( } Highlight::ExitSpan => { token_handler.current_class = None; + if current_expansion.is_some() { + level -= 1; + } token_handler.pending_exit_span = Some( token_handler .closing_tags @@ -440,6 +534,8 @@ enum Class { QuestionMark, Decoration(&'static str), Backline(u32), + /// Macro expansion. + Expansion, } impl Class { @@ -489,6 +585,7 @@ impl Class { Class::QuestionMark => "question-mark", Class::Decoration(kind) => kind, Class::Backline(_) => "", + Class::Expansion => "", } } @@ -513,7 +610,8 @@ impl Class { | Self::Lifetime | Self::QuestionMark | Self::Decoration(_) - | Self::Backline(_) => None, + | Self::Backline(_) + | Self::Expansion => None, } } } @@ -628,6 +726,13 @@ impl Decorations { } } +/// Convenient wrapper to create a [`Span`] from a position in the file. +fn new_span(lo: u32, text: &str, file_span: Span) -> Span { + let hi = lo + text.len() as u32; + let file_lo = file_span.lo(); + file_span.with_lo(file_lo + BytePos(lo)).with_hi(file_lo + BytePos(hi)) +} + /// Processes program tokens, classifying strings of text by highlighting /// category (`Class`). struct Classifier<'src> { @@ -660,13 +765,6 @@ impl<'src> Classifier<'src> { } } - /// Convenient wrapper to create a [`Span`] from a position in the file. - fn new_span(&self, lo: u32, text: &str) -> Span { - let hi = lo + text.len() as u32; - let file_lo = self.file_span.lo(); - self.file_span.with_lo(file_lo + BytePos(lo)).with_hi(file_lo + BytePos(hi)) - } - /// Concatenate colons and idents as one when possible. fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> { let start = self.byte_pos as usize; @@ -735,18 +833,18 @@ impl<'src> Classifier<'src> { /// The general structure for this method is to iterate over each token, /// possibly giving it an HTML span with a class specifying what flavor of /// token is used. - fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'src>)) { + fn highlight(mut self, sink: &mut dyn FnMut(Span, Highlight<'src>)) { loop { if let Some(decs) = self.decorations.as_mut() { let byte_pos = self.byte_pos; let n_starts = decs.starts.iter().filter(|(i, _)| byte_pos >= *i).count(); for (_, kind) in decs.starts.drain(0..n_starts) { - sink(Highlight::EnterSpan { class: Class::Decoration(kind) }); + sink(DUMMY_SP, Highlight::EnterSpan { class: Class::Decoration(kind) }); } let n_ends = decs.ends.iter().filter(|i| byte_pos >= **i).count(); for _ in decs.ends.drain(0..n_ends) { - sink(Highlight::ExitSpan); + sink(DUMMY_SP, Highlight::ExitSpan); } } @@ -784,14 +882,20 @@ impl<'src> Classifier<'src> { &mut self, token: TokenKind, text: &'src str, - sink: &mut dyn FnMut(Highlight<'src>), + sink: &mut dyn FnMut(Span, Highlight<'src>), before: u32, ) { let lookahead = self.peek(); - let no_highlight = |sink: &mut dyn FnMut(_)| sink(Highlight::Token { text, class: None }); - let whitespace = |sink: &mut dyn FnMut(_)| { + let file_span = self.file_span; + let no_highlight = |sink: &mut dyn FnMut(_, _)| sink(new_span(before, text, file_span), Highlight::Token { text, class: None }); + let whitespace = |sink: &mut dyn FnMut(_, _)| { + let mut start = 0u32; for part in text.split('\n').intersperse("\n").filter(|s| !s.is_empty()) { - sink(Highlight::Token { text: part, class: None }); + sink( + new_span(before + start, part, file_span), + Highlight::Token { text: part, class: None }, + ); + start += part.len() as u32; } }; let class = match token { @@ -807,8 +911,8 @@ impl<'src> Classifier<'src> { // leading identifier. TokenKind::Bang if self.in_macro => { self.in_macro = false; - sink(Highlight::Token { text, class: None }); - sink(Highlight::ExitSpan); + sink(new_span(before, text, file_span), Highlight::Token { text, class: None }); + sink(DUMMY_SP, Highlight::ExitSpan); return; } @@ -819,12 +923,18 @@ impl<'src> Classifier<'src> { Some((TokenKind::Whitespace, _)) => return whitespace(sink), Some((TokenKind::Ident, "mut")) => { self.next(); - sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) }); + sink( + DUMMY_SP, + Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) }, + ); return; } Some((TokenKind::Ident, "const")) => { self.next(); - sink(Highlight::Token { text: "*const", class: Some(Class::RefKeyWord) }); + sink( + DUMMY_SP, + Highlight::Token { text: "*const", class: Some(Class::RefKeyWord) }, + ); return; } _ => Class::RefKeyWord, @@ -832,18 +942,21 @@ impl<'src> Classifier<'src> { TokenKind::And => match self.tokens.peek() { Some((TokenKind::And, _)) => { self.next(); - sink(Highlight::Token { text: "&&", class: None }); + sink(DUMMY_SP, Highlight::Token { text: "&&", class: None }); return; } Some((TokenKind::Eq, _)) => { self.next(); - sink(Highlight::Token { text: "&=", class: None }); + sink(DUMMY_SP, Highlight::Token { text: "&=", class: None }); return; } Some((TokenKind::Whitespace, _)) => return whitespace(sink), Some((TokenKind::Ident, "mut")) => { self.next(); - sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) }); + sink( + DUMMY_SP, + Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) }, + ); return; } _ => Class::RefKeyWord, @@ -853,19 +966,19 @@ impl<'src> Classifier<'src> { TokenKind::Eq => match lookahead { Some(TokenKind::Eq) => { self.next(); - sink(Highlight::Token { text: "==", class: None }); + sink(DUMMY_SP, Highlight::Token { text: "==", class: None }); return; } Some(TokenKind::Gt) => { self.next(); - sink(Highlight::Token { text: "=>", class: None }); + sink(DUMMY_SP, Highlight::Token { text: "=>", class: None }); return; } _ => return no_highlight(sink), }, TokenKind::Minus if lookahead == Some(TokenKind::Gt) => { self.next(); - sink(Highlight::Token { text: "->", class: None }); + sink(DUMMY_SP, Highlight::Token { text: "->", class: None }); return; } @@ -916,16 +1029,22 @@ impl<'src> Classifier<'src> { self.next(); if let Some(TokenKind::OpenBracket) = self.peek() { self.in_attribute = true; - sink(Highlight::EnterSpan { class: Class::Attribute }); + sink( + new_span(before, text, file_span), + Highlight::EnterSpan { class: Class::Attribute }, + ); } - sink(Highlight::Token { text: "#", class: None }); - sink(Highlight::Token { text: "!", class: None }); + sink(DUMMY_SP, Highlight::Token { text: "#", class: None }); + sink(DUMMY_SP, Highlight::Token { text: "!", class: None }); return; } // Case 2: #[outer_attribute] Some(TokenKind::OpenBracket) => { self.in_attribute = true; - sink(Highlight::EnterSpan { class: Class::Attribute }); + sink( + new_span(before, text, file_span), + Highlight::EnterSpan { class: Class::Attribute }, + ); } _ => (), } @@ -934,8 +1053,8 @@ impl<'src> Classifier<'src> { TokenKind::CloseBracket => { if self.in_attribute { self.in_attribute = false; - sink(Highlight::Token { text: "]", class: None }); - sink(Highlight::ExitSpan); + sink(new_span(before, text, file_span), Highlight::Token { text: "]", class: None }); + sink(DUMMY_SP, Highlight::ExitSpan); return; } return no_highlight(sink); @@ -956,15 +1075,16 @@ impl<'src> Classifier<'src> { TokenKind::GuardedStrPrefix => return no_highlight(sink), TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => { self.in_macro = true; - sink(Highlight::EnterSpan { class: Class::Macro(self.new_span(before, text)) }); - sink(Highlight::Token { text, class: None }); + let span = new_span(before, text, file_span); + sink(DUMMY_SP, Highlight::EnterSpan { class: Class::Macro(span) }); + sink(span, Highlight::Token { text, class: None }); return; } TokenKind::Ident => match get_real_ident_class(text, false) { None => match text { - "Option" | "Result" => Class::PreludeTy(self.new_span(before, text)), + "Option" | "Result" => Class::PreludeTy(new_span(before, text, file_span)), "Some" | "None" | "Ok" | "Err" => { - Class::PreludeVal(self.new_span(before, text)) + Class::PreludeVal(new_span(before, text, file_span)) } // "union" is a weak keyword and is only considered as a keyword when declaring // a union type. @@ -973,13 +1093,13 @@ impl<'src> Classifier<'src> { self.in_macro_nonterminal = false; Class::MacroNonTerminal } - "self" | "Self" => Class::Self_(self.new_span(before, text)), - _ => Class::Ident(self.new_span(before, text)), + "self" | "Self" => Class::Self_(new_span(before, text, file_span)), + _ => Class::Ident(new_span(before, text, file_span)), }, Some(c) => c, }, TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => { - Class::Ident(self.new_span(before, text)) + Class::Ident(new_span(before, text, file_span)) } TokenKind::Lifetime { .. } | TokenKind::RawLifetime @@ -988,8 +1108,13 @@ impl<'src> Classifier<'src> { }; // Anything that didn't return above is the simple case where we the // class just spans a single token, so we can use the `string` method. + let mut start = 0u32; for part in text.split('\n').intersperse("\n").filter(|s| !s.is_empty()) { - sink(Highlight::Token { text: part, class: Some(class) }); + sink( + new_span(before + start, part, file_span), + Highlight::Token { text: part, class: Some(class) }, + ); + start += part.len() as u32; } } @@ -1042,9 +1167,9 @@ fn exit_span(out: &mut impl Write, closing_tag: &str) { /// Note that if `context` is not `None` and that the given `klass` contains a `Span`, the function /// will then try to find this `span` in the `span_correspondence_map`. If found, it'll then /// generate a link for this element (which corresponds to where its definition is located). -fn string( +fn string( out: &mut W, - text: T, + text: EscapeBodyText<'_>, klass: Option, href_context: &Option>, open_tag: bool, @@ -1052,6 +1177,9 @@ fn string( ) { if let Some(Class::Backline(line)) = klass { write_line_number_callback(out, line, "\n"); + } else if let Some(Class::Expansion) = klass { + // Nothing to escape here so we get the text to write it directly. + out.write_str(text.0).unwrap(); } else if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag) { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index e4fca09d64f..33dec1c24e6 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -12,7 +12,7 @@ use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::edition::Edition; -use rustc_span::{FileName, Symbol, sym}; +use rustc_span::{BytePos, FileName, Symbol, sym}; use tracing::info; use super::print_item::{full_path, print_item, print_item_path}; @@ -29,6 +29,7 @@ use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary}; +use crate::html::render::ExpandedCode; use crate::html::render::write_shared::write_shared; use crate::html::url_parts_builder::UrlPartsBuilder; use crate::html::{layout, sources, static_files}; @@ -139,6 +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) expanded_codes: FxHashMap>, /// The [`Cache`] used during rendering. pub(crate) cache: Cache, pub(crate) call_locations: AllCallLocations, @@ -548,7 +550,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } } - let (local_sources, matches) = collect_spans_and_sources( + let (local_sources, matches, expanded_codes) = collect_spans_and_sources( tcx, &krate, &src_root, @@ -579,6 +581,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { cache, call_locations, should_merge: options.should_merge, + expanded_codes, }; let dst = output; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8d7f0577506..0986b9ca47b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -63,7 +63,7 @@ use serde::{Serialize, Serializer}; use tracing::{debug, info}; pub(crate) use self::context::*; -pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources}; +pub(crate) use self::span_map::{ExpandedCode, LinkFromSrc, collect_spans_and_sources}; pub(crate) use self::write_shared::*; use crate::clean::{self, ItemId, RenderedLink}; use crate::display::{Joined as _, MaybeDisplay as _}; diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 846d3ad310c..842da838049 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -30,12 +30,26 @@ pub(crate) enum LinkFromSrc { Doc(DefId), } +/// Contains information about macro expansion in the source code pages. +#[derive(Debug)] +pub(crate) struct ExpandedCode { + /// The line where the macro expansion starts. + pub(crate) start_line: u32, + /// The line where the macro expansion ends. + pub(crate) end_line: u32, + /// The source code of the expanded macro. + pub(crate) code: String, + /// The span of macro callsite. + pub(crate) span: Span, +} + /// This function will do at most two things: /// /// 1. Generate a `span` correspondence map which links an item `span` to its definition `span`. /// 2. Collect the source code files. /// -/// It returns the `krate`, the source code files and the `span` correspondence map. +/// It returns the source code files, the `span` correspondence map and the expanded macros +/// correspondence map. /// /// Note about the `span` correspondence map: the keys are actually `(lo, hi)` of `span`s. We don't /// need the `span` context later on, only their position, so instead of keeping a whole `Span`, we @@ -46,17 +60,23 @@ pub(crate) fn collect_spans_and_sources( src_root: &Path, include_sources: bool, generate_link_to_definition: bool, -) -> (FxIndexMap, FxHashMap) { +) -> ( + FxIndexMap, + FxHashMap, + FxHashMap>, +) { if include_sources { let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; + let mut expanded_visitor = ExpandedCodeVisitor { tcx, expanded_codes: Vec::new() }; + tcx.hir_walk_toplevel_module(&mut expanded_visitor); if generate_link_to_definition { tcx.hir_walk_toplevel_module(&mut visitor); } let sources = sources::collect_local_sources(tcx, src_root, krate); - (sources, visitor.matches) + (sources, visitor.matches, expanded_visitor.compute_expanded()) } else { - (Default::default(), Default::default()) + (Default::default(), Default::default(), Default::default()) } } @@ -292,3 +312,89 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { intravisit::walk_item(self, item); } } + +/// Contains temporary information of macro expanded code. +/// +/// As we go through the HIR visitor, if any span overlaps with another, they will +/// both be merged. +struct ExpandedCodeInfo { + /// Callsite of the macro. + span: Span, + /// Expanded macro source code. + code: String, +} + +/// HIR visitor which retrieves expanded macro. +/// +/// Once done, the `expanded_codes` will be transformed into a vec of [`ExpandedCode`] +/// which contains more information needed when running the source code highlighter. +pub struct ExpandedCodeVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + expanded_codes: Vec, +} + +impl<'tcx> ExpandedCodeVisitor<'tcx> { + fn handle_new_span) -> String>(&mut self, new_span: Span, f: F) { + if new_span.is_dummy() || !new_span.from_expansion() { + return; + } + let new_span = new_span.source_callsite(); + if let Some(index) = + self.expanded_codes.iter().position(|info| info.span.overlaps(new_span)) + { + if !self.expanded_codes[index].span.contains(new_span) { + // We replace the item. + let info = &mut self.expanded_codes[index]; + info.span = new_span; + info.code = f(self.tcx); + } + } else { + // We add a new item. + self.expanded_codes.push(ExpandedCodeInfo { + span: new_span, + code: f(self.tcx), + }); + } + } + + fn compute_expanded(mut self) -> FxHashMap> { + self.expanded_codes.sort_unstable_by(|item1, item2| item1.span.cmp(&item2.span)); + let source_map = self.tcx.sess.source_map(); + let mut expanded: FxHashMap> = FxHashMap::default(); + for ExpandedCodeInfo { span, code } in self.expanded_codes { + if let Ok(lines) = source_map.span_to_lines(span) + && !lines.lines.is_empty() + { + let mut out = String::new(); + super::highlight::write_code(&mut out, &code, None, None, None); + let first = lines.lines.first().unwrap(); + let end = lines.lines.last().unwrap(); + expanded.entry(lines.file.start_pos).or_default().push(ExpandedCode { + start_line: first.line_index as u32 + 1, + end_line: end.line_index as u32 + 1, + code: out, + span, + }); + } + } + expanded + } +} + +impl<'tcx> Visitor<'tcx> for ExpandedCodeVisitor<'tcx> { + type NestedFilter = nested_filter::All; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } + + fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { + self.handle_new_span(expr.span, |tcx| rustc_hir_pretty::expr_to_string(&tcx, expr)); + intravisit::walk_expr(self, expr); + } + + fn visit_item(&mut self, item: &'tcx rustc_hir::Item<'tcx>) { + self.handle_new_span(item.span, |tcx| rustc_hir_pretty::item_to_string(&tcx, item)); + intravisit::walk_item(self, item); + } +} diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index dc27d7943d9..9403701d454 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -956,14 +956,55 @@ rustdoc-topbar { .example-wrap.digits-8 { --example-wrap-digits-count: 8ch; } .example-wrap.digits-9 { --example-wrap-digits-count: 9ch; } -.example-wrap [data-nosnippet] { +.example-wrap .expansion { + position: relative; + display: inline; +} +.example-wrap .expansion > input { + display: none; +} +.example-wrap .expansion > label { + position: absolute; + left: -20px; + top: 0; + border: 1px solid var(--border-color); + border-radius: 4px; + cursor: pointer; + color: var(--main-color); + padding: 0 2px; + line-height: 20px; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + +} +.example-wrap .expansion .expanded { + display: none; + color: var(--main-color); +} +.example-wrap .expansion > input:checked ~ .expanded, +.example-wrap .expansion > input:checked ~ * .expanded { + display: inherit; +} +.example-wrap .expansion > input:checked ~ .original, +.example-wrap .expansion > input:checked ~ * .original { + display: none; +} + +.src .example-wrap [data-nosnippet] { width: calc(var(--example-wrap-digits-count) + var(--line-number-padding) * 2); } -.example-wrap pre > code { +.src .example-wrap pre > code { padding-left: calc( var(--example-wrap-digits-count) + var(--line-number-padding) * 2 + var(--line-number-right-margin)); } +.src .example-wrap .expansion [data-nosnippet] { + left: calc(( + var(--example-wrap-digits-count) + var(--line-number-padding) * 2 + + var(--line-number-right-margin)) * -1); +} .example-wrap [data-nosnippet] { color: var(--src-line-numbers-span-color); @@ -978,23 +1019,21 @@ rustdoc-topbar { position: absolute; left: 0; } -.example-wrap .line-highlighted[data-nosnippet] { - background-color: var(--src-line-number-highlighted-background-color); -} .example-wrap pre > code { position: relative; - display: block; -} -:root.word-wrap-source-code .example-wrap pre > code { word-break: break-all; + display: block; white-space: pre-wrap; } -:root.word-wrap-source-code .example-wrap pre > code * { +.example-wrap pre > code * { word-break: break-all; } .example-wrap [data-nosnippet]:target { border-right: none; } +.example-wrap .line-highlighted[data-nosnippet] { + background-color: var(--src-line-number-highlighted-background-color); +} .example-wrap.hide-lines [data-nosnippet] { display: none; } -- cgit 1.4.1-3-g733a5 From f8ce37621ae83f1323a83f833ab2abecdc20a0ba Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 18 Feb 2025 18:07:14 +0100 Subject: Add new unstable `--generate-macro-expansion` rustdoc command line flag --- src/librustdoc/config.rs | 11 +++++++++++ src/librustdoc/html/highlight.rs | 25 ++++++++++++++++--------- src/librustdoc/html/render/context.rs | 2 ++ src/librustdoc/html/render/span_map.rs | 10 +++++----- src/librustdoc/lib.rs | 8 ++++++++ 5 files changed, 42 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index c52c7236883..450ac04b40d 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -305,6 +305,8 @@ pub(crate) struct RenderOptions { pub(crate) parts_out_dir: Option, /// disable minification of CSS/JS pub(crate) disable_minification: bool, + /// If `true`, HTML source pages will generate the possibility to expand macros. + pub(crate) generate_macro_expansion: bool, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -786,6 +788,7 @@ impl Options { let show_type_layout = matches.opt_present("show-type-layout"); let nocapture = matches.opt_present("nocapture"); let generate_link_to_definition = matches.opt_present("generate-link-to-definition"); + let generate_macro_expansion = matches.opt_present("generate-macro-expansion"); let extern_html_root_takes_precedence = matches.opt_present("extern-html-root-takes-precedence"); let html_no_source = matches.opt_present("html-no-source"); @@ -801,6 +804,13 @@ impl Options { .with_note("`--generate-link-to-definition` option will be ignored") .emit(); } + if generate_macro_expansion && (show_coverage || output_format != OutputFormat::Html) { + dcx.struct_warn( + "`--generate-macro-expansion` option can only be used with HTML output format", + ) + .with_note("`--generate-macro-expansion` option will be ignored") + .emit(); + } let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx); let with_examples = matches.opt_strs("with-examples"); @@ -881,6 +891,7 @@ impl Options { unstable_features, emit, generate_link_to_definition, + generate_macro_expansion, call_locations, no_emit_shared: false, html_no_source, diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 165b0c587b0..7e362791af9 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -281,7 +281,7 @@ fn get_expansion<'a, W: Write>( && let Some(expanded_code) = expanded_codes.iter().find(|code| code.start_line == line) { let (closing, reopening) = if let Some(current_class) = token_handler.current_class - && let class = current_class.as_html() + && let class = current_class.as_html() && !class.is_empty() { ("", format!("")) @@ -321,11 +321,15 @@ fn end_expansion(token_handler: &mut TokenHandler<'_, '_, W>, level: u } let mut out = String::new(); let mut end = String::new(); - for (tag, class) in token_handler.closing_tags.iter().skip(token_handler.closing_tags.len() - level) { + for (tag, class) in + token_handler.closing_tags.iter().skip(token_handler.closing_tags.len() - level) + { out.push_str(tag); end.push_str(&format!("", class.as_html())); } - token_handler.pending_elems.push((Cow::Owned(format!("{out}{end}")), Some(Class::Expansion))); + token_handler + .pending_elems + .push((Cow::Owned(format!("{out}{end}")), Some(Class::Expansion))); } #[derive(Clone, Copy)] @@ -399,8 +403,7 @@ pub(super) fn write_code( .href_context .as_ref() .and_then(|c| c.context.shared.expanded_codes.get(&c.file_span.lo())); - let mut current_expansion = - get_expansion(&mut token_handler, expanded_codes, line); + let mut current_expansion = get_expansion(&mut token_handler, expanded_codes, line); token_handler.write_pending_elems(None); let mut level = 0; @@ -440,8 +443,7 @@ pub(super) fn write_code( .push((Cow::Borrowed(text), Some(Class::Backline(line)))); } if current_expansion.is_none() { - current_expansion = - get_expansion(&mut token_handler, expanded_codes, line); + current_expansion = get_expansion(&mut token_handler, expanded_codes, line); } } else { token_handler.pending_elems.push((Cow::Borrowed(text), class)); @@ -887,7 +889,9 @@ impl<'src> Classifier<'src> { ) { let lookahead = self.peek(); let file_span = self.file_span; - let no_highlight = |sink: &mut dyn FnMut(_, _)| sink(new_span(before, text, file_span), Highlight::Token { text, class: None }); + let no_highlight = |sink: &mut dyn FnMut(_, _)| { + sink(new_span(before, text, file_span), Highlight::Token { text, class: None }) + }; let whitespace = |sink: &mut dyn FnMut(_, _)| { let mut start = 0u32; for part in text.split('\n').intersperse("\n").filter(|s| !s.is_empty()) { @@ -1053,7 +1057,10 @@ impl<'src> Classifier<'src> { TokenKind::CloseBracket => { if self.in_attribute { self.in_attribute = false; - sink(new_span(before, text, file_span), Highlight::Token { text: "]", class: None }); + sink( + new_span(before, text, file_span), + Highlight::Token { text: "]", class: None }, + ); sink(DUMMY_SP, Highlight::ExitSpan); return; } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 33dec1c24e6..af9af5ba2b3 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -492,6 +492,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { generate_redirect_map, show_type_layout, generate_link_to_definition, + generate_macro_expansion, call_locations, no_emit_shared, html_no_source, @@ -556,6 +557,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { &src_root, include_sources, generate_link_to_definition, + generate_macro_expansion, ); let (sender, receiver) = channel(); diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 842da838049..10969188dc7 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -60,6 +60,7 @@ pub(crate) fn collect_spans_and_sources( src_root: &Path, include_sources: bool, generate_link_to_definition: bool, + generate_macro_expansion: bool, ) -> ( FxIndexMap, FxHashMap, @@ -69,7 +70,9 @@ pub(crate) fn collect_spans_and_sources( let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; let mut expanded_visitor = ExpandedCodeVisitor { tcx, expanded_codes: Vec::new() }; - tcx.hir_walk_toplevel_module(&mut expanded_visitor); + if generate_macro_expansion { + tcx.hir_walk_toplevel_module(&mut expanded_visitor); + } if generate_link_to_definition { tcx.hir_walk_toplevel_module(&mut visitor); } @@ -350,10 +353,7 @@ impl<'tcx> ExpandedCodeVisitor<'tcx> { } } else { // We add a new item. - self.expanded_codes.push(ExpandedCodeInfo { - span: new_span, - code: f(self.tcx), - }); + self.expanded_codes.push(ExpandedCodeInfo { span: new_span, code: f(self.tcx) }); } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 28dbd8ba7d3..09e7a42e944 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -704,6 +704,14 @@ fn opts() -> Vec { "removed, see issue #44136 for more information", "[rust]", ), + opt( + Unstable, + Flag, + "", + "generate-macro-expansion", + "Add possibility to expand macros in the HTML source code pages", + "", + ), ] } -- cgit 1.4.1-3-g733a5 From 36421286d50f4dd7eaab93219adc054d5c2ced2b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 21 Feb 2025 00:44:32 +0100 Subject: Add documentation for `--generate-macro-expansion` --- src/doc/rustdoc/src/unstable-features.md | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 7bd2970eee7..724e260009e 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -796,3 +796,7 @@ will be split as follows: "you today?", ] ``` + +## `--generate-macro-expansion`: Generate macros expansion toggles in source code + +This flag enables the generation of toggles to expand macros in the HTML source code pages, -- cgit 1.4.1-3-g733a5 From 6c1b481e7bc6cdce1646c53beaa9112d2f7b1d9f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 24 Feb 2025 18:13:50 +0100 Subject: Correctly handle multiple macro expansions on a same line --- src/librustdoc/html/highlight.rs | 57 ++++++++++++++++++++++-------- src/librustdoc/html/static/css/rustdoc.css | 10 +++--- 2 files changed, 49 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 7e362791af9..39fec2cbe69 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -272,14 +272,25 @@ fn empty_line_number(out: &mut impl Write, _: u32, extra: &'static str) { out.write_str(extra).unwrap(); } +fn get_next_expansion<'a>( + expanded_codes: Option<&'a Vec>, + line: u32, + span: Span, +) -> Option<&'a ExpandedCode> { + if let Some(expanded_codes) = expanded_codes { + expanded_codes.iter().find(|code| code.start_line == line && code.span.lo() >= span.lo()) + } else { + None + } +} + fn get_expansion<'a, W: Write>( token_handler: &mut TokenHandler<'_, '_, W>, expanded_codes: Option<&'a Vec>, line: u32, + span: Span, ) -> Option<&'a ExpandedCode> { - if let Some(expanded_codes) = expanded_codes - && let Some(expanded_code) = expanded_codes.iter().find(|code| code.start_line == line) - { + if let Some(expanded_code) = get_next_expansion(expanded_codes, line, span) { let (closing, reopening) = if let Some(current_class) = token_handler.current_class && let class = current_class.as_html() && !class.is_empty() @@ -314,10 +325,21 @@ fn start_expansion(out: &mut Vec<(Cow<'_, str>, Option)>, expanded_code: )); } -fn end_expansion(token_handler: &mut TokenHandler<'_, '_, W>, level: usize) { +fn end_expansion<'a, W: Write>( + token_handler: &mut TokenHandler<'_, '_, W>, + expanded_codes: Option<&'a Vec>, + level: usize, + line: u32, + span: Span, +) -> Option<&'a ExpandedCode> { + if let Some(expanded_code) = get_next_expansion(expanded_codes, line, span) { + // We close the current "original" content. + token_handler.pending_elems.push((Cow::Borrowed(""), Some(Class::Expansion))); + return Some(expanded_code); + } if level == 0 { token_handler.pending_elems.push((Cow::Borrowed(""), Some(Class::Expansion))); - return; + return None; } let mut out = String::new(); let mut end = String::new(); @@ -330,6 +352,7 @@ fn end_expansion(token_handler: &mut TokenHandler<'_, '_, W>, level: u token_handler .pending_elems .push((Cow::Owned(format!("{out}{end}")), Some(Class::Expansion))); + None } #[derive(Clone, Copy)] @@ -399,11 +422,14 @@ pub(super) fn write_code( (0, u32::MAX) }; - let expanded_codes = token_handler - .href_context - .as_ref() - .and_then(|c| c.context.shared.expanded_codes.get(&c.file_span.lo())); - let mut current_expansion = get_expansion(&mut token_handler, expanded_codes, line); + let (expanded_codes, file_span) = match token_handler.href_context.as_ref().and_then(|c| { + let expanded_codes = c.context.shared.expanded_codes.get(&c.file_span.lo())?; + Some((expanded_codes, c.file_span)) + }) { + Some((expanded_codes, file_span)) => (Some(expanded_codes), file_span), + None => (None, DUMMY_SP), + }; + let mut current_expansion = get_expansion(&mut token_handler, expanded_codes, line, file_span); token_handler.write_pending_elems(None); let mut level = 0; @@ -443,7 +469,8 @@ pub(super) fn write_code( .push((Cow::Borrowed(text), Some(Class::Backline(line)))); } if current_expansion.is_none() { - current_expansion = get_expansion(&mut token_handler, expanded_codes, line); + current_expansion = + get_expansion(&mut token_handler, expanded_codes, line, span); } } else { token_handler.pending_elems.push((Cow::Borrowed(text), class)); @@ -459,9 +486,11 @@ pub(super) fn write_code( } } if need_end { - end_expansion(&mut token_handler, level); - current_expansion = None; - level = 0; + current_expansion = + end_expansion(&mut token_handler, expanded_codes, level, line, span); + if current_expansion.is_none() { + level = 0; + } } } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 9403701d454..f3dafffbb6b 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -992,10 +992,10 @@ rustdoc-topbar { display: none; } -.src .example-wrap [data-nosnippet] { +.example-wrap [data-nosnippet] { width: calc(var(--example-wrap-digits-count) + var(--line-number-padding) * 2); } -.src .example-wrap pre > code { +.example-wrap pre > code { padding-left: calc( var(--example-wrap-digits-count) + var(--line-number-padding) * 2 + var(--line-number-right-margin)); @@ -1021,11 +1021,13 @@ rustdoc-topbar { } .example-wrap pre > code { position: relative; - word-break: break-all; display: block; +} +:root.word-wrap-source-code .example-wrap pre > code { + word-break: break-all; white-space: pre-wrap; } -.example-wrap pre > code * { +:root.word-wrap-source-code .example-wrap pre > code * { word-break: break-all; } .example-wrap [data-nosnippet]:target { -- cgit 1.4.1-3-g733a5 From b7a415017c853d0fee920d6b2822efd1dd5dd509 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 25 Feb 2025 18:12:35 +0100 Subject: Update rustdoc-gui tests --- src/doc/rustdoc/src/unstable-features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 724e260009e..bb28e3abbf3 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -799,4 +799,4 @@ will be split as follows: ## `--generate-macro-expansion`: Generate macros expansion toggles in source code -This flag enables the generation of toggles to expand macros in the HTML source code pages, +This flag enables the generation of toggles to expand macros in the HTML source code pages. -- cgit 1.4.1-3-g733a5 From 3de3b279f0e2490ed1a76f4a9abe75656a1c0dab Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 May 2025 14:07:23 +0200 Subject: Go around firefox bug --- src/librustdoc/html/static/css/rustdoc.css | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index f3dafffbb6b..0b7a8abdf09 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1001,7 +1001,13 @@ rustdoc-topbar { + var(--line-number-right-margin)); } .src .example-wrap .expansion [data-nosnippet] { - left: calc(( + /* FIXME: Once is solved, uncomment + next line and remove the two other rules. */ + /*left: calc(( + var(--example-wrap-digits-count) + var(--line-number-padding) * 2 + + var(--line-number-right-margin)) * -1);*/ + position: initial; + margin-left: calc(( var(--example-wrap-digits-count) + var(--line-number-padding) * 2 + var(--line-number-right-margin)) * -1); } -- cgit 1.4.1-3-g733a5 From ab000e15e1c6fd571882ebd0852ee39fabe6820d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 May 2025 17:00:41 +0200 Subject: Clean up computation of macro expansion span and correctly handle spans open inside expansion spans --- src/librustdoc/html/highlight.rs | 75 ++++++++++++++++++++++++++-------- src/librustdoc/html/render/span_map.rs | 43 ++++++++++++++----- 2 files changed, 90 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 39fec2cbe69..3457ac5b232 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -169,6 +169,17 @@ struct TokenHandler<'a, 'tcx, F: Write> { write_line_number: fn(&mut F, u32, &'static str), } +impl std::fmt::Debug for TokenHandler<'_, '_, F> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TokenHandler") + .field("closing_tags", &self.closing_tags) + .field("pending_exit_span", &self.pending_exit_span) + .field("current_class", &self.current_class) + .field("pending_elems", &self.pending_elems) + .finish() + } +} + impl TokenHandler<'_, '_, F> { fn handle_exit_span(&mut self) { // We can't get the last `closing_tags` element using `pop()` because `closing_tags` is @@ -221,6 +232,12 @@ impl TokenHandler<'_, '_, F> { } else { None }; + let mut last_pending = None; + // To prevent opening a macro expansion span being closed right away because + // the currently open item is replaced by a new class. + if let Some((_, Some(Class::Expansion))) = self.pending_elems.last() { + last_pending = self.pending_elems.pop(); + } for (text, class) in self.pending_elems.iter() { string( self.out, @@ -234,6 +251,16 @@ impl TokenHandler<'_, '_, F> { if let Some(close_tag) = close_tag { exit_span(self.out, close_tag); } + if let Some((text, class)) = last_pending { + string( + self.out, + EscapeBodyText(&text), + class, + &self.href_context, + close_tag.is_none(), + self.write_line_number, + ); + } } self.pending_elems.clear(); true @@ -278,7 +305,7 @@ fn get_next_expansion<'a>( span: Span, ) -> Option<&'a ExpandedCode> { if let Some(expanded_codes) = expanded_codes { - expanded_codes.iter().find(|code| code.start_line == line && code.span.lo() >= span.lo()) + expanded_codes.iter().find(|code| code.start_line == line && code.span.lo() > span.lo()) } else { None } @@ -328,7 +355,7 @@ fn start_expansion(out: &mut Vec<(Cow<'_, str>, Option)>, expanded_code: fn end_expansion<'a, W: Write>( token_handler: &mut TokenHandler<'_, '_, W>, expanded_codes: Option<&'a Vec>, - level: usize, + expansion_start_tags: &[(&'static str, Class)], line: u32, span: Span, ) -> Option<&'a ExpandedCode> { @@ -337,15 +364,27 @@ fn end_expansion<'a, W: Write>( token_handler.pending_elems.push((Cow::Borrowed(""), Some(Class::Expansion))); return Some(expanded_code); } - if level == 0 { + if expansion_start_tags.is_empty() && token_handler.closing_tags.is_empty() { + // No need tag opened so we can just close expansion. token_handler.pending_elems.push((Cow::Borrowed(""), Some(Class::Expansion))); return None; } + + // If tags were opened inside the expansion, we need to close them and re-open them outside + // of the expansion span. let mut out = String::new(); let mut end = String::new(); - for (tag, class) in - token_handler.closing_tags.iter().skip(token_handler.closing_tags.len() - level) + + let mut closing_tags = token_handler.closing_tags.iter().peekable(); + let mut start_closing_tags = expansion_start_tags.iter().peekable(); + + while let (Some(tag), Some(start_tag)) = (closing_tags.peek(), start_closing_tags.peek()) + && tag == start_tag { + closing_tags.next(); + start_closing_tags.next(); + } + for (tag, class) in start_closing_tags.chain(closing_tags) { out.push_str(tag); end.push_str(&format!("", class.as_html())); } @@ -431,7 +470,7 @@ pub(super) fn write_code( }; let mut current_expansion = get_expansion(&mut token_handler, expanded_codes, line, file_span); token_handler.write_pending_elems(None); - let mut level = 0; + let mut expansion_start_tags = Vec::new(); Classifier::new( &src, @@ -471,6 +510,12 @@ pub(super) fn write_code( if current_expansion.is_none() { current_expansion = get_expansion(&mut token_handler, expanded_codes, line, span); + expansion_start_tags = token_handler.closing_tags.clone(); + } + if let Some(ref current_expansion) = current_expansion + && current_expansion.span.lo() == span.hi() + { + start_expansion(&mut token_handler.pending_elems, current_expansion); } } else { token_handler.pending_elems.push((Cow::Borrowed(text), class)); @@ -486,11 +531,13 @@ pub(super) fn write_code( } } if need_end { - current_expansion = - end_expansion(&mut token_handler, expanded_codes, level, line, span); - if current_expansion.is_none() { - level = 0; - } + current_expansion = end_expansion( + &mut token_handler, + expanded_codes, + &expansion_start_tags, + line, + span, + ); } } } @@ -511,9 +558,6 @@ pub(super) fn write_code( if should_add { let closing_tag = enter_span(token_handler.out, class, &token_handler.href_context); - if current_expansion.is_some() { - level += 1; - } token_handler.closing_tags.push((closing_tag, class)); } @@ -522,9 +566,6 @@ pub(super) fn write_code( } Highlight::ExitSpan => { token_handler.current_class = None; - if current_expansion.is_some() { - level -= 1; - } token_handler.pending_exit_span = Some( token_handler .closing_tags diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 10969188dc7..04071a9e066 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -325,6 +325,8 @@ struct ExpandedCodeInfo { span: Span, /// Expanded macro source code. code: String, + /// Expanded span + expanded_span: Span, } /// HIR visitor which retrieves expanded macro. @@ -341,19 +343,32 @@ impl<'tcx> ExpandedCodeVisitor<'tcx> { if new_span.is_dummy() || !new_span.from_expansion() { return; } - let new_span = new_span.source_callsite(); + let callsite_span = new_span.source_callsite(); if let Some(index) = - self.expanded_codes.iter().position(|info| info.span.overlaps(new_span)) + self.expanded_codes.iter().position(|info| info.span.overlaps(callsite_span)) { - if !self.expanded_codes[index].span.contains(new_span) { + let info = &mut self.expanded_codes[index]; + if new_span.contains(info.expanded_span) { // We replace the item. - let info = &mut self.expanded_codes[index]; - info.span = new_span; + info.span = callsite_span; + info.expanded_span = new_span; info.code = f(self.tcx); + } else { + // We push the new item after the existing one. + let expanded_code = &mut self.expanded_codes[index]; + expanded_code.code.push('\n'); + expanded_code.code.push_str(&f(self.tcx)); + let lo = BytePos(expanded_code.expanded_span.lo().0.min(new_span.lo().0)); + let hi = BytePos(expanded_code.expanded_span.hi().0.min(new_span.hi().0)); + expanded_code.expanded_span = expanded_code.expanded_span.with_lo(lo).with_hi(hi); } } else { // We add a new item. - self.expanded_codes.push(ExpandedCodeInfo { span: new_span, code: f(self.tcx) }); + self.expanded_codes.push(ExpandedCodeInfo { + span: callsite_span, + code: f(self.tcx), + expanded_span: new_span, + }); } } @@ -361,7 +376,7 @@ impl<'tcx> ExpandedCodeVisitor<'tcx> { self.expanded_codes.sort_unstable_by(|item1, item2| item1.span.cmp(&item2.span)); let source_map = self.tcx.sess.source_map(); let mut expanded: FxHashMap> = FxHashMap::default(); - for ExpandedCodeInfo { span, code } in self.expanded_codes { + for ExpandedCodeInfo { span, code, .. } in self.expanded_codes { if let Ok(lines) = source_map.span_to_lines(span) && !lines.lines.is_empty() { @@ -389,12 +404,18 @@ impl<'tcx> Visitor<'tcx> for ExpandedCodeVisitor<'tcx> { } fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { - self.handle_new_span(expr.span, |tcx| rustc_hir_pretty::expr_to_string(&tcx, expr)); - intravisit::walk_expr(self, expr); + if expr.span.from_expansion() { + self.handle_new_span(expr.span, |tcx| rustc_hir_pretty::expr_to_string(&tcx, expr)); + } else { + intravisit::walk_expr(self, expr); + } } fn visit_item(&mut self, item: &'tcx rustc_hir::Item<'tcx>) { - self.handle_new_span(item.span, |tcx| rustc_hir_pretty::item_to_string(&tcx, item)); - intravisit::walk_item(self, item); + if item.span.from_expansion() { + self.handle_new_span(item.span, |tcx| rustc_hir_pretty::item_to_string(&tcx, item)); + } else { + intravisit::walk_item(self, item); + } } } -- cgit 1.4.1-3-g733a5 From f8b8cc4cceda39ec2c0a933fd1ba4b9951401862 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 19 May 2025 23:10:09 +0200 Subject: Do macro expansion at AST level rather than HIR --- src/librustdoc/core.rs | 13 ++- src/librustdoc/formats/renderer.rs | 18 ++--- src/librustdoc/html/highlight.rs | 3 +- src/librustdoc/html/macro_expansion.rs | 140 +++++++++++++++++++++++++++++++++ src/librustdoc/html/mod.rs | 1 + src/librustdoc/html/render/context.rs | 29 +++---- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/render/span_map.rs | 135 +------------------------------ src/librustdoc/json/mod.rs | 20 ++--- src/librustdoc/lib.rs | 50 ++++++++++-- src/librustdoc/scrape_examples.rs | 4 +- tests/rustdoc-gui/macro-expansion.goml | 54 ++++++------- 12 files changed, 264 insertions(+), 205 deletions(-) create mode 100644 src/librustdoc/html/macro_expansion.rs (limited to 'src') diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index e89733b2f6d..b8aaafcb517 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -31,6 +31,7 @@ use crate::clean::inline::build_trait; use crate::clean::{self, ItemId}; use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions}; use crate::formats::cache::Cache; +use crate::html::macro_expansion::{ExpandedCode, source_macro_expansion}; use crate::passes; use crate::passes::Condition::*; use crate::passes::collect_intra_doc_links::LinkCollector; @@ -334,11 +335,19 @@ pub(crate) fn run_global_ctxt( show_coverage: bool, render_options: RenderOptions, output_format: OutputFormat, -) -> (clean::Crate, RenderOptions, Cache) { +) -> (clean::Crate, RenderOptions, Cache, FxHashMap>) { // Certain queries assume that some checks were run elsewhere // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425), // so type-check everything other than function bodies in this crate before running lints. + let expanded_macros = { + // We need for these variables to be removed to ensure that the `Crate` won't be "stolen" + // anymore. + let (_resolver, krate) = &*tcx.resolver_for_lowering().borrow(); + + source_macro_expansion(&krate, &render_options, output_format, tcx.sess.source_map()) + }; + // NOTE: this does not call `tcx.analysis()` so that we won't // typeck function bodies or run the default rustc lints. // (see `override_queries` in the `config`) @@ -448,7 +457,7 @@ pub(crate) fn run_global_ctxt( tcx.dcx().abort_if_errors(); - (krate, ctxt.render_options, ctxt.cache) + (krate, ctxt.render_options, ctxt.cache, expanded_macros) } /// Due to , diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index aa4be4db997..305c8c39ba7 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -31,15 +31,6 @@ pub(crate) trait FormatRenderer<'tcx>: Sized { /// reset the information between each call to `item` by using `restore_module_data`. type ModuleData; - /// Sets up any state required for the renderer. When this is called the cache has already been - /// populated. - fn init( - krate: clean::Crate, - options: RenderOptions, - cache: Cache, - tcx: TyCtxt<'tcx>, - ) -> Result<(Self, clean::Crate), Error>; - /// This method is called right before call [`Self::item`]. This method returns a type /// containing information that needs to be reset after the [`Self::item`] method has been /// called with the [`Self::restore_module_data`] method. @@ -105,18 +96,23 @@ fn run_format_inner<'tcx, T: FormatRenderer<'tcx>>( } /// Main method for rendering a crate. -pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>( +pub(crate) fn run_format< + 'tcx, + T: FormatRenderer<'tcx>, + F: FnOnce(clean::Crate, RenderOptions, Cache, TyCtxt<'tcx>) -> Result<(T, clean::Crate), Error>, +>( krate: clean::Crate, options: RenderOptions, cache: Cache, tcx: TyCtxt<'tcx>, + init: F, ) -> Result<(), Error> { let prof = &tcx.sess.prof; let emit_crate = options.should_emit_crate(); let (mut format_renderer, krate) = prof .verbose_generic_activity_with_arg("create_renderer", T::descr()) - .run(|| T::init(krate, options, cache, tcx))?; + .run(|| init(krate, options, cache, tcx))?; if !emit_crate { return Ok(()); diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 3457ac5b232..5a25d659b0f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -18,7 +18,8 @@ use rustc_span::{BytePos, DUMMY_SP, Span}; use super::format::{self, write_str}; use crate::clean::PrimitiveType; use crate::html::escape::EscapeBodyText; -use crate::html::render::{Context, ExpandedCode, LinkFromSrc}; +use crate::html::macro_expansion::ExpandedCode; +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. pub(crate) struct HrefContext<'a, 'tcx> { diff --git a/src/librustdoc/html/macro_expansion.rs b/src/librustdoc/html/macro_expansion.rs new file mode 100644 index 00000000000..7b6758868b7 --- /dev/null +++ b/src/librustdoc/html/macro_expansion.rs @@ -0,0 +1,140 @@ +use rustc_ast::visit::{Visitor, walk_crate, walk_expr, walk_item}; +use rustc_ast::{Crate, Expr, Item}; +use rustc_data_structures::fx::FxHashMap; +use rustc_span::source_map::SourceMap; +use rustc_span::{BytePos, Span}; + +use crate::config::{OutputFormat, RenderOptions}; + +/// It returns the expanded macros correspondence map. +pub(crate) fn source_macro_expansion( + krate: &Crate, + render_options: &RenderOptions, + output_format: OutputFormat, + source_map: &SourceMap, +) -> FxHashMap> { + if output_format == OutputFormat::Html + && !render_options.html_no_source + && render_options.generate_macro_expansion + { + let mut expanded_visitor = ExpandedCodeVisitor { expanded_codes: Vec::new(), source_map }; + walk_crate(&mut expanded_visitor, krate); + expanded_visitor.compute_expanded() + } else { + Default::default() + } +} + +/// Contains information about macro expansion in the source code pages. +#[derive(Debug)] +pub(crate) struct ExpandedCode { + /// The line where the macro expansion starts. + pub(crate) start_line: u32, + /// The line where the macro expansion ends. + pub(crate) end_line: u32, + /// The source code of the expanded macro. + pub(crate) code: String, + /// The span of macro callsite. + pub(crate) span: Span, +} + +/// Contains temporary information of macro expanded code. +/// +/// As we go through the HIR visitor, if any span overlaps with another, they will +/// both be merged. +struct ExpandedCodeInfo { + /// Callsite of the macro. + span: Span, + /// Expanded macro source code. + code: String, + /// Expanded span + expanded_span: Span, +} + +/// HIR visitor which retrieves expanded macro. +/// +/// Once done, the `expanded_codes` will be transformed into a vec of [`ExpandedCode`] +/// which contains more information needed when running the source code highlighter. +pub(crate) struct ExpandedCodeVisitor<'ast> { + expanded_codes: Vec, + source_map: &'ast SourceMap, +} + +impl<'ast> ExpandedCodeVisitor<'ast> { + fn handle_new_span String>(&mut self, new_span: Span, f: F) { + if new_span.is_dummy() || !new_span.from_expansion() { + return; + } + let callsite_span = new_span.source_callsite(); + if let Some(index) = + self.expanded_codes.iter().position(|info| info.span.overlaps(callsite_span)) + { + let info = &mut self.expanded_codes[index]; + if new_span.contains(info.expanded_span) { + // We replace the item. + info.span = callsite_span; + info.expanded_span = new_span; + info.code = f(); + } else { + // We push the new item after the existing one. + let expanded_code = &mut self.expanded_codes[index]; + expanded_code.code.push('\n'); + expanded_code.code.push_str(&f()); + let lo = BytePos(expanded_code.expanded_span.lo().0.min(new_span.lo().0)); + let hi = BytePos(expanded_code.expanded_span.hi().0.min(new_span.hi().0)); + expanded_code.expanded_span = expanded_code.expanded_span.with_lo(lo).with_hi(hi); + } + } else { + // We add a new item. + self.expanded_codes.push(ExpandedCodeInfo { + span: callsite_span, + code: f(), + expanded_span: new_span, + }); + } + } + + fn compute_expanded(mut self) -> FxHashMap> { + self.expanded_codes.sort_unstable_by(|item1, item2| item1.span.cmp(&item2.span)); + let mut expanded: FxHashMap> = FxHashMap::default(); + for ExpandedCodeInfo { span, code, .. } in self.expanded_codes { + if let Ok(lines) = self.source_map.span_to_lines(span) + && !lines.lines.is_empty() + { + let mut out = String::new(); + super::highlight::write_code(&mut out, &code, None, None, None); + let first = lines.lines.first().unwrap(); + let end = lines.lines.last().unwrap(); + expanded.entry(lines.file.start_pos).or_default().push(ExpandedCode { + start_line: first.line_index as u32 + 1, + end_line: end.line_index as u32 + 1, + code: out, + span, + }); + } + } + expanded + } +} + +// We need to use the AST pretty printing because: +// +// 1. HIR pretty printing doesn't display accurately the code (like `impl Trait`). +// 2. `SourceMap::snippet_opt` might fail if the source is not available. +impl<'ast> Visitor<'ast> for ExpandedCodeVisitor<'ast> { + fn visit_expr(&mut self, expr: &'ast Expr) { + if expr.span.from_expansion() { + self.handle_new_span(expr.span, || rustc_ast_pretty::pprust::expr_to_string(expr)); + } else { + walk_expr(self, expr); + } + } + + fn visit_item(&mut self, item: &'ast Item) { + if item.span.from_expansion() { + self.handle_new_span(item.span, || rustc_ast_pretty::pprust::item_to_string(item)); + } else { + walk_item(self, item); + } + } +} diff --git a/src/librustdoc/html/mod.rs b/src/librustdoc/html/mod.rs index 481ed16c05f..170449fc033 100644 --- a/src/librustdoc/html/mod.rs +++ b/src/librustdoc/html/mod.rs @@ -4,6 +4,7 @@ pub(crate) mod highlight; pub(crate) mod layout; mod length_limit; // used by the error-index generator, so it needs to be public +pub(crate) mod macro_expansion; pub mod markdown; pub(crate) mod render; pub(crate) mod sources; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index af9af5ba2b3..faaecaf0cbb 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -28,8 +28,8 @@ use crate::formats::FormatRenderer; use crate::formats::cache::Cache; 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::ExpandedCode; use crate::html::render::write_shared::write_shared; use crate::html::url_parts_builder::UrlPartsBuilder; use crate::html::{layout, sources, static_files}; @@ -460,20 +460,13 @@ impl<'tcx> Context<'tcx> { } } -/// Generates the documentation for `crate` into the directory `dst` -impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { - fn descr() -> &'static str { - "html" - } - - const RUN_ON_MODULE: bool = true; - type ModuleData = ContextInfo; - - fn init( +impl<'tcx> Context<'tcx> { + pub(crate) fn init( krate: clean::Crate, options: RenderOptions, cache: Cache, tcx: TyCtxt<'tcx>, + expanded_codes: FxHashMap>, ) -> Result<(Self, clean::Crate), Error> { // need to save a copy of the options for rendering the index page let md_opts = options.clone(); @@ -492,7 +485,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { generate_redirect_map, show_type_layout, generate_link_to_definition, - generate_macro_expansion, call_locations, no_emit_shared, html_no_source, @@ -551,13 +543,12 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } } - let (local_sources, matches, expanded_codes) = collect_spans_and_sources( + let (local_sources, matches) = collect_spans_and_sources( tcx, &krate, &src_root, include_sources, generate_link_to_definition, - generate_macro_expansion, ); let (sender, receiver) = channel(); @@ -609,6 +600,16 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { Ok((cx, krate)) } +} + +/// Generates the documentation for `crate` into the directory `dst` +impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { + fn descr() -> &'static str { + "html" + } + + const RUN_ON_MODULE: bool = true; + type ModuleData = ContextInfo; fn save_module_data(&mut self) -> Self::ModuleData { self.deref_id_map.borrow_mut().clear(); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 0986b9ca47b..8d7f0577506 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -63,7 +63,7 @@ use serde::{Serialize, Serializer}; use tracing::{debug, info}; pub(crate) use self::context::*; -pub(crate) use self::span_map::{ExpandedCode, LinkFromSrc, collect_spans_and_sources}; +pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources}; pub(crate) use self::write_shared::*; use crate::clean::{self, ItemId, RenderedLink}; use crate::display::{Joined as _, MaybeDisplay as _}; diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 04071a9e066..8bc2e0bd957 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -30,26 +30,12 @@ pub(crate) enum LinkFromSrc { Doc(DefId), } -/// Contains information about macro expansion in the source code pages. -#[derive(Debug)] -pub(crate) struct ExpandedCode { - /// The line where the macro expansion starts. - pub(crate) start_line: u32, - /// The line where the macro expansion ends. - pub(crate) end_line: u32, - /// The source code of the expanded macro. - pub(crate) code: String, - /// The span of macro callsite. - pub(crate) span: Span, -} - /// This function will do at most two things: /// /// 1. Generate a `span` correspondence map which links an item `span` to its definition `span`. /// 2. Collect the source code files. /// -/// It returns the source code files, the `span` correspondence map and the expanded macros -/// correspondence map. +/// It returns the source code files and the `span` correspondence map. /// /// Note about the `span` correspondence map: the keys are actually `(lo, hi)` of `span`s. We don't /// need the `span` context later on, only their position, so instead of keeping a whole `Span`, we @@ -60,26 +46,17 @@ pub(crate) fn collect_spans_and_sources( src_root: &Path, include_sources: bool, generate_link_to_definition: bool, - generate_macro_expansion: bool, -) -> ( - FxIndexMap, - FxHashMap, - FxHashMap>, -) { +) -> (FxIndexMap, FxHashMap) { if include_sources { let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() }; - let mut expanded_visitor = ExpandedCodeVisitor { tcx, expanded_codes: Vec::new() }; - if generate_macro_expansion { - tcx.hir_walk_toplevel_module(&mut expanded_visitor); - } if generate_link_to_definition { tcx.hir_walk_toplevel_module(&mut visitor); } let sources = sources::collect_local_sources(tcx, src_root, krate); - (sources, visitor.matches, expanded_visitor.compute_expanded()) + (sources, visitor.matches) } else { - (Default::default(), Default::default(), Default::default()) + (Default::default(), Default::default()) } } @@ -315,107 +292,3 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { intravisit::walk_item(self, item); } } - -/// Contains temporary information of macro expanded code. -/// -/// As we go through the HIR visitor, if any span overlaps with another, they will -/// both be merged. -struct ExpandedCodeInfo { - /// Callsite of the macro. - span: Span, - /// Expanded macro source code. - code: String, - /// Expanded span - expanded_span: Span, -} - -/// HIR visitor which retrieves expanded macro. -/// -/// Once done, the `expanded_codes` will be transformed into a vec of [`ExpandedCode`] -/// which contains more information needed when running the source code highlighter. -pub struct ExpandedCodeVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - expanded_codes: Vec, -} - -impl<'tcx> ExpandedCodeVisitor<'tcx> { - fn handle_new_span) -> String>(&mut self, new_span: Span, f: F) { - if new_span.is_dummy() || !new_span.from_expansion() { - return; - } - let callsite_span = new_span.source_callsite(); - if let Some(index) = - self.expanded_codes.iter().position(|info| info.span.overlaps(callsite_span)) - { - let info = &mut self.expanded_codes[index]; - if new_span.contains(info.expanded_span) { - // We replace the item. - info.span = callsite_span; - info.expanded_span = new_span; - info.code = f(self.tcx); - } else { - // We push the new item after the existing one. - let expanded_code = &mut self.expanded_codes[index]; - expanded_code.code.push('\n'); - expanded_code.code.push_str(&f(self.tcx)); - let lo = BytePos(expanded_code.expanded_span.lo().0.min(new_span.lo().0)); - let hi = BytePos(expanded_code.expanded_span.hi().0.min(new_span.hi().0)); - expanded_code.expanded_span = expanded_code.expanded_span.with_lo(lo).with_hi(hi); - } - } else { - // We add a new item. - self.expanded_codes.push(ExpandedCodeInfo { - span: callsite_span, - code: f(self.tcx), - expanded_span: new_span, - }); - } - } - - fn compute_expanded(mut self) -> FxHashMap> { - self.expanded_codes.sort_unstable_by(|item1, item2| item1.span.cmp(&item2.span)); - let source_map = self.tcx.sess.source_map(); - let mut expanded: FxHashMap> = FxHashMap::default(); - for ExpandedCodeInfo { span, code, .. } in self.expanded_codes { - if let Ok(lines) = source_map.span_to_lines(span) - && !lines.lines.is_empty() - { - let mut out = String::new(); - super::highlight::write_code(&mut out, &code, None, None, None); - let first = lines.lines.first().unwrap(); - let end = lines.lines.last().unwrap(); - expanded.entry(lines.file.start_pos).or_default().push(ExpandedCode { - start_line: first.line_index as u32 + 1, - end_line: end.line_index as u32 + 1, - code: out, - span, - }); - } - } - expanded - } -} - -impl<'tcx> Visitor<'tcx> for ExpandedCodeVisitor<'tcx> { - type NestedFilter = nested_filter::All; - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.tcx - } - - fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { - if expr.span.from_expansion() { - self.handle_new_span(expr.span, |tcx| rustc_hir_pretty::expr_to_string(&tcx, expr)); - } else { - intravisit::walk_expr(self, expr); - } - } - - fn visit_item(&mut self, item: &'tcx rustc_hir::Item<'tcx>) { - if item.span.from_expansion() { - self.handle_new_span(item.span, |tcx| rustc_hir_pretty::item_to_string(&tcx, item)); - } else { - intravisit::walk_item(self, item); - } - } -} diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 760e48baffa..b724d7e866a 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -175,15 +175,8 @@ fn target(sess: &rustc_session::Session) -> types::Target { } } -impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { - fn descr() -> &'static str { - "json" - } - - const RUN_ON_MODULE: bool = false; - type ModuleData = (); - - fn init( +impl<'tcx> JsonRenderer<'tcx> { + pub(crate) fn init( krate: clean::Crate, options: RenderOptions, cache: Cache, @@ -205,6 +198,15 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { krate, )) } +} + +impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { + fn descr() -> &'static str { + "json" + } + + const RUN_ON_MODULE: bool = false; + type ModuleData = (); fn save_module_data(&mut self) -> Self::ModuleData { unreachable!("RUN_ON_MODULE = false, should never call save_module_data") diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 09e7a42e944..fe56fdb2271 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -80,6 +80,8 @@ use rustc_session::{EarlyDiagCtxt, getopts}; use tracing::info; use crate::clean::utils::DOC_RUST_LANG_ORG_VERSION; +use crate::error::Error; +use crate::formats::cache::Cache; /// A macro to create a FxHashMap. /// @@ -734,13 +736,23 @@ pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) { } } -fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( +fn run_renderer< + 'tcx, + T: formats::FormatRenderer<'tcx>, + F: FnOnce( + clean::Crate, + config::RenderOptions, + Cache, + TyCtxt<'tcx>, + ) -> Result<(T, clean::Crate), Error>, +>( krate: clean::Crate, renderopts: config::RenderOptions, cache: formats::cache::Cache, tcx: TyCtxt<'tcx>, + init: F, ) { - match formats::run_format::(krate, renderopts, cache, tcx) { + match formats::run_format::(krate, renderopts, cache, tcx, init) { Ok(_) => tcx.dcx().abort_if_errors(), Err(e) => { let mut msg = @@ -870,6 +882,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { let scrape_examples_options = options.scrape_examples_options.clone(); let bin_crate = options.bin_crate; + let output_format = options.output_format; let config = core::create_config(input, options, &render_options); let registered_lints = config.register_lints.is_some(); @@ -894,9 +907,10 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { sess.dcx().fatal("Compilation failed, aborting rustdoc"); } - let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { - core::run_global_ctxt(tcx, show_coverage, render_options, output_format) - }); + let (krate, render_opts, mut cache, expanded_macros) = sess + .time("run_global_ctxt", || { + core::run_global_ctxt(tcx, show_coverage, render_options, output_format) + }); info!("finished with rustc"); if let Some(options) = scrape_examples_options { @@ -927,10 +941,32 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { info!("going to format"); match output_format { config::OutputFormat::Html => sess.time("render_html", || { - run_renderer::>(krate, render_opts, cache, tcx) + run_renderer( + krate, + render_opts, + cache, + tcx, + |krate, render_opts, cache, tcx| { + html::render::Context::init( + krate, + render_opts, + cache, + tcx, + expanded_macros, + ) + }, + ) }), config::OutputFormat::Json => sess.time("render_json", || { - run_renderer::>(krate, render_opts, cache, tcx) + run_renderer( + krate, + render_opts, + cache, + tcx, + |krate, render_opts, cache, tcx| { + json::JsonRenderer::init(krate, render_opts, cache, tcx) + }, + ) }), // Already handled above with doctest runners. config::OutputFormat::Doctest => unreachable!(), diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 9f71d6ae789..16034c11827 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -18,7 +18,6 @@ use rustc_span::edition::Edition; use rustc_span::{BytePos, FileName, SourceFile}; use tracing::{debug, trace, warn}; -use crate::formats::renderer::FormatRenderer; use crate::html::render::Context; use crate::{clean, config, formats}; @@ -276,7 +275,8 @@ pub(crate) fn run( let inner = move || -> Result<(), String> { // Generates source files for examples renderopts.no_emit_shared = true; - let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?; + let (cx, _) = Context::init(krate, renderopts, cache, tcx, Default::default()) + .map_err(|e| e.to_string())?; // Collect CrateIds corresponding to provided target crates // If two different versions of the crate in the dependency tree, then examples will be diff --git a/tests/rustdoc-gui/macro-expansion.goml b/tests/rustdoc-gui/macro-expansion.goml index 3d790ae37a8..c398c58adac 100644 --- a/tests/rustdoc-gui/macro-expansion.goml +++ b/tests/rustdoc-gui/macro-expansion.goml @@ -27,48 +27,48 @@ define-function: ( } ) -// First we check the derive macro expansion at line 12. -call-function: ("check-expansion", {"line": 12, "original_content": "Debug"}) -// Then we check the `bar` macro expansion at line 22. -call-function: ("check-expansion", {"line": 22, "original_content": "bar!(y)"}) +// First we check the derive macro expansion at line 33. +call-function: ("check-expansion", {"line": 33, "original_content": "Debug"}) +// Then we check the `bar` macro expansion at line 41. +call-function: ("check-expansion", {"line": 41, "original_content": "bar!(y)"}) // Then we check the `println` macro expansion at line 23-25. -call-function: ("check-expansion", {"line": 23, "original_content": 'println!(" -24 {y} -25 ")'}) +call-function: ("check-expansion", {"line": 42, "original_content": 'println!(" +43 {y} +44 ")'}) // Then finally we check when there are two macro calls on a same line. -assert-count: ("#expand-27 ~ .original", 2) -assert-count: ("#expand-27 ~ .expanded", 2) +assert-count: ("#expand-50 ~ .original", 2) +assert-count: ("#expand-50 ~ .expanded", 2) store-value: (repeat_o, '/following-sibling::*[@class="original"]') store-value: (repeat_e, '/following-sibling::*[@class="expanded"]') -assert-text: ('//*[@id="expand-27"]' + |repeat_o|, "stringify!(foo)") -assert-text: ('//*[@id="expand-27"]' + |repeat_o| + |repeat_o|, "stringify!(bar)") -assert-text: ('//*[@id="expand-27"]' + |repeat_e|, '"foo"') -assert-text: ('//*[@id="expand-27"]' + |repeat_e| + |repeat_e|, '"bar"') +assert-text: ('//*[@id="expand-50"]' + |repeat_o|, "stringify!(foo)") +assert-text: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, "stringify!(bar)") +assert-text: ('//*[@id="expand-50"]' + |repeat_e|, '"foo"') +assert-text: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, '"bar"') // The "original" content should be expanded. -assert-css: ('//*[@id="expand-27"]' + |repeat_o|, {"display": "inline"}) -assert-css: ('//*[@id="expand-27"]' + |repeat_o| + |repeat_o|, {"display": "inline"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "inline"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "inline"}) // The expanded macro should be hidden. -assert-css: ('//*[@id="expand-27"]' + |repeat_e|, {"display": "none"}) -assert-css: ('//*[@id="expand-27"]' + |repeat_e| + |repeat_e|, {"display": "none"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "none"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "none"}) // We "expand" the macro (because the line starts with a string, the label is not at the "top // level" of the ``, so we need to use a different selector). -click: ".expansion label[for='expand-27']" +click: ".expansion label[for='expand-50']" // The "original" content is hidden. -assert-css: ('//*[@id="expand-27"]' + |repeat_o|, {"display": "none"}) -assert-css: ('//*[@id="expand-27"]' + |repeat_o| + |repeat_o|, {"display": "none"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "none"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "none"}) // The expanded macro is visible. -assert-css: ('//*[@id="expand-27"]' + |repeat_e|, {"display": "inline"}) -assert-css: ('//*[@id="expand-27"]' + |repeat_e| + |repeat_e|, {"display": "inline"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "inline"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "inline"}) // We collapse the macro. -click: ".expansion label[for='expand-27']" +click: ".expansion label[for='expand-50']" // The "original" content is expanded. -assert-css: ('//*[@id="expand-27"]' + |repeat_o|, {"display": "inline"}) -assert-css: ('//*[@id="expand-27"]' + |repeat_o| + |repeat_o|, {"display": "inline"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "inline"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "inline"}) // The expanded macro is hidden. -assert-css: ('//*[@id="expand-27"]' + |repeat_e|, {"display": "none"}) -assert-css: ('//*[@id="expand-27"]' + |repeat_e| + |repeat_e|, {"display": "none"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "none"}) +assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "none"}) -- cgit 1.4.1-3-g733a5 From b968ef8d198046bce1c77381a8069d2f837a2455 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 26 May 2025 15:04:48 +0200 Subject: Make macro expansion feature buttons accessible --- src/librustdoc/html/highlight.rs | 7 +++-- src/librustdoc/html/static/css/rustdoc.css | 14 ++++----- tests/rustdoc-gui/macro-expansion.goml | 49 +++++++++++++++++++++++++++--- 3 files changed, 55 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 5a25d659b0f..40530f67d6e 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -332,8 +332,11 @@ fn get_expansion<'a, W: Write>( Cow::Owned(format!( "{closing}\ \ - \ - {reopening}", + {reopening}", )), Some(Class::Expansion), )); diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 0b7a8abdf09..86f1a42bc01 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -961,10 +961,10 @@ rustdoc-topbar { display: inline; } .example-wrap .expansion > input { - display: none; -} -.example-wrap .expansion > label { + display: block; position: absolute; + appearance: none; + content: '↕'; left: -20px; top: 0; border: 1px solid var(--border-color); @@ -973,11 +973,9 @@ rustdoc-topbar { color: var(--main-color); padding: 0 2px; line-height: 20px; - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; - user-select: none; - +} +.example-wrap .expansion > input::after { + content: "↕"; } .example-wrap .expansion .expanded { display: none; diff --git a/tests/rustdoc-gui/macro-expansion.goml b/tests/rustdoc-gui/macro-expansion.goml index c398c58adac..5e9a3049405 100644 --- a/tests/rustdoc-gui/macro-expansion.goml +++ b/tests/rustdoc-gui/macro-expansion.goml @@ -12,14 +12,14 @@ define-function: ( assert-css: ("a[id='" + |line| + "'] + .expansion .expanded", {"display": "none"}) // We "expand" the macro. - click: "a[id='" + |line| + "'] + .expansion label" + click: "a[id='" + |line| + "'] + .expansion input[type=checkbox]" // The "original" content is hidden. assert-css: ("a[id='" + |line| + "'] + .expansion .original", {"display": "none"}) // The expanded macro is visible. assert-css: ("a[id='" + |line| + "'] + .expansion .expanded", {"display": "inline"}) // We collapse the macro. - click: "a[id='" + |line| + "'] + .expansion label" + click: "a[id='" + |line| + "'] + .expansion input[type=checkbox]" // The "original" content is expanded. assert-css: ("a[id='" + |line| + "'] + .expansion .original", {"display": "inline"}) // The expanded macro is hidden. @@ -31,7 +31,7 @@ define-function: ( call-function: ("check-expansion", {"line": 33, "original_content": "Debug"}) // Then we check the `bar` macro expansion at line 41. call-function: ("check-expansion", {"line": 41, "original_content": "bar!(y)"}) -// Then we check the `println` macro expansion at line 23-25. +// Then we check the `println` macro expansion at line 42-44. call-function: ("check-expansion", {"line": 42, "original_content": 'println!(" 43 {y} 44 ")'}) @@ -56,7 +56,7 @@ assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "none // We "expand" the macro (because the line starts with a string, the label is not at the "top // level" of the ``, so we need to use a different selector). -click: ".expansion label[for='expand-50']" +click: "#expand-50" // The "original" content is hidden. assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "none"}) assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "none"}) @@ -65,10 +65,49 @@ assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "inline"}) assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "inline"}) // We collapse the macro. -click: ".expansion label[for='expand-50']" +click: "#expand-50" // The "original" content is expanded. assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "inline"}) assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "inline"}) // The expanded macro is hidden. assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "none"}) assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "none"}) + +// Checking the line 46 `println` which needs to be handled differently because the line number is +// inside a "comment" span. +assert-text: ("#expand-46 ~ .original", 'println!(" +47 {y} +48 ")') +// The "original" content should be expanded. +assert-css: ("#expand-46 ~ .original", {"display": "inline"}) +// The expanded macro should be hidden. +assert-css: ("#expand-46 ~ .expanded", {"display": "none"}) + +// We "expand" the macro. +click: "#expand-46" +// The "original" content is hidden. +assert-css: ("#expand-46 ~ .original", {"display": "none"}) +// The expanded macro is visible. +assert-css: ("#expand-46 ~ .expanded", {"display": "inline"}) + +// We collapse the macro. +click: "#expand-46" +// The "original" content is expanded. +assert-css: ("#expand-46 ~ .original", {"display": "inline"}) +// The expanded macro is hidden. +assert-css: ("#expand-46 ~ .expanded", {"display": "none"}) + +// Ensure that the toggles are focusable and can be interacted with keyboard. +focus: "//a[@id='27']" +press-key: "Tab" +assert: "#expand-27:focus" +assert-css: ("#expand-27 ~ .expanded", {"display": "none"}) +assert-css: ("#expand-27 ~ .original", {"display": "inline"}) +// We now expand the macro. +press-key: "Space" +assert-css: ("#expand-27 ~ .expanded", {"display": "inline"}) +assert-css: ("#expand-27 ~ .original", {"display": "none"}) +// We collapse the macro. +press-key: "Space" +assert-css: ("#expand-27 ~ .expanded", {"display": "none"}) +assert-css: ("#expand-27 ~ .original", {"display": "inline"}) -- cgit 1.4.1-3-g733a5 From bd5f3d76789028e0cdb432ff20f744b6fb24efc2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 29 Jun 2025 12:26:06 +0200 Subject: Improve code --- src/librustdoc/html/highlight.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 40530f67d6e..583c178fa11 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -233,12 +233,10 @@ impl TokenHandler<'_, '_, F> { } else { None }; - let mut last_pending = None; // To prevent opening a macro expansion span being closed right away because // the currently open item is replaced by a new class. - if let Some((_, Some(Class::Expansion))) = self.pending_elems.last() { - last_pending = self.pending_elems.pop(); - } + let last_pending = + self.pending_elems.pop_if(|(_, class)| *class == Some(Class::Expansion)); for (text, class) in self.pending_elems.iter() { string( self.out, -- cgit 1.4.1-3-g733a5 From 0e9b126695847418a681b96b87b5976fb069394a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 1 Aug 2025 16:57:39 +0200 Subject: Also support statements and patterns for macro expansion --- src/librustdoc/html/macro_expansion.rs | 20 ++++++++++++++++++-- tests/rustdoc/macro/macro_expansion.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 tests/rustdoc/macro/macro_expansion.rs (limited to 'src') diff --git a/src/librustdoc/html/macro_expansion.rs b/src/librustdoc/html/macro_expansion.rs index 7b6758868b7..d76663a3d1a 100644 --- a/src/librustdoc/html/macro_expansion.rs +++ b/src/librustdoc/html/macro_expansion.rs @@ -1,5 +1,5 @@ -use rustc_ast::visit::{Visitor, walk_crate, walk_expr, walk_item}; -use rustc_ast::{Crate, Expr, Item}; +use rustc_ast::visit::{Visitor, walk_crate, walk_expr, walk_item, walk_pat, walk_stmt}; +use rustc_ast::{Crate, Expr, Item, Pat, Stmt}; use rustc_data_structures::fx::FxHashMap; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span}; @@ -137,4 +137,20 @@ impl<'ast> Visitor<'ast> for ExpandedCodeVisitor<'ast> { walk_item(self, item); } } + + fn visit_stmt(&mut self, stmt: &'ast Stmt) { + if stmt.span.from_expansion() { + self.handle_new_span(stmt.span, || rustc_ast_pretty::pprust::stmt_to_string(stmt)); + } else { + walk_stmt(self, stmt); + } + } + + fn visit_pat(&mut self, pat: &'ast Pat) { + if pat.span.from_expansion() { + self.handle_new_span(pat.span, || rustc_ast_pretty::pprust::pat_to_string(pat)); + } else { + walk_pat(self, pat); + } + } } diff --git a/tests/rustdoc/macro/macro_expansion.rs b/tests/rustdoc/macro/macro_expansion.rs new file mode 100644 index 00000000000..c989ccad967 --- /dev/null +++ b/tests/rustdoc/macro/macro_expansion.rs @@ -0,0 +1,28 @@ +// This test checks that patterns and statements are also getting expanded. + +//@ compile-flags: -Zunstable-options --generate-macro-expansion + +#![crate_name = "foo"] + +//@ has 'src/foo/macro_expansion.rs.html' +//@ count - '//span[@class="expansion"]' 2 + +macro_rules! pat { + ($x:literal) => { + Some($x) + } +} + +macro_rules! stmt { + ($x:expr) => {{ + let _ = $x; + }} +} + +fn bar() { + match Some("hello") { + pat!("blolb") => {} + _ => {} + } + stmt!(1) +} -- cgit 1.4.1-3-g733a5 From f5fddc776ca450c08fe8fc3ecbe5e2c969055d01 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 23 Aug 2025 01:38:57 +0200 Subject: Improve code and add test with macro coming from another file from the same crate --- src/librustdoc/html/highlight.rs | 22 +++--- src/librustdoc/html/macro_expansion.rs | 8 +- src/librustdoc/html/mod.rs | 2 +- src/librustdoc/lib.rs | 26 +++---- tests/rustdoc-gui/macro-expansion.goml | 103 ++++++++++++++----------- tests/rustdoc-gui/src/macro_expansion/lib.rs | 5 ++ tests/rustdoc-gui/src/macro_expansion/other.rs | 6 ++ 7 files changed, 92 insertions(+), 80 deletions(-) create mode 100644 tests/rustdoc-gui/src/macro_expansion/other.rs (limited to 'src') diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 583c178fa11..feafb41dc99 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -298,21 +298,17 @@ fn empty_line_number(out: &mut impl Write, _: u32, extra: &'static str) { out.write_str(extra).unwrap(); } -fn get_next_expansion<'a>( - expanded_codes: Option<&'a Vec>, +fn get_next_expansion( + expanded_codes: &[ExpandedCode], line: u32, span: Span, -) -> Option<&'a ExpandedCode> { - if let Some(expanded_codes) = expanded_codes { - expanded_codes.iter().find(|code| code.start_line == line && code.span.lo() > span.lo()) - } else { - None - } +) -> Option<&ExpandedCode> { + expanded_codes.iter().find(|code| code.start_line == line && code.span.lo() > span.lo()) } fn get_expansion<'a, W: Write>( token_handler: &mut TokenHandler<'_, '_, W>, - expanded_codes: Option<&'a Vec>, + expanded_codes: &'a [ExpandedCode], line: u32, span: Span, ) -> Option<&'a ExpandedCode> { @@ -356,7 +352,7 @@ fn start_expansion(out: &mut Vec<(Cow<'_, str>, Option)>, expanded_code: fn end_expansion<'a, W: Write>( token_handler: &mut TokenHandler<'_, '_, W>, - expanded_codes: Option<&'a Vec>, + expanded_codes: &'a [ExpandedCode], expansion_start_tags: &[(&'static str, Class)], line: u32, span: Span, @@ -467,8 +463,8 @@ pub(super) fn write_code( let expanded_codes = c.context.shared.expanded_codes.get(&c.file_span.lo())?; Some((expanded_codes, c.file_span)) }) { - Some((expanded_codes, file_span)) => (Some(expanded_codes), file_span), - None => (None, DUMMY_SP), + Some((expanded_codes, file_span)) => (expanded_codes.as_slice(), file_span), + None => (&[] as &[ExpandedCode], DUMMY_SP), }; let mut current_expansion = get_expansion(&mut token_handler, expanded_codes, line, file_span); token_handler.write_pending_elems(None); @@ -1257,7 +1253,7 @@ fn string( if let Some(Class::Backline(line)) = klass { write_line_number_callback(out, line, "\n"); } else if let Some(Class::Expansion) = klass { - // Nothing to escape here so we get the text to write it directly. + // This has already been escaped so we get the text to write it directly. out.write_str(text.0).unwrap(); } else if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag) diff --git a/src/librustdoc/html/macro_expansion.rs b/src/librustdoc/html/macro_expansion.rs index d76663a3d1a..9098e92a5cd 100644 --- a/src/librustdoc/html/macro_expansion.rs +++ b/src/librustdoc/html/macro_expansion.rs @@ -45,16 +45,16 @@ pub(crate) struct ExpandedCode { struct ExpandedCodeInfo { /// Callsite of the macro. span: Span, - /// Expanded macro source code. + /// Expanded macro source code (HTML escaped). code: String, - /// Expanded span + /// Span of macro-generated code. expanded_span: Span, } /// HIR visitor which retrieves expanded macro. /// /// Once done, the `expanded_codes` will be transformed into a vec of [`ExpandedCode`] -/// which contains more information needed when running the source code highlighter. +/// which contains the information needed when running the source code highlighter. pub(crate) struct ExpandedCodeVisitor<'ast> { expanded_codes: Vec, source_map: &'ast SourceMap, @@ -71,7 +71,7 @@ impl<'ast> ExpandedCodeVisitor<'ast> { { let info = &mut self.expanded_codes[index]; if new_span.contains(info.expanded_span) { - // We replace the item. + // New macro expansion recursively contains the old one, so replace it. info.span = callsite_span; info.expanded_span = new_span; info.code = f(); diff --git a/src/librustdoc/html/mod.rs b/src/librustdoc/html/mod.rs index 170449fc033..d42f4782845 100644 --- a/src/librustdoc/html/mod.rs +++ b/src/librustdoc/html/mod.rs @@ -3,8 +3,8 @@ pub(crate) mod format; pub(crate) mod highlight; pub(crate) mod layout; mod length_limit; -// used by the error-index generator, so it needs to be public pub(crate) mod macro_expansion; +// used by the error-index generator, so it needs to be public pub mod markdown; pub(crate) mod render; pub(crate) mod sources; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index fe56fdb2271..d891d1fba25 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -665,6 +665,14 @@ fn opts() -> Vec { "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)", "", ), + opt( + Unstable, + Flag, + "", + "generate-macro-expansion", + "Add possibility to expand macros in the HTML source code pages", + "", + ), // deprecated / removed options opt( Stable, @@ -706,14 +714,6 @@ fn opts() -> Vec { "removed, see issue #44136 for more information", "[rust]", ), - opt( - Unstable, - Flag, - "", - "generate-macro-expansion", - "Add possibility to expand macros in the HTML source code pages", - "", - ), ] } @@ -958,15 +958,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { ) }), config::OutputFormat::Json => sess.time("render_json", || { - run_renderer( - krate, - render_opts, - cache, - tcx, - |krate, render_opts, cache, tcx| { - json::JsonRenderer::init(krate, render_opts, cache, tcx) - }, - ) + run_renderer(krate, render_opts, cache, tcx, json::JsonRenderer::init) }), // Already handled above with doctest runners. config::OutputFormat::Doctest => unreachable!(), diff --git a/tests/rustdoc-gui/macro-expansion.goml b/tests/rustdoc-gui/macro-expansion.goml index 5e9a3049405..b87d0e4870a 100644 --- a/tests/rustdoc-gui/macro-expansion.goml +++ b/tests/rustdoc-gui/macro-expansion.goml @@ -28,86 +28,99 @@ define-function: ( ) // First we check the derive macro expansion at line 33. -call-function: ("check-expansion", {"line": 33, "original_content": "Debug"}) +call-function: ("check-expansion", {"line": 35, "original_content": "Debug"}) // Then we check the `bar` macro expansion at line 41. -call-function: ("check-expansion", {"line": 41, "original_content": "bar!(y)"}) +call-function: ("check-expansion", {"line": 43, "original_content": "bar!(y)"}) // Then we check the `println` macro expansion at line 42-44. -call-function: ("check-expansion", {"line": 42, "original_content": 'println!(" -43 {y} -44 ")'}) +call-function: ("check-expansion", {"line": 44, "original_content": 'println!(" +45 {y} +46 ")'}) // Then finally we check when there are two macro calls on a same line. -assert-count: ("#expand-50 ~ .original", 2) -assert-count: ("#expand-50 ~ .expanded", 2) +assert-count: ("#expand-52 ~ .original", 2) +assert-count: ("#expand-52 ~ .expanded", 2) store-value: (repeat_o, '/following-sibling::*[@class="original"]') store-value: (repeat_e, '/following-sibling::*[@class="expanded"]') -assert-text: ('//*[@id="expand-50"]' + |repeat_o|, "stringify!(foo)") -assert-text: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, "stringify!(bar)") -assert-text: ('//*[@id="expand-50"]' + |repeat_e|, '"foo"') -assert-text: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, '"bar"') +store-value: (expand_id, "expand-52") +assert-text: ('//*[@id="' + |expand_id| + '"]' + |repeat_o|, "stringify!(foo)") +assert-text: ('//*[@id="' + |expand_id| + '"]' + |repeat_o| + |repeat_o|, "stringify!(bar)") +assert-text: ('//*[@id="' + |expand_id| + '"]' + |repeat_e|, '"foo"') +assert-text: ('//*[@id="' + |expand_id| + '"]' + |repeat_e| + |repeat_e|, '"bar"') // The "original" content should be expanded. -assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "inline"}) -assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "inline"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o|, {"display": "inline"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o| + |repeat_o|, {"display": "inline"}) // The expanded macro should be hidden. -assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "none"}) -assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "none"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e|, {"display": "none"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e| + |repeat_e|, {"display": "none"}) // We "expand" the macro (because the line starts with a string, the label is not at the "top // level" of the ``, so we need to use a different selector). -click: "#expand-50" +click: "#" + |expand_id| // The "original" content is hidden. -assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "none"}) -assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "none"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o|, {"display": "none"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o| + |repeat_o|, {"display": "none"}) // The expanded macro is visible. -assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "inline"}) -assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "inline"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e|, {"display": "inline"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e| + |repeat_e|, {"display": "inline"}) // We collapse the macro. -click: "#expand-50" +click: "#" + |expand_id| // The "original" content is expanded. -assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "inline"}) -assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "inline"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o|, {"display": "inline"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o| + |repeat_o|, {"display": "inline"}) // The expanded macro is hidden. -assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "none"}) -assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "none"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e|, {"display": "none"}) +assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e| + |repeat_e|, {"display": "none"}) -// Checking the line 46 `println` which needs to be handled differently because the line number is +// Checking the line 48 `println` which needs to be handled differently because the line number is // inside a "comment" span. -assert-text: ("#expand-46 ~ .original", 'println!(" -47 {y} -48 ")') +store-value: (expand_id, "expand-48") +assert-text: ("#" + |expand_id| + " ~ .original", 'println!(" +49 {y} +50 ")') // The "original" content should be expanded. -assert-css: ("#expand-46 ~ .original", {"display": "inline"}) +assert-css: ("#" + |expand_id| + " ~ .original", {"display": "inline"}) // The expanded macro should be hidden. -assert-css: ("#expand-46 ~ .expanded", {"display": "none"}) +assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "none"}) // We "expand" the macro. -click: "#expand-46" +click: "#" + |expand_id| // The "original" content is hidden. -assert-css: ("#expand-46 ~ .original", {"display": "none"}) +assert-css: ("#" + |expand_id| + " ~ .original", {"display": "none"}) // The expanded macro is visible. -assert-css: ("#expand-46 ~ .expanded", {"display": "inline"}) +assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "inline"}) // We collapse the macro. -click: "#expand-46" +click: "#" + |expand_id| // The "original" content is expanded. -assert-css: ("#expand-46 ~ .original", {"display": "inline"}) +assert-css: ("#" + |expand_id| + " ~ .original", {"display": "inline"}) // The expanded macro is hidden. -assert-css: ("#expand-46 ~ .expanded", {"display": "none"}) +assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "none"}) // Ensure that the toggles are focusable and can be interacted with keyboard. -focus: "//a[@id='27']" +focus: "//a[@id='29']" press-key: "Tab" -assert: "#expand-27:focus" -assert-css: ("#expand-27 ~ .expanded", {"display": "none"}) -assert-css: ("#expand-27 ~ .original", {"display": "inline"}) +store-value: (expand_id, "expand-29") +assert: "#" + |expand_id| + ":focus" +assert-css: ("#" + |expand_id| +" ~ .expanded", {"display": "none"}) +assert-css: ("#" + |expand_id| +" ~ .original", {"display": "inline"}) // We now expand the macro. press-key: "Space" -assert-css: ("#expand-27 ~ .expanded", {"display": "inline"}) -assert-css: ("#expand-27 ~ .original", {"display": "none"}) +assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "inline"}) +assert-css: ("#" + |expand_id| + " ~ .original", {"display": "none"}) // We collapse the macro. press-key: "Space" -assert-css: ("#expand-27 ~ .expanded", {"display": "none"}) -assert-css: ("#expand-27 ~ .original", {"display": "inline"}) +assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "none"}) +assert-css: ("#" + |expand_id| + " ~ .original", {"display": "inline"}) + +// Now we check a macro coming from another file. +store-value: (expand_id, "expand-55") +// We "expand" the macro. +click: "#" + |expand_id| +// The "original" content is hidden. +assert-css: ("#" + |expand_id| + " ~ .original", {"display": "none"}) +// The expanded macro is visible. +assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "inline"}) +assert-text: ("#" + |expand_id| + " ~ .expanded", "{ y += 2; };") diff --git a/tests/rustdoc-gui/src/macro_expansion/lib.rs b/tests/rustdoc-gui/src/macro_expansion/lib.rs index 7926e0143d8..62a92d5d15e 100644 --- a/tests/rustdoc-gui/src/macro_expansion/lib.rs +++ b/tests/rustdoc-gui/src/macro_expansion/lib.rs @@ -1,6 +1,8 @@ // Test crate used to check the `--generate-macro-expansion` option. //@ compile-flags: -Zunstable-options --generate-macro-expansion --generate-link-to-definition +mod other; + #[macro_export] macro_rules! bar { ($x:ident) => {{ @@ -48,4 +50,7 @@ fn foo() { "); let s = y_f("\ bla", stringify!(foo), stringify!(bar)); + + // Macro from another file. + other_macro!(y); } diff --git a/tests/rustdoc-gui/src/macro_expansion/other.rs b/tests/rustdoc-gui/src/macro_expansion/other.rs new file mode 100644 index 00000000000..8661b01be38 --- /dev/null +++ b/tests/rustdoc-gui/src/macro_expansion/other.rs @@ -0,0 +1,6 @@ +#[macro_export] +macro_rules! other_macro { + ($x:ident) => {{ + $x += 2; + }} +} -- cgit 1.4.1-3-g733a5 From 3c664785c12a5b32b4489d0791cf8cc77fd1b3f6 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 27 Jul 2025 13:41:10 +0200 Subject: Allow `integer_to_ptr_transmutes` in tests --- src/tools/miri/tests/fail/branchless-select-i128-pointer.rs | 2 ++ src/tools/miri/tests/fail/provenance/provenance_transmute.rs | 2 ++ src/tools/miri/tests/fail/validity/dangling_ref1.rs | 3 +++ src/tools/miri/tests/panic/transmute_fat2.rs | 2 ++ src/tools/miri/tests/pass/binops.rs | 1 + src/tools/miri/tests/pass/too-large-primval-write-problem.rs | 2 ++ tests/ui/binop/binops.rs | 1 + 7 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs index 2b861e5447b..7147813c4b6 100644 --- a/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs +++ b/src/tools/miri/tests/fail/branchless-select-i128-pointer.rs @@ -1,3 +1,5 @@ +#![allow(integer_to_ptr_transmutes)] + use std::mem::transmute; #[cfg(target_pointer_width = "32")] diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs index d72f10530d7..60cb9a7f6bf 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs @@ -1,5 +1,7 @@ //@compile-flags: -Zmiri-permissive-provenance +#![allow(integer_to_ptr_transmutes)] + use std::mem; // This is the example from diff --git a/src/tools/miri/tests/fail/validity/dangling_ref1.rs b/src/tools/miri/tests/fail/validity/dangling_ref1.rs index fc3a9f34463..57ba1117e76 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref1.rs +++ b/src/tools/miri/tests/fail/validity/dangling_ref1.rs @@ -1,5 +1,8 @@ // Make sure we catch this even without Stacked Borrows //@compile-flags: -Zmiri-disable-stacked-borrows + +#![allow(integer_to_ptr_transmutes)] + use std::mem; fn main() { diff --git a/src/tools/miri/tests/panic/transmute_fat2.rs b/src/tools/miri/tests/panic/transmute_fat2.rs index e695ff2d57b..7441f25d03e 100644 --- a/src/tools/miri/tests/panic/transmute_fat2.rs +++ b/src/tools/miri/tests/panic/transmute_fat2.rs @@ -1,3 +1,5 @@ +#![allow(integer_to_ptr_transmutes)] + fn main() { #[cfg(all(target_endian = "little", target_pointer_width = "64"))] let bad = unsafe { std::mem::transmute::(42) }; diff --git a/src/tools/miri/tests/pass/binops.rs b/src/tools/miri/tests/pass/binops.rs index 0aff7acb29d..fcbe6c85b7b 100644 --- a/src/tools/miri/tests/pass/binops.rs +++ b/src/tools/miri/tests/pass/binops.rs @@ -32,6 +32,7 @@ fn test_bool() { assert_eq!(true ^ true, false); } +#[allow(integer_to_ptr_transmutes)] fn test_ptr() { unsafe { let p1: *const u8 = ::std::mem::transmute(0_usize); diff --git a/src/tools/miri/tests/pass/too-large-primval-write-problem.rs b/src/tools/miri/tests/pass/too-large-primval-write-problem.rs index f4c418bd78a..00882b7ecca 100644 --- a/src/tools/miri/tests/pass/too-large-primval-write-problem.rs +++ b/src/tools/miri/tests/pass/too-large-primval-write-problem.rs @@ -7,6 +7,8 @@ // // This is just intended as a regression test to make sure we don't reintroduce this problem. +#![allow(integer_to_ptr_transmutes)] + #[cfg(target_pointer_width = "32")] fn main() { use std::mem::transmute; diff --git a/tests/ui/binop/binops.rs b/tests/ui/binop/binops.rs index 7142190a45b..702e9a61345 100644 --- a/tests/ui/binop/binops.rs +++ b/tests/ui/binop/binops.rs @@ -35,6 +35,7 @@ fn test_bool() { assert_eq!(true ^ true, false); } +#[allow(integer_to_ptr_transmutes)] fn test_ptr() { unsafe { let p1: *const u8 = ::std::mem::transmute(0_usize); -- cgit 1.4.1-3-g733a5 From 02a67cc4a535fdb226a57a3d8d3ef32d68fd347c Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 27 Jul 2025 21:21:49 +0200 Subject: Adjust clippy lints for rustc `integer_to_ptr_transmutes` lint --- .../src/transmute/useless_transmute.rs | 12 +----- src/tools/clippy/tests/ui/transmute.rs | 3 +- src/tools/clippy/tests/ui/transmute.stderr | 46 ++++++++-------------- .../ui/transmutes_expressible_as_ptr_casts.fixed | 3 -- .../ui/transmutes_expressible_as_ptr_casts.rs | 3 -- .../ui/transmutes_expressible_as_ptr_casts.stderr | 32 ++++++--------- 6 files changed, 32 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs index ec5fb2793f9..b898920baef 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs @@ -49,17 +49,7 @@ pub(super) fn check<'tcx>( true }, (ty::Int(_) | ty::Uint(_), ty::RawPtr(_, _)) => { - span_lint_and_then( - cx, - USELESS_TRANSMUTE, - e.span, - "transmute from an integer to a pointer", - |diag| { - if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - diag.span_suggestion(e.span, "try", arg.as_ty(to_ty.to_string()), Applicability::Unspecified); - } - }, - ); + // Handled by the upstream rustc `integer_to_ptr_transmutes` lint true }, _ => false, diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index e968e7a5924..e7099104f94 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -4,6 +4,7 @@ dead_code, clippy::borrow_as_ptr, unnecessary_transmutes, + integer_to_ptr_transmutes, clippy::needless_lifetimes, clippy::missing_transmute_annotations )] @@ -60,12 +61,10 @@ fn useless() { //~^ useless_transmute let _: *const usize = std::mem::transmute(5_isize); - //~^ useless_transmute let _ = std::ptr::dangling::(); let _: *const usize = std::mem::transmute(1 + 1usize); - //~^ useless_transmute let _ = (1 + 1_usize) as *const usize; } diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index 79528ec06f1..9478db09481 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -1,5 +1,5 @@ error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:33:27 + --> tests/ui/transmute.rs:34:27 | LL | let _: *const T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T` @@ -8,61 +8,49 @@ LL | let _: *const T = core::mem::transmute(t); = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:36:25 + --> tests/ui/transmute.rs:37:25 | LL | let _: *mut T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:39:27 + --> tests/ui/transmute.rs:40:27 | LL | let _: *const U = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:47:27 + --> tests/ui/transmute.rs:48:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:50:27 + --> tests/ui/transmute.rs:51:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:53:27 + --> tests/ui/transmute.rs:54:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:56:27 + --> tests/ui/transmute.rs:57:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:59:27 + --> tests/ui/transmute.rs:60:27 | LL | let _: Vec = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ -error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:62:31 - | -LL | let _: *const usize = std::mem::transmute(5_isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize` - -error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:67:31 - | -LL | let _: *const usize = std::mem::transmute(1 + 1usize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize` - error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:99:24 + --> tests/ui/transmute.rs:98:24 | LL | let _: Usize = core::mem::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +59,25 @@ LL | let _: Usize = core::mem::transmute(int_const_ptr); = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:102:24 + --> tests/ui/transmute.rs:101:24 | LL | let _: Usize = core::mem::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:105:31 + --> tests/ui/transmute.rs:104:31 | LL | let _: *const Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:108:29 + --> tests/ui/transmute.rs:107:29 | LL | let _: *mut Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:115:28 + --> tests/ui/transmute.rs:114:28 | LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` @@ -98,7 +86,7 @@ LL | let _: bool = unsafe { std::mem::transmute(0_u8) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:122:28 + --> tests/ui/transmute.rs:121:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -107,16 +95,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]` error: transmute from a `&mut [u8]` to a `&mut str` - --> tests/ui/transmute.rs:125:32 + --> tests/ui/transmute.rs:124:32 | LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:128:30 + --> tests/ui/transmute.rs:127:30 | LL | const _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)` -error: aborting due to 18 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed index e7ad2a1cbbc..02f67f79e2b 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -13,9 +13,6 @@ fn main() { // We should see an error message for each transmute, and no error messages for // the casts, since the casts are the recommended fixes. - // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast - let _ptr_i32_transmute = unsafe { usize::MAX as *const i32 }; - //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs index 42a81777a82..c5e156405eb 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -13,9 +13,6 @@ fn main() { // We should see an error message for each transmute, and no error messages for // the casts, since the casts are the recommended fixes. - // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast - let _ptr_i32_transmute = unsafe { transmute::(usize::MAX) }; - //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr index 7746f087cc7..f39a64d57eb 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -1,14 +1,5 @@ -error: transmute from an integer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:17:39 - | -LL | let _ptr_i32_transmute = unsafe { transmute::(usize::MAX) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `usize::MAX as *const i32` - | - = note: `-D clippy::useless-transmute` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` - error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:22:38 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:19:38 | LL | let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +13,7 @@ LL + let _ptr_i8_transmute = unsafe { ptr_i32.cast::() }; | error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:29:46 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:26:46 | LL | let _ptr_to_unsized_transmute = unsafe { transmute::<*const [i32], *const [u32]>(slice_ptr) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +25,7 @@ LL + let _ptr_to_unsized_transmute = unsafe { slice_ptr as *const [u32] }; | error: transmute from `*const i32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:36:50 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:33:50 | LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, usize>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as usize` @@ -43,40 +34,43 @@ LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, us = help: to override `-D warnings` add `#[allow(clippy::transmutes_expressible_as_ptr_casts)]` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:43:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:40:41 | LL | let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array_ref as *const [i32; 4]` + | + = note: `-D clippy::useless-transmute` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from `fn(usize) -> u8` to `*const usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:52:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:49:41 | LL | let _usize_ptr_transmute = unsafe { transmute:: u8, *const usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as *const usize` error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:57:49 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:54:49 | LL | let _usize_from_fn_ptr_transmute = unsafe { transmute:: u8, usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize` error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:61:36 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:58:36 | LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:73:14 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:70:14 | LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` error: transmute from `fn()` to `*const u8` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:92:28 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:89:28 | LL | let _x: u8 = unsafe { *std::mem::transmute::(f) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f as *const u8)` -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors -- cgit 1.4.1-3-g733a5 From e4557f0ea4f7e015b3108dc509bce562f64528bc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 23 Aug 2025 20:54:02 +0000 Subject: Use unnamed lifetime spans as primary spans for MISMATCHED_LIFETIME_SYNTAXES --- compiler/rustc_lint/src/lifetime_syntax.rs | 8 +- src/tools/clippy/tests/ui/ptr_arg.stderr | 4 +- .../type-dependent/issue-71348.full.stderr | 4 +- .../rpit-assoc-pair-with-lifetime.stderr | 4 +- .../example-from-issue48686.stderr | 4 +- .../missing-lifetime-kind.stderr | 16 +-- .../not-tied-to-crate.stderr | 8 +- .../static.stderr | 16 +-- tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs | 6 +- .../lifetimes/mismatched-lifetime-syntaxes.stderr | 153 ++++++++++----------- .../elision/ignore-non-reference-lifetimes.stderr | 8 +- tests/ui/self/self_lifetime-async.stderr | 8 +- tests/ui/self/self_lifetime.stderr | 8 +- 13 files changed, 122 insertions(+), 125 deletions(-) (limited to 'src') diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 464f4fc34b9..413525eb6e5 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -214,9 +214,9 @@ impl LifetimeSyntaxCategories> { } } - pub fn flatten(&self) -> impl Iterator { - let Self { hidden, elided, named } = self; - [hidden.iter(), elided.iter(), named.iter()].into_iter().flatten() + pub fn iter_unnamed(&self) -> impl Iterator { + let Self { hidden, elided, named: _ } = self; + [hidden.iter(), elided.iter()].into_iter().flatten() } } @@ -495,7 +495,7 @@ fn emit_mismatch_diagnostic<'tcx>( cx.emit_span_lint( MISMATCHED_LIFETIME_SYNTAXES, - inputs.flatten().copied().collect::>(), + inputs.iter_unnamed().chain(outputs.iter_unnamed()).copied().collect::>(), lints::MismatchedLifetimeSyntaxes { inputs, outputs, suggestions }, ); } diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 87235057349..f32e83d8b81 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -268,10 +268,10 @@ LL | fn barbar(_x: &mut Vec, y: &mut String) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: eliding a lifetime that's named elsewhere is confusing - --> tests/ui/ptr_arg.rs:314:36 + --> tests/ui/ptr_arg.rs:314:56 | LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - | ^^ ^^ ---- the same lifetime is elided here + | -- -- ^^^^ the same lifetime is elided here | | | | | the lifetime is named here | the lifetime is named here diff --git a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr index 32fa46b92b3..299ae680093 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr @@ -1,8 +1,8 @@ warning: hiding a lifetime that's named elsewhere is confusing - --> $DIR/issue-71348.rs:18:40 + --> $DIR/issue-71348.rs:18:56 | LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target - | ^^ -- ------------------------ the same lifetime is hidden here + | -- -- ^^^^^^^^^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | | | the same lifetime is named here | the lifetime is named here diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr index 3651226e0c3..7a9254bac60 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31 + --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:82 | LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator { - | ^^ the lifetime is named here ---- the same lifetime is elided here + | -- the lifetime is named here ^^^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr index 5a7a5a6ebf9..2b7d6a6da27 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/example-from-issue48686.rs:6:21 + --> $DIR/example-from-issue48686.rs:6:50 | LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - | ^^^^^^^ ------- the same lifetime is elided here + | ------- ^^^^^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr index af56a0a0ea5..c4d6e78d787 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:3:22 + --> $DIR/missing-lifetime-kind.rs:3:32 | LL | fn ampersand<'a>(x: &'a u8) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 { | ++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:10:21 + --> $DIR/missing-lifetime-kind.rs:10:31 | LL | fn brackets<'a>(x: &'a u8) -> Brackets { - | ^^ -------- the same lifetime is hidden here + | -- ^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -32,10 +32,10 @@ LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> { | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:17:18 + --> $DIR/missing-lifetime-kind.rs:17:28 | LL | fn comma<'a>(x: &'a u8) -> Comma { - | ^^ --------- the same lifetime is hidden here + | -- ^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -46,10 +46,10 @@ LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> { | +++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/missing-lifetime-kind.rs:22:23 + --> $DIR/missing-lifetime-kind.rs:22:34 | LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr index cf0a29678fa..28de809faab 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/not-tied-to-crate.rs:8:16 + --> $DIR/not-tied-to-crate.rs:8:31 | LL | fn bar(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn bar(x: &'static u8) -> &'static u8 { | +++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/not-tied-to-crate.rs:14:16 + --> $DIR/not-tied-to-crate.rs:14:31 | LL | fn baz(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr index d60bec6f7e4..5f21a2877a7 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:16:18 + --> $DIR/static.rs:16:33 | LL | fn ampersand(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn ampersand(x: &'static u8) -> &'static u8 { | +++++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:23:17 + --> $DIR/static.rs:23:32 | LL | fn brackets(x: &'static u8) -> Brackets { - | ^^^^^^^ -------- the same lifetime is hidden here + | ------- ^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -32,10 +32,10 @@ LL | fn brackets(x: &'static u8) -> Brackets<'static> { | +++++++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:30:14 + --> $DIR/static.rs:30:29 | LL | fn comma(x: &'static u8) -> Comma { - | ^^^^^^^ --------- the same lifetime is hidden here + | ------- ^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -46,10 +46,10 @@ LL | fn comma(x: &'static u8) -> Comma<'static, u8> { | ++++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/static.rs:35:19 + --> $DIR/static.rs:35:35 | LL | fn underscore(x: &'static u8) -> &'_ u8 { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs index f6260c47202..f404c4163a9 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs @@ -36,8 +36,8 @@ fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> Contains fn explicit_bound_path_to_explicit_anonymous_path<'a>( v: ContainsLifetime<'a>, - //~^ ERROR eliding a lifetime that's named elsewhere is confusing ) -> ContainsLifetime<'_> { + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } @@ -188,8 +188,8 @@ mod impl_trait { fn explicit_bound_path_to_impl_trait_precise_capture<'a>( v: ContainsLifetime<'a>, - //~^ ERROR eliding a lifetime that's named elsewhere is confusing ) -> impl FnOnce() + use<'_> { + //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } } @@ -208,8 +208,8 @@ mod dyn_trait { fn explicit_bound_path_to_dyn_trait_bound<'a>( v: ContainsLifetime<'a>, - //~^ ERROR hiding a lifetime that's named elsewhere is confusing ) -> Box + '_> { + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Box::new(iter::once(v)) } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr index 20b7561c594..89768fc764a 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr @@ -1,8 +1,8 @@ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:10:47 + --> $DIR/mismatched-lifetime-syntaxes.rs:10:57 | LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -18,10 +18,10 @@ LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 { | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:15:57 + --> $DIR/mismatched-lifetime-syntaxes.rs:15:68 | LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -36,7 +36,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:22:48 | LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { - | ^^^^^^^^^^^^^^^^ -- the same lifetime is elided here + | ^^^^^^^^^^^^^^^^ ^^ the same lifetime is elided here | | | the lifetime is hidden here | @@ -50,7 +50,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:27:65 | LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | ^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -61,10 +61,10 @@ LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> Con | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:32:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:32:73 | LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | -- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -75,13 +75,12 @@ LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> Con | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:38:25 + --> $DIR/mismatched-lifetime-syntaxes.rs:39:23 | LL | v: ContainsLifetime<'a>, - | ^^ the lifetime is named here -LL | + | -- the lifetime is named here LL | ) -> ContainsLifetime<'_> { - | -- the same lifetime is elided here + | ^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -94,7 +93,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:46:37 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -108,7 +107,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:51:48 | LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | ^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -119,10 +118,10 @@ LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime<' | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:56:48 + --> $DIR/mismatched-lifetime-syntaxes.rs:56:58 | LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | -- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -133,10 +132,10 @@ LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<' | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:61:58 + --> $DIR/mismatched-lifetime-syntaxes.rs:61:85 | LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -151,7 +150,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:68:37 | LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { - | ^^^^^^^^^^^^^^^^ --- the same lifetime is elided here + | ^^^^^^^^^^^^^^^^ ^^^ the same lifetime is elided here | | | the lifetime is hidden here | @@ -165,7 +164,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:73:47 | LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { - | ^^^^^^^^^^^^^^^^ -- the same lifetime is elided here + | ^^^^^^^^^^^^^^^^ ^^ the same lifetime is elided here | | | the lifetime is hidden here | @@ -176,10 +175,10 @@ LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:78:64 + --> $DIR/mismatched-lifetime-syntaxes.rs:78:72 | LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -190,10 +189,10 @@ LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:83:74 + --> $DIR/mismatched-lifetime-syntaxes.rs:83:83 | LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -205,10 +204,10 @@ LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:89:55 + --> $DIR/mismatched-lifetime-syntaxes.rs:89:67 | LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -219,10 +218,10 @@ LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 { | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:94:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:94:78 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -237,7 +236,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:101:56 | LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | ^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -248,10 +247,10 @@ LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> Contains | ++++ error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:106:56 + --> $DIR/mismatched-lifetime-syntaxes.rs:106:68 | LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { - | ^^ ---------------- the same lifetime is hidden here + | -- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -262,10 +261,10 @@ LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> Contains | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:111:66 + --> $DIR/mismatched-lifetime-syntaxes.rs:111:95 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -277,10 +276,10 @@ LL + fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) - | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:126:39 + --> $DIR/mismatched-lifetime-syntaxes.rs:126:54 | LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -291,10 +290,10 @@ LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 { | +++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:131:49 + --> $DIR/mismatched-lifetime-syntaxes.rs:131:65 | LL | fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -306,10 +305,10 @@ LL + fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 | error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:136:40 + --> $DIR/mismatched-lifetime-syntaxes.rs:136:55 | LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { - | ^^^^^^^ ---------------- the same lifetime is hidden here + | ------- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -320,10 +319,10 @@ LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'sta | +++++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:141:50 + --> $DIR/mismatched-lifetime-syntaxes.rs:141:82 | LL | fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -335,10 +334,10 @@ LL + fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLif | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:147:40 + --> $DIR/mismatched-lifetime-syntaxes.rs:147:57 | LL | fn static_ref_to_implicit_ref(&'static self) -> &u8 { - | ^^^^^^^ --- the same lifetime is elided here + | ------- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -349,10 +348,10 @@ LL | fn static_ref_to_implicit_ref(&'static self) -> &'static u8 { | +++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:152:50 + --> $DIR/mismatched-lifetime-syntaxes.rs:152:68 | LL | fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -364,10 +363,10 @@ LL + fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static | error: hiding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:157:41 + --> $DIR/mismatched-lifetime-syntaxes.rs:157:58 | LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { - | ^^^^^^^ ---------------- the same lifetime is hidden here + | ------- ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is named here | @@ -378,10 +377,10 @@ LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<' | +++++++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:162:51 + --> $DIR/mismatched-lifetime-syntaxes.rs:162:85 | LL | fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { - | ^^^^^^^ -- the same lifetime is elided here + | ------- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -393,10 +392,10 @@ LL + fn static_ref_to_explicit_anonymous_path(&'static self) -> Contains | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:174:55 + --> $DIR/mismatched-lifetime-syntaxes.rs:174:81 | LL | fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -408,10 +407,10 @@ LL + fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:179:65 + --> $DIR/mismatched-lifetime-syntaxes.rs:179:95 | LL | fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { - | ^^ the lifetime is named here -- the same lifetime is elided here + | -- the lifetime is named here ^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -421,10 +420,10 @@ LL + fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> i | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:184:72 + --> $DIR/mismatched-lifetime-syntaxes.rs:184:96 | LL | fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { - | ^^ -- the same lifetime is elided here + | -- ^^ the same lifetime is elided here | | | the lifetime is named here | @@ -436,13 +435,12 @@ LL + fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:190:29 + --> $DIR/mismatched-lifetime-syntaxes.rs:191:30 | LL | v: ContainsLifetime<'a>, - | ^^ the lifetime is named here -LL | + | -- the lifetime is named here LL | ) -> impl FnOnce() + use<'_> { - | -- the same lifetime is elided here + | ^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -452,10 +450,10 @@ LL + ) -> impl FnOnce() + use<'a> { | error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:204:54 + --> $DIR/mismatched-lifetime-syntaxes.rs:204:88 | LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box + '_> { - | ^^ the lifetime is named here --- the same lifetime is elided here + | -- the lifetime is named here ^^^ the same lifetime is elided here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -464,13 +462,12 @@ LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box $DIR/mismatched-lifetime-syntaxes.rs:210:29 + --> $DIR/mismatched-lifetime-syntaxes.rs:211:34 | LL | v: ContainsLifetime<'a>, - | ^^ the lifetime is named here -LL | + | -- the lifetime is named here LL | ) -> Box + '_> { - | ---------------- the same lifetime is hidden here + | ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | = help: the same lifetime is referred to in inconsistent ways, making the signature confusing help: consistently use `'a` @@ -479,10 +476,10 @@ LL | ) -> Box> + '_> { | ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:222:33 + --> $DIR/mismatched-lifetime-syntaxes.rs:222:52 | LL | fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 { - | ^^ ^^ --- the same lifetime is elided here + | -- -- ^^^ the same lifetime is elided here | | | | | the lifetime is named here | the lifetime is named here @@ -494,10 +491,10 @@ LL | fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &'a u8 { | ++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:227:33 + --> $DIR/mismatched-lifetime-syntaxes.rs:227:44 | LL | fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { - | ^^ --- --- the same lifetime is elided here + | -- ^^^ ^^^ the same lifetime is elided here | | | | | the same lifetime is elided here | the lifetime is named here @@ -509,10 +506,10 @@ LL | fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) { | ++ ++ error: hiding or eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:232:53 + --> $DIR/mismatched-lifetime-syntaxes.rs:232:62 | LL | fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) { - | ^^ --- ---------------- the same lifetime is hidden here + | -- ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | | | the same lifetime is elided here | the lifetime is named here @@ -524,10 +521,10 @@ LL | fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&'a u8, Contai | ++ ++++ error: eliding a lifetime that's named elsewhere is confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:237:38 + --> $DIR/mismatched-lifetime-syntaxes.rs:237:49 | LL | fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) { - | ^^ --- -- -- the same lifetime is named here + | -- ^^^ -- -- the same lifetime is named here | | | | | | | the same lifetime is named here | | the same lifetime is elided here @@ -543,7 +540,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:250:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -557,7 +554,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:253:49 | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime; - | ^^^^^ ---------------- the same lifetime is hidden here + | ^^^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -571,7 +568,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:258:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -585,7 +582,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:263:49 | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime { - | ^^^^^ ---------------- the same lifetime is hidden here + | ^^^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | @@ -599,7 +596,7 @@ error: hiding a lifetime that's elided elsewhere is confusing --> $DIR/mismatched-lifetime-syntaxes.rs:277:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - | ^^^ ---------------- the same lifetime is hidden here + | ^^^ ^^^^^^^^^^^^^^^^ the same lifetime is hidden here | | | the lifetime is elided here | diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr index 7108fa1a290..1a5c87114d4 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/ignore-non-reference-lifetimes.rs:6:30 + --> $DIR/ignore-non-reference-lifetimes.rs:6:41 | LL | fn a<'a>(self: Self, a: &'a str) -> &str { - | ^^ ---- the same lifetime is elided here + | -- ^^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -14,10 +14,10 @@ LL | fn a<'a>(self: Self, a: &'a str) -> &'a str { | ++ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/ignore-non-reference-lifetimes.rs:10:33 + --> $DIR/ignore-non-reference-lifetimes.rs:10:44 | LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - | ^^ ---- the same lifetime is elided here + | -- ^^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr index 43dc96abdc2..78cc610fd04 100644 --- a/tests/ui/self/self_lifetime-async.stderr +++ b/tests/ui/self/self_lifetime-async.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime-async.rs:6:29 + --> $DIR/self_lifetime-async.rs:6:44 | LL | async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -14,10 +14,10 @@ LL | async fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } | ++ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime-async.rs:12:42 + --> $DIR/self_lifetime-async.rs:12:52 | LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr index 4f9b2fcd2ad..84f63454633 100644 --- a/tests/ui/self/self_lifetime.stderr +++ b/tests/ui/self/self_lifetime.stderr @@ -1,8 +1,8 @@ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime.rs:7:23 + --> $DIR/self_lifetime.rs:7:38 | LL | fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | @@ -14,10 +14,10 @@ LL | fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } | ++ warning: eliding a lifetime that's named elsewhere is confusing - --> $DIR/self_lifetime.rs:13:36 + --> $DIR/self_lifetime.rs:13:46 | LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | ^^ --- the same lifetime is elided here + | -- ^^^ the same lifetime is elided here | | | the lifetime is named here | -- cgit 1.4.1-3-g733a5 From b8313dfb04a12b45483f2a8a7527d8ba1c63ae03 Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Sat, 23 Aug 2025 11:05:05 +0200 Subject: rustdoc: render attributes in Field and Variants sections --- src/librustdoc/html/render/print_item.rs | 24 +++++++++++++++++++++--- src/librustdoc/html/templates/item_union.html | 2 +- tests/rustdoc/attributes.rs | 4 ++++ 3 files changed, 26 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 2618ec272ca..b86a2c94697 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1460,6 +1460,13 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { ) } + fn print_field_attrs(&self, field: &'a clean::Item) -> impl Display { + fmt::from_fn(move |w| { + render_attributes_in_code(w, field, "", self.cx); + Ok(()) + }) + } + fn document_field(&self, field: &'a clean::Item) -> impl Display { document(self.cx, field, Some(self.it), HeadingOffset::H3) } @@ -1770,6 +1777,7 @@ fn item_variants( ) .maybe_display() )?; + render_attributes_in_code(w, variant, "", cx); if let clean::VariantItem(ref var) = variant.kind && let clean::VariantKind::CLike = var.kind { @@ -1843,7 +1851,12 @@ fn item_variants( "
\ \ §\ - {f}: {t}\ + " + )?; + render_attributes_in_code(w, field, "", cx); + write!( + w, + "{f}: {t}\ \ {doc}\
", @@ -2079,10 +2092,15 @@ fn item_fields( w, "\ §\ - {field_name}: {ty}\ + ", + item_type = ItemType::StructField, + )?; + render_attributes_in_code(w, field, "", cx); + write!( + w, + "{field_name}: {ty}\ \ {doc}", - item_type = ItemType::StructField, ty = ty.print(cx), doc = document(cx, field, Some(it), HeadingOffset::H3), )?; diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html index 5dba43ca255..171e079ed13 100644 --- a/src/librustdoc/html/templates/item_union.html +++ b/src/librustdoc/html/templates/item_union.html @@ -12,7 +12,7 @@ {% let name = field.name.expect("union field name") %} {# #} § {# #} - {{ name }}: {{+ self.print_ty(ty)|safe }} {# #} + {{+ self.print_field_attrs(field)|safe }}{{ name }}: {{+ self.print_ty(ty)|safe }} {# #} {% if let Some(stability_class) = self.stability_field(field) %} diff --git a/tests/rustdoc/attributes.rs b/tests/rustdoc/attributes.rs index db5f89ed46e..33e4e31bec6 100644 --- a/tests/rustdoc/attributes.rs +++ b/tests/rustdoc/attributes.rs @@ -28,12 +28,15 @@ macro_rules! macro_rule { #[unsafe(link_section = "enum")] pub enum Enum { //@ has 'foo/enum.Enum.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "a")]' + //@ has - '//*[@class="variants"]//*[@class="code-attribute"]' '#[unsafe(link_section = "a")]' #[unsafe(link_section = "a")] A, //@ has 'foo/enum.Enum.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "quz")]' + //@ has - '//*[@class="variants"]//*[@class="code-attribute"]' '#[unsafe(link_section = "quz")]' #[unsafe(link_section = "quz")] Quz { //@ has 'foo/enum.Enum.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "b")]' + //@ has - '//*[@class="variants"]//*[@class="code-attribute"]' '#[unsafe(link_section = "b")]' #[unsafe(link_section = "b")] b: (), }, @@ -66,6 +69,7 @@ pub union Union { #[unsafe(link_section = "struct")] pub struct Struct { //@ has 'foo/struct.Struct.html' '//*[@class="code-attribute"]' '#[unsafe(link_section = "x")]' + //@ has - '//*[@id="structfield.x"]//*[@class="code-attribute"]' '#[unsafe(link_section = "x")]' #[unsafe(link_section = "x")] pub x: u32, y: f32, -- cgit 1.4.1-3-g733a5