From 76323c8c596877d72ab3727aac13708dceb29ca7 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Fri, 17 Apr 2026 11:07:32 +0200 Subject: [PATCH 01/98] [draft] Link to proposed LLM policy --- src/doc/rustc-dev-guide/src/about-this-guide.md | 3 ++- src/doc/rustc-dev-guide/src/contributing.md | 6 ++++++ src/doc/rustc-dev-guide/src/getting-started.md | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) 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 4dc453a2042de..57f6e676866d8 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -72,6 +72,7 @@ You might also find the following sites useful: - [rustc API docs] -- rustdoc documentation for the compiler, devtools, and internal tools - [Forge] -- contains documentation about Rust infrastructure, team procedures, and more +- `rust-lang/rust`'s [LLM policy] - [compiler-team] -- the home-base for the Rust compiler team, with description of the team procedures, active working groups, and the team calendar. - [std-dev-guide] -- a similar guide for developing the standard library. @@ -93,7 +94,7 @@ You might also find the following sites useful: For example, searching for `* -> vec` should find all functions that return a `Vec`. _Hint:_ Find more tips and keyboard shortcuts by typing `?` on any Rustdoc page! - +[LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html [rustc dev guide]: about-this-guide.md [gsearchdocs]: https://www.google.com/search?q=site:doc.rust-lang.org+your+query+here [stddocs]: https://doc.rust-lang.org/std diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 7f4779515b13c..05685d9f2fa58 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -517,6 +517,12 @@ This is used for [RFCs], issues, and pull requests. [rfcbot]: https://github.com/anp/rfcbot-rs/ [RFCs]: https://github.com/rust-lang/rfcs +## LLM policy + +See [Forge][LLM policy]. + +[LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html + ## Helpful links and information This section has moved to the ["About this guide"] chapter. diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index a5da912aa4c4d..12167347d44ef 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -48,6 +48,8 @@ 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. +See also [our LLM policy](https://forge.rust-lang.org/policies/llm-usage.html). + ### Experts Not all `t-compiler` members are experts on all parts of `rustc`; From f32e5d87873a76facca83f917091b6971f90cabd Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 23 May 2026 06:41:40 +0200 Subject: [PATCH 02/98] add guidance for working with LLMs --- src/doc/rustc-dev-guide/src/SUMMARY.md | 1 + src/doc/rustc-dev-guide/src/llm-guidance.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/doc/rustc-dev-guide/src/llm-guidance.md diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 9a9861186011d..29a259130d395 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -50,6 +50,7 @@ - [About the compiler team](./compiler-team.md) - [Using Git](./git.md) - [Mastering @rustbot](./rustbot.md) +- [Running LLMs](./llm-guidance.md) - [Walkthrough: a typical contribution](./walkthrough.md) - [Implementing new language features](./implementing-new-features.md) - [Stability guarantees](./stability-guarantees.md) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance.md new file mode 100644 index 0000000000000..1e668d1624174 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/llm-guidance.md @@ -0,0 +1,15 @@ +# Running LLMs + +This is a non-binding list of suggestions for working with LLMs. +This is not our moderation policy; see [Forge][LLM policy]. + +## Review bots + +- If a more reliable tool, such as a linter or formatter, already exists for the language you're writing, we strongly suggest using that tool instead of or in addition to the LLM. +- Configure LLM review tools to reduce false positives and excessive focus on trivialities, as these are common, exhausting failure modes. + +## LLM-authored code + +- We recommend, but do not require, using a second LLM for adversarial local review before publishing your changes. + +[LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html From e07d7cc69fd3fd7bf6c62f20f4f85c51f8fe97da Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 6 Jun 2026 13:16:48 +0200 Subject: [PATCH 03/98] Suggest using an LLM to generate tools, rather than making the LLM the tool --- src/doc/rustc-dev-guide/src/llm-guidance.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance.md index 1e668d1624174..b93b3c6d52ec5 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance.md @@ -7,9 +7,13 @@ This is not our moderation policy; see [Forge][LLM policy]. - If a more reliable tool, such as a linter or formatter, already exists for the language you're writing, we strongly suggest using that tool instead of or in addition to the LLM. - Configure LLM review tools to reduce false positives and excessive focus on trivialities, as these are common, exhausting failure modes. +- Wherever possible, ask an LLM to *generate a linter*, which you then tell it to run. + This both saves on token costs, and allows people who are not using an LLM to run the analysis. ## LLM-authored code - We recommend, but do not require, using a second LLM for adversarial local review before publishing your changes. +- Mass renames or rewrites should *strongly* prefer using a proper syntax rewrite tool, such as [`ast-grep`]. + You may use an LLM for generating the instructions for that tool, but you should be very cautious about performing the rewrite directly with an LLM. [LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html From baf98d4b9ed078def5c58b4dd1dd098daa357e67 Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 11 Jun 2026 17:58:39 +0200 Subject: [PATCH 04/98] add note that LLMs prefer their own output --- src/doc/rustc-dev-guide/src/llm-guidance.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance.md index b93b3c6d52ec5..d76f819fb9f30 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance.md @@ -9,6 +9,7 @@ This is not our moderation policy; see [Forge][LLM policy]. - Configure LLM review tools to reduce false positives and excessive focus on trivialities, as these are common, exhausting failure modes. - Wherever possible, ask an LLM to *generate a linter*, which you then tell it to run. This both saves on token costs, and allows people who are not using an LLM to run the analysis. +- Note that LLMs sometimes demonstrate a preference for LLM output, particularly output from the same model. ## LLM-authored code From 32c4dcb73668043e42ffcb9fcd55b7c716ed5282 Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 18 Jun 2026 02:01:10 +0200 Subject: [PATCH 05/98] extend llm guidance --- src/doc/rustc-dev-guide/src/llm-guidance.md | 52 ++++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance.md index d76f819fb9f30..bbb12bd0e37f1 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance.md @@ -1,20 +1,60 @@ -# Running LLMs +# Working with LLMs This is a non-binding list of suggestions for working with LLMs. This is not our moderation policy; see [Forge][LLM policy]. -## Review bots +[LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html + +## Automated checks and LLM review - If a more reliable tool, such as a linter or formatter, already exists for the language you're writing, we strongly suggest using that tool instead of or in addition to the LLM. - Configure LLM review tools to reduce false positives and excessive focus on trivialities, as these are common, exhausting failure modes. - Wherever possible, ask an LLM to *generate a linter*, which you then tell it to run. This both saves on token costs, and allows people who are not using an LLM to run the analysis. -- Note that LLMs sometimes demonstrate a preference for LLM output, particularly output from the same model. +- LLMs sometimes prefer LLM-generated output, particularly output from the same + model. Treat LLM review as advisory, and do not rely on the model that + produced a change as its only reviewer. -## LLM-authored code +## Writing LLM-created code -- We recommend, but do not require, using a second LLM for adversarial local review before publishing your changes. +- We recommend, but do not require, using a different model for adversarial + local review before publishing your changes. This does not replace human + self-review. - Mass renames or rewrites should *strongly* prefer using a proper syntax rewrite tool, such as [`ast-grep`]. You may use an LLM for generating the instructions for that tool, but you should be very cautious about performing the rewrite directly with an LLM. -[LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html +[`ast-grep`]: https://astgrep.com/ + +## Reviewing LLM-created code + +Point people to [#llm-mentoring](https://rust-lang.zulipchat.com/#narrow/channel/606558-llm-mentoring/) liberally. +Deal with low-quality PRs by closing the PR and asking the author to follow the "solicited" rule in the Forge policy. +Deal with borderline PRs by asking the author to do work that shows they're paying attention; it's ok to ask for that work before you've put much time into review yourself. +For example, ask them to reproduce the bug, explain the change in their own +words, identify relevant edge cases, or add or justify tests. + +If you find yourself suggesting the same fixes on multiple PRs, +consider adding them to the dev-guide. + +## Disclosure guidelines + +Disclose the *extent* and *purpose* of your LLM use. +We don't care which model you used, but we do care whether you used the LLM to +implement the idea or to come up with it. +Write the disclosure yourself. You may use an LLM to privately review a +disclosure you have written, but not to draft or rewrite it. + +**Good** examples: + +> LLM disclosure: I wrote the three commits by hand after viewing profiling data. I used an LLM to review the commits before submitting. The LLM identified that ImplString::is_negative was no longer used, so I removed that field by hand. + +> Created with the help of Claude Code, which: +> - traced the missing cache hits to the unconditional return(pass) by inspecting Fastly vs CloudFront headers, +> - reviewed the git history to understand why the snippet was added, and +> - made the VCL change. + +**Bad** examples: + +> 🤖 Generated with Claude Code + +> Co-Authored-By: Claude Opus 4.6 (1M context) From 2685feceadb5712acd93184038dbbe60a3b038d4 Mon Sep 17 00:00:00 2001 From: jyn Date: Tue, 28 Jul 2026 13:54:01 +0200 Subject: [PATCH 06/98] extend LLM guidance with a summary of the policy --- src/doc/rustc-dev-guide/src/llm-guidance.md | 135 ++++++++++++++++---- 1 file changed, 109 insertions(+), 26 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance.md index bbb12bd0e37f1..5426f6f8944d1 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance.md @@ -1,10 +1,70 @@ # Working with LLMs -This is a non-binding list of suggestions for working with LLMs. -This is not our moderation policy; see [Forge][LLM policy]. +This is a list of guidelines for working with LLMs, as well as a summary of the moderation policy. +This is not the policy itself; see [Forge][LLM policy]. +If the two conflict, Forge is canonical. [LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html +## Writing LLM-created code + +### Rules + +Before anything else, you **must** find a reviewer who volunteers to review your PR. +LLM PRs without an assigned reviewer will be closed. + +Disclose your use of LLMs, following the disclosure guidelines below. +Write the disclosure yourself. +You may use an LLM to privately review a disclosure you have written, but not to draft or rewrite it. + +You may *not* use an LLM to write doc-comments, `// SAFETY` comments, diagnostics, or soundness-critical code. +If you don't know what counts as soundness-critical, discuss it with your reviewer. + +**Write your own PR description and comments**. +LLM-created PR descriptions are banned. +LLM-created Github comments are banned. +We want to hear from you, not from your agent. + +### Guidelines + +Start with one PR at a time. +We understand it's easy to be excited about contributing to Rust, but your PRs are not only a gift but a responsibility for the reviewers. +Go slow. + +Avoid E-easy and E-mentor issues. +Those are intended for people to get familiar with the project, not for LLMs. + +Mass renames or rewrites should *strongly* prefer using a proper syntax rewrite tool, such as [`ast-grep`]. +You may use an LLM for generating the instructions for that tool, but you should be very cautious about performing the rewrite directly with an LLM. + +Read the documentation. Strive for quality. Review your own PR before opening it: +Does it make sense? Can you tell what the goal of the PR is? Does it achieve that goal? + +We recommend using a different model for adversarial local review before publishing your changes. +This does not replace human self-review. + +[`ast-grep`]: https://astgrep.com/ + +#### Disclosure guidelines + +Disclose the *extent* and *purpose* of your LLM use. +We don't care which model you used, but we do care whether you used the LLM to implement the idea or to come up with it. + +**Good** examples: + +> LLM disclosure: I wrote the three commits by hand after viewing profiling data. I used an LLM to review the commits before submitting. The LLM identified that `ImplString::is_negative` was no longer used, so I removed that field by hand. + +> Created with the help of Claude Code, which: +> - traced the missing cache hits to the unconditional `return(pass)` by inspecting Fastly vs CloudFront headers, +> - reviewed the git history to understand why the snippet was added, and +> - made the VCL change. + +**Bad** examples: + +> 🤖 Generated with Claude Code + +> Co-Authored-By: Claude Opus 4.6 (1M context) + ## Automated checks and LLM review - If a more reliable tool, such as a linter or formatter, already exists for the language you're writing, we strongly suggest using that tool instead of or in addition to the LLM. @@ -15,20 +75,25 @@ This is not our moderation policy; see [Forge][LLM policy]. model. Treat LLM review as advisory, and do not rely on the model that produced a change as its only reviewer. -## Writing LLM-created code +## Reviewing LLM-created code -- We recommend, but do not require, using a different model for adversarial - local review before publishing your changes. This does not replace human - self-review. -- Mass renames or rewrites should *strongly* prefer using a proper syntax rewrite tool, such as [`ast-grep`]. - You may use an LLM for generating the instructions for that tool, but you should be very cautious about performing the rewrite directly with an LLM. +First, add the new `ai-assisted` label to the PR. -[`ast-grep`]: https://astgrep.com/ +### Rules -## Reviewing LLM-created code +We expect everyone to follow the new policy, not just authors. +That means it is **your responsibility** to check whether an `ai-assisted` PR touches an area that's disallowed by the policy. +You may request that the author redo it without LLM-generated code, in which case this section doesn't apply. + +The following areas are currently banned: +- Code that affects soundness. If the author is not obviously experienced in the domain, you are required to close the PR. +- Diagnostics. All user-facing diagnostics must be human-written. +- Docs. All public doc-comments, and all `SAFETY` comments, must be human-written. + +### Guidelines Point people to [#llm-mentoring](https://rust-lang.zulipchat.com/#narrow/channel/606558-llm-mentoring/) liberally. -Deal with low-quality PRs by closing the PR and asking the author to follow the "solicited" rule in the Forge policy. +Deal with low-quality PRs by closing the PR and asking the author to follow the policy. Deal with borderline PRs by asking the author to do work that shows they're paying attention; it's ok to ask for that work before you've put much time into review yourself. For example, ask them to reproduce the bug, explain the change in their own words, identify relevant edge cases, or add or justify tests. @@ -36,25 +101,43 @@ words, identify relevant edge cases, or add or justify tests. If you find yourself suggesting the same fixes on multiple PRs, consider adding them to the dev-guide. -## Disclosure guidelines +#### Missing disclosure -Disclose the *extent* and *purpose* of your LLM use. -We don't care which model you used, but we do care whether you used the LLM to -implement the idea or to come up with it. -Write the disclosure yourself. You may use an LLM to privately review a -disclosure you have written, but not to draft or rewrite it. +If you see a PR that is "obviously" LLM-created without disclosing that use, you have the option—but not the responsibility—to close it unilaterally. -**Good** examples: +We suggest using the following wording: -> LLM disclosure: I wrote the three commits by hand after viewing profiling data. I used an LLM to review the commits before submitting. The LLM identified that ImplString::is_negative was no longer used, so I removed that field by hand. +> This PR appears to be LLM-generated without disclosing use of an LLM, +> so I am going to close this PR. +> You are welcome to open additional PRs as long as they follow our [policy][forge-page]. +> For more information, see [#llm-mentoring] on Zulip. -> Created with the help of Claude Code, which: -> - traced the missing cache hits to the unconditional return(pass) by inspecting Fastly vs CloudFront headers, -> - reviewed the git history to understand why the snippet was added, and -> - made the VCL change. +Examples of "obvious" LLM tells are: +- PR descriptions that are completely wrong/don't match the code. +- PR descriptions that state the exact tests that were run (e.g. `./x test --stage 1 tests/ui/.rs`) or useless tests such as `git diff --check`. +- Responses to reviewer questions that fall into one of the above categories. -**Bad** examples: +You do not have an obligation to detect LLM-created PRs; +you don't need to play detective. -> 🤖 Generated with Claude Code +PR templates will have a "Did you use an LLM?" question so that this rarely comes up. +If the author deleted the question without answering it, you can close the PR, no questions asked. -> Co-Authored-By: Claude Opus 4.6 (1M context) +#### Missing solicited reviewer + +If the PR discloses use, but does not assign a reviewer following the [experiment guidelines], you can close it similarly: + +> You've opened an LLM-generated PR, but it's in the normal review queue, which breaks our [policy][experiment guidelines]. +> I am going to close this PR. +> Please do not re-open it until you find a project member who has volunteered to review it. +> For more information, see [#llm-mentoring] on Zulip. + +#### Missing tests, low-quality, or not self-reviewed + +If a PR is clearly not ready for review, you do not have to review it. +It's ok to simply skim the PR and tell the author "you need to add tests before I can review this". +If you notice on your skim that the PR is clearly the wrong approach, it's ok to close the PR and tell the author to talk with you in the [#llm-mentoring] channel before opening a new PR. + +[experiment guidelines]: https://forge.rust-lang.org/policies/llm-usage.html#experiment-llm-created-code-changes-intended-for-review +[#llm-mentoring]: https://rust-lang.zulipchat.com/join/rlfvpemsaacs3pfi6kwqnqjb/ +[forge-page]: https://forge.rust-lang.org/policies/llm-usage.html From 7da7cd027e177b488f06328a493a4e518e4909ac Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 09:04:02 +0200 Subject: [PATCH 07/98] flesh out author guidance --- src/doc/rustc-dev-guide/src/llm-guidance.md | 27 ++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance.md index 5426f6f8944d1..aff7197463634 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance.md @@ -11,7 +11,8 @@ If the two conflict, Forge is canonical. ### Rules Before anything else, you **must** find a reviewer who volunteers to review your PR. -LLM PRs without an assigned reviewer will be closed. +LLM-created PRs without an assigned reviewer will be closed. +If you do not know where to find a reviewer, see [#llm-mentoring] on Zulip. Disclose your use of LLMs, following the disclosure guidelines below. Write the disclosure yourself. @@ -27,6 +28,8 @@ We want to hear from you, not from your agent. ### Guidelines +#### Before you write code + Start with one PR at a time. We understand it's easy to be excited about contributing to Rust, but your PRs are not only a gift but a responsibility for the reviewers. Go slow. @@ -34,15 +37,33 @@ Go slow. Avoid E-easy and E-mentor issues. Those are intended for people to get familiar with the project, not for LLMs. +#### While working + +When fixing a bug, reproduce the bug *before* fixing it. +Write a test that fails, fix the bug, then verify the test now succeeds. +Otherwise, you don't know that you were testing the right thing. + Mass renames or rewrites should *strongly* prefer using a proper syntax rewrite tool, such as [`ast-grep`]. You may use an LLM for generating the instructions for that tool, but you should be very cautious about performing the rewrite directly with an LLM. -Read the documentation. Strive for quality. Review your own PR before opening it: +#### Before opening a PR + +Review your own PR before opening it: Does it make sense? Can you tell what the goal of the PR is? Does it achieve that goal? +Run tests to verify your change works. +Do NOT report which tests you ran in the PR description; +that's useless to us, since CI will run them anyway. + +You must review diagnostic snapshots; don't simply `--bless` them away. + We recommend using a different model for adversarial local review before publishing your changes. This does not replace human self-review. +You must understand and be able to explain your own change and its edge cases. +Asking the LLM can be a starting point but is not sufficient. +You are responsible for your own code; you cannot disclaim responsibility to your agent. + [`ast-grep`]: https://astgrep.com/ #### Disclosure guidelines @@ -92,7 +113,7 @@ The following areas are currently banned: ### Guidelines -Point people to [#llm-mentoring](https://rust-lang.zulipchat.com/#narrow/channel/606558-llm-mentoring/) liberally. +Point people to [#llm-mentoring] liberally. Deal with low-quality PRs by closing the PR and asking the author to follow the policy. Deal with borderline PRs by asking the author to do work that shows they're paying attention; it's ok to ask for that work before you've put much time into review yourself. For example, ask them to reproduce the bug, explain the change in their own From 500f94c222e814442984ef9271d0194dcd22314b Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 09:04:10 +0200 Subject: [PATCH 08/98] more author guidance; cross-references --- src/doc/rustc-dev-guide/src/llm-guidance.md | 37 +++++++++++++++---- .../src/tests/best-practices.md | 2 +- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance.md index aff7197463634..183e81c10f50b 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance.md @@ -18,7 +18,8 @@ Disclose your use of LLMs, following the disclosure guidelines below. Write the disclosure yourself. You may use an LLM to privately review a disclosure you have written, but not to draft or rewrite it. -You may *not* use an LLM to write doc-comments, `// SAFETY` comments, diagnostics, or soundness-critical code. +You may *not* use an LLM to write doc-comments, `// SAFETY` comments, diagnostic wording, or soundness-critical code. +Write them yourself instead. If you don't know what counts as soundness-critical, discuss it with your reviewer. **Write your own PR description and comments**. @@ -37,11 +38,21 @@ Go slow. Avoid E-easy and E-mentor issues. Those are intended for people to get familiar with the project, not for LLMs. +Determine whether this is a *useful* and *well-scoped* change. +For example: + +- Search for related issues and PRs. +- Find relevant code, tests, git history, and Zulip discussion. +- If this is a cross-cutting change, consult the "cross-cutting" section of [the contributing docs](./contributing.md#pull-requests). +- Make the smallest change that fixes the problem. + Do not combine it with unrelated refactors or cleanups. + #### While working -When fixing a bug, reproduce the bug *before* fixing it. -Write a test that fails, fix the bug, then verify the test now succeeds. -Otherwise, you don't know that you were testing the right thing. +When fixing a bug, verify that your test fails before and succeeds after your change. +Consult [adding new tests](./tests/adding.md) and [best practices](./tests/best-practices.md) for test procedures. +Tests are absolutely required; either existing tests or new tests you write. +Untested LLM PRs will not be merged. Mass renames or rewrites should *strongly* prefer using a proper syntax rewrite tool, such as [`ast-grep`]. You may use an LLM for generating the instructions for that tool, but you should be very cautious about performing the rewrite directly with an LLM. @@ -51,19 +62,31 @@ You may use an LLM for generating the instructions for that tool, but you should Review your own PR before opening it: Does it make sense? Can you tell what the goal of the PR is? Does it achieve that goal? -Run tests to verify your change works. +[Run tests](tests/running.md) to verify your change works. Do NOT report which tests you ran in the PR description; that's useless to us, since CI will run them anyway. -You must review diagnostic snapshots; don't simply `--bless` them away. +You must [review diagnostic snapshots](tests/adding.md#step-4-review-the-output); +don't simply `--bless` them away. We recommend using a different model for adversarial local review before publishing your changes. This does not replace human self-review. +#### Understand your own change + You must understand and be able to explain your own change and its edge cases. Asking the LLM can be a starting point but is not sufficient. You are responsible for your own code; you cannot disclaim responsibility to your agent. +Some questions that you should be able to answer: + +- What is the original bug? When does it happen? How severe is it? What causes it? +- Why is this the right fix? Are there other fixes possible? What are their advantages or disadvantages? +- Are there any edge cases? Does your code handle them? +- What behavior is *unchanged*? What test establishes that? +- Why does your test trigger the bug? +- What are you still not certain about? + [`ast-grep`]: https://astgrep.com/ #### Disclosure guidelines @@ -107,7 +130,7 @@ That means it is **your responsibility** to check whether an `ai-assisted` PR to You may request that the author redo it without LLM-generated code, in which case this section doesn't apply. The following areas are currently banned: -- Code that affects soundness. If the author is not obviously experienced in the domain, you are required to close the PR. +- Code that affects soundness. If the author is not an org member who is experienced in the domain, you are required to close the PR. - Diagnostics. All user-facing diagnostics must be human-written. - Docs. All public doc-comments, and all `SAFETY` comments, must be human-written. diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md index b6daffa6683c0..4e6f40c4b78e6 100644 --- a/src/doc/rustc-dev-guide/src/tests/best-practices.md +++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md @@ -140,7 +140,7 @@ A good rule of thumb is non-trivial things exercised in the test deserves some explanation to help other contributors to understand. This may include remarks on: -- How an ICE can get triggered if it's quite elaborate. +- How an ICE or bug can get triggered if it's quite elaborate. - Related issues and tests (e.g. this test is like another test but is kept separate because...). - Platform-specific behaviors. From ac6af3961c651b0c0bb81c889ec2203d04caae67 Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 10:30:18 +0200 Subject: [PATCH 09/98] change tone from policy to mentorship --- src/doc/rustc-dev-guide/src/llm-guidance.md | 56 ++++++++++++++------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance.md index 183e81c10f50b..175b3d1e3848c 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance.md @@ -8,18 +8,35 @@ If the two conflict, Forge is canonical. ## Writing LLM-created code +LLMs are a valuable tool, but one that is easy to misuse. +The main risks are **overwhelming volume** and **lack of understanding**. +When writing your PR, keep in mind that there is a person on the other end who needs to review and understand your change. +Help us out by making your change small, targeted, and easy to review. + +Keep in mind this quote: + +> Programs must be written for people to read, and only incidentally for machines to execute. +> — Harold Abelson and Gerald Jay Sussman, [*Structure and Interpretation of Computer Programs*][sicp] + +[sicp]: https://web.mit.edu/6.001/6.037/sicp.pdf + ### Rules -Before anything else, you **must** find a reviewer who volunteers to review your PR. -LLM-created PRs without an assigned reviewer will be closed. -If you do not know where to find a reviewer, see [#llm-mentoring] on Zulip. +Before anything else, find a reviewer who volunteers to review your PR. +If you do not know where to find a reviewer, ask in [#llm-mentoring] on Zulip. +Your first message should say: + +- your relevant experience, so we can find an issue that's suitable for you +- which problem (or kind of problem) you want to work on +- (optional) ideas you have so far for a solution +- (optional) how you expect to test your solution Disclose your use of LLMs, following the disclosure guidelines below. Write the disclosure yourself. You may use an LLM to privately review a disclosure you have written, but not to draft or rewrite it. -You may *not* use an LLM to write doc-comments, `// SAFETY` comments, diagnostic wording, or soundness-critical code. -Write them yourself instead. +Write your own doc-comments, `// SAFETY` comments, diagnostic wording, and soundness-critical code. +As before, you can use an LLM to review your work, but not to write it from scratch. If you don't know what counts as soundness-critical, discuss it with your reviewer. **Write your own PR description and comments**. @@ -32,11 +49,11 @@ We want to hear from you, not from your agent. #### Before you write code Start with one PR at a time. -We understand it's easy to be excited about contributing to Rust, but your PRs are not only a gift but a responsibility for the reviewers. +Your PRs are not only a gift but a responsibility for reviewers. Go slow. -Avoid E-easy and E-mentor issues. -Those are intended for people to get familiar with the project, not for LLMs. +Do not use an LLM for `E-easy` issues; those are meant for you to write the code yourself. +Ask first before working on an `E-mentor` issue; mentors may not want to work with LLM-generated code. Determine whether this is a *useful* and *well-scoped* change. For example: @@ -63,22 +80,24 @@ Review your own PR before opening it: Does it make sense? Can you tell what the goal of the PR is? Does it achieve that goal? [Run tests](tests/running.md) to verify your change works. -Do NOT report which tests you ran in the PR description; -that's useless to us, since CI will run them anyway. +Do NOT report which UI tests you ran in the PR description; +that's noise, since CI will run them anyway. +If you did manual testing or benchmarking, do report that, +but note that all LLM PRs must have automated tests. -You must [review diagnostic snapshots](tests/adding.md#step-4-review-the-output); +[Review diagnostic snapshots](tests/adding.md#step-4-review-the-output); don't simply `--bless` them away. We recommend using a different model for adversarial local review before publishing your changes. -This does not replace human self-review. +You're still responsible for reviewing your own changes yourself. #### Understand your own change -You must understand and be able to explain your own change and its edge cases. -Asking the LLM can be a starting point but is not sufficient. -You are responsible for your own code; you cannot disclaim responsibility to your agent. +We want you to understand and be able to explain your own change and its edge cases. +Asking the LLM can be a starting point but it's not the same as explaining it yourself. -Some questions that you should be able to answer: +Try explaining your change to yourself before opening the PR. +For example, ask yourself: - What is the original bug? When does it happen? How severe is it? What causes it? - Why is this the right fix? Are there other fixes possible? What are their advantages or disadvantages? @@ -87,6 +106,9 @@ Some questions that you should be able to answer: - Why does your test trigger the bug? - What are you still not certain about? +It's ok to be uncertain and to ask for help. +We would much rather help you because you're not sure than have you guess wrong and then have to reverse-engineer where you went wrong. + [`ast-grep`]: https://astgrep.com/ #### Disclosure guidelines @@ -138,7 +160,7 @@ The following areas are currently banned: Point people to [#llm-mentoring] liberally. Deal with low-quality PRs by closing the PR and asking the author to follow the policy. -Deal with borderline PRs by asking the author to do work that shows they're paying attention; it's ok to ask for that work before you've put much time into review yourself. +Deal with borderline PRs by asking the author to put in the work themselves rather than offloading it to you. For example, ask them to reproduce the bug, explain the change in their own words, identify relevant edge cases, or add or justify tests. From ef9670cfc89d846eeb98eed61fa38948606dad0b Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 11:44:43 +0200 Subject: [PATCH 10/98] add "maintainable code" section --- src/doc/rustc-dev-guide/src/llm-guidance.md | 43 +++++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance.md index 175b3d1e3848c..d186df8779436 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance.md @@ -10,8 +10,9 @@ If the two conflict, Forge is canonical. LLMs are a valuable tool, but one that is easy to misuse. The main risks are **overwhelming volume** and **lack of understanding**. -When writing your PR, keep in mind that there is a person on the other end who needs to review and understand your change. -Help us out by making your change small, targeted, and easy to review. +When writing your PR, keep in mind that there is a person on the other end who needs to review and understand your change, +and that other people in the project will need to read your code for years to come. +Help us out by making your change small, targeted, and high-quality. Keep in mind this quote: @@ -49,7 +50,7 @@ We want to hear from you, not from your agent. #### Before you write code Start with one PR at a time. -Your PRs are not only a gift but a responsibility for reviewers. +Keep your changes small enough that you and your reviewer can understand every part of them. Go slow. Do not use an LLM for `E-easy` issues; those are meant for you to write the code yourself. @@ -74,11 +75,45 @@ Untested LLM PRs will not be merged. Mass renames or rewrites should *strongly* prefer using a proper syntax rewrite tool, such as [`ast-grep`]. You may use an LLM for generating the instructions for that tool, but you should be very cautious about performing the rewrite directly with an LLM. +Work in small steps. +Run tests after every meaningful change, so you know where you first went wrong. +Do not write all your code at once; that will make it very hard to know what broke. +Ideally, commit your changes in [small atomic commits] as you go. + +Verify your understanding against the existing code, documentation, and tests. +You can get better advice from your LLM by telling *it* to read the relevant materials. +Do not rely on the LLM as a source of truth. + +[small atomic commits](https://github.blog/developer-skills/github/write-better-commits-build-better-projects/#%e2%9a%9b%ef%b8%8f-resize-and-stabilize-the-commits) + +#### Write maintainable code + +Treat generated code as a *draft*, not a final product. + +Follow the style of surrounding code. +Use existing helpers and avoid duplicating logic or validation. + +Represent data in [one normalized place](https://react.dev/learn/choosing-the-state-structure); +trying to keep data in sync between two different places is a code smell. + +When practical, [make invalid states unrepresentable](https://kentcdodds.com/blog/make-impossible-states-impossible), [not just checked at construction time](https://lexi-lambda.github.io/blog/2020/11/01/names-are-not-type-safety/). + +Write comments that say *why* you have done a thing, not *what* you have done. +It's ok to go into detail about non-obvious bugs. + +Preserve existing behavior. +Consider platform differences and error cases. + #### Before opening a PR Review your own PR before opening it: Does it make sense? Can you tell what the goal of the PR is? Does it achieve that goal? +Remove outdated or prototyping code and debugging. + +Re-read the whole diff, *not* just your conversation with the agent. +Your reviewer is going to see your code, not your conversation. + [Run tests](tests/running.md) to verify your change works. Do NOT report which UI tests you ran in the PR description; that's noise, since CI will run them anyway. @@ -102,6 +137,8 @@ For example, ask yourself: - What is the original bug? When does it happen? How severe is it? What causes it? - Why is this the right fix? Are there other fixes possible? What are their advantages or disadvantages? - Are there any edge cases? Does your code handle them? +- Does the code have existing [invariants](https://brooker.co.za/blog/2023/07/28/ds-testing.html)? + Did you preserve those invariants? - What behavior is *unchanged*? What test establishes that? - Why does your test trigger the bug? - What are you still not certain about? From cebbf10814b33518523e751d6c0b10572affd499 Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 11:45:16 +0200 Subject: [PATCH 11/98] split authoring and reviewing sections --- src/doc/rustc-dev-guide/src/SUMMARY.md | 4 +- .../rustc-dev-guide/src/llm-guidance/index.md | 10 ++ .../src/llm-guidance/reviewing.md | 76 +++++++++++++ .../writing.md} | 106 ++---------------- 4 files changed, 100 insertions(+), 96 deletions(-) create mode 100644 src/doc/rustc-dev-guide/src/llm-guidance/index.md create mode 100644 src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md rename src/doc/rustc-dev-guide/src/{llm-guidance.md => llm-guidance/writing.md} (59%) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 29a259130d395..d082f6e253175 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -50,7 +50,9 @@ - [About the compiler team](./compiler-team.md) - [Using Git](./git.md) - [Mastering @rustbot](./rustbot.md) -- [Running LLMs](./llm-guidance.md) +- [Running LLMs](./llm-guidance/index.md) + - [Writing code with LLMs](./llm-guidance/writing.md) + - [Reviewing code with LLMs](./llm-guidance/reviewing.md) - [Walkthrough: a typical contribution](./walkthrough.md) - [Implementing new language features](./implementing-new-features.md) - [Stability guarantees](./stability-guarantees.md) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/index.md b/src/doc/rustc-dev-guide/src/llm-guidance/index.md new file mode 100644 index 0000000000000..3709e7ead854c --- /dev/null +++ b/src/doc/rustc-dev-guide/src/llm-guidance/index.md @@ -0,0 +1,10 @@ +# Working with LLMs + +This section is a list of guidelines for working with LLMs, as well as a summary of the moderation policy. +This is not the policy itself; see [Forge][LLM policy]. +If the two conflict, Forge is canonical. + +If you are writing code using an LLM, see [Writing LLM-created code](./writing.md). +If you are reviewing LLM-created code, or reviewing using an LLM, see [Reviewing with LLMs](./reviewing.md). + +[LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md new file mode 100644 index 0000000000000..4feab70ec3dcc --- /dev/null +++ b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md @@ -0,0 +1,76 @@ +## Using an LLM to review code + +- If a more reliable tool, such as a linter or formatter, already exists for the language you're writing, we strongly suggest using that tool instead of or in addition to the LLM. +- Configure LLM review tools to reduce false positives and excessive focus on trivialities, as these are common, exhausting failure modes. +- Wherever possible, ask an LLM to *generate a linter*, which you then tell it to run. + This both saves on token costs, and allows people who are not using an LLM to run the analysis. +- LLMs sometimes prefer LLM-generated output, particularly output from the same + model. Treat LLM review as advisory, and do not rely on the model that + produced a change as its only reviewer. + +## Reviewing LLM-created code + +First, add the new `ai-assisted` label to the PR. + +### Rules + +We expect everyone to follow the new policy, not just authors. +That means it is **your responsibility** to check whether an `ai-assisted` PR touches an area that's disallowed by the policy. +You may request that the author redo it without LLM-generated code, in which case this section doesn't apply. + +The following areas are currently banned: +- Code that affects soundness. If the author is not an org member who is experienced in the domain, you are required to close the PR. +- Diagnostics. All user-facing diagnostics must be human-written. +- Docs. All public doc-comments, and all `SAFETY` comments, must be human-written. + +### Guidelines + +Point people to [#llm-mentoring] liberally. +Deal with low-quality PRs by closing the PR and asking the author to follow the policy. +Deal with borderline PRs by asking the author to put in the work themselves rather than offloading it to you. +For example, ask them to reproduce the bug, explain the change in their own +words, identify relevant edge cases, or add or justify tests. + +If you find yourself suggesting the same fixes on multiple PRs, +consider adding them to the dev-guide. + +#### Missing disclosure + +If you see a PR that is "obviously" LLM-created without disclosing that use, you have the option—but not the responsibility—to close it unilaterally. + +We suggest using the following wording: + +> This PR appears to be LLM-generated without disclosing use of an LLM, +> so I am going to close this PR. +> You are welcome to open additional PRs as long as they follow our [policy][forge-page]. +> For more information, see [#llm-mentoring] on Zulip. + +Examples of "obvious" LLM tells are: +- PR descriptions that are completely wrong/don't match the code. +- PR descriptions that state the exact tests that were run (e.g. `./x test --stage 1 tests/ui/.rs`) or useless tests such as `git diff --check`. +- Responses to reviewer questions that fall into one of the above categories. + +You do not have an obligation to detect LLM-created PRs; +you don't need to play detective. + +PR templates will have a "Did you use an LLM?" question so that this rarely comes up. +If the author deleted the question without answering it, you can close the PR, no questions asked. + +#### Missing solicited reviewer + +If the PR discloses use, but does not assign a reviewer following the [experiment guidelines], you can close it similarly: + +> You've opened an LLM-generated PR, but it's in the normal review queue, which breaks our [policy][experiment guidelines]. +> I am going to close this PR. +> Please do not re-open it until you find a project member who has volunteered to review it. +> For more information, see [#llm-mentoring] on Zulip. + +#### Missing tests, low-quality, or not self-reviewed + +If a PR is clearly not ready for review, you do not have to review it. +It's ok to simply skim the PR and tell the author "you need to add tests before I can review this". +If you notice on your skim that the PR is clearly the wrong approach, it's ok to close the PR and tell the author to talk with you in the [#llm-mentoring] channel before opening a new PR. + +[experiment guidelines]: https://forge.rust-lang.org/policies/llm-usage.html#experiment-llm-created-code-changes-intended-for-review +[#llm-mentoring]: https://rust-lang.zulipchat.com/join/rlfvpemsaacs3pfi6kwqnqjb/ +[forge-page]: https://forge.rust-lang.org/policies/llm-usage.html diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md similarity index 59% rename from src/doc/rustc-dev-guide/src/llm-guidance.md rename to src/doc/rustc-dev-guide/src/llm-guidance/writing.md index d186df8779436..c4ed09bc65936 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md @@ -1,12 +1,4 @@ -# Working with LLMs - -This is a list of guidelines for working with LLMs, as well as a summary of the moderation policy. -This is not the policy itself; see [Forge][LLM policy]. -If the two conflict, Forge is canonical. - -[LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html - -## Writing LLM-created code +# Writing LLM-created code LLMs are a valuable tool, but one that is easy to misuse. The main risks are **overwhelming volume** and **lack of understanding**. @@ -20,8 +12,9 @@ Keep in mind this quote: > — Harold Abelson and Gerald Jay Sussman, [*Structure and Interpretation of Computer Programs*][sicp] [sicp]: https://web.mit.edu/6.001/6.037/sicp.pdf +[#llm-mentoring]: https://rust-lang.zulipchat.com/join/rlfvpemsaacs3pfi6kwqnqjb/ -### Rules +## Rules Before anything else, find a reviewer who volunteers to review your PR. If you do not know where to find a reviewer, ask in [#llm-mentoring] on Zulip. @@ -45,9 +38,9 @@ LLM-created PR descriptions are banned. LLM-created Github comments are banned. We want to hear from you, not from your agent. -### Guidelines +## Guidelines -#### Before you write code +### Before you write code Start with one PR at a time. Keep your changes small enough that you and your reviewer can understand every part of them. @@ -65,7 +58,7 @@ For example: - Make the smallest change that fixes the problem. Do not combine it with unrelated refactors or cleanups. -#### While working +### While working When fixing a bug, verify that your test fails before and succeeds after your change. Consult [adding new tests](./tests/adding.md) and [best practices](./tests/best-practices.md) for test procedures. @@ -84,9 +77,9 @@ Verify your understanding against the existing code, documentation, and tests. You can get better advice from your LLM by telling *it* to read the relevant materials. Do not rely on the LLM as a source of truth. -[small atomic commits](https://github.blog/developer-skills/github/write-better-commits-build-better-projects/#%e2%9a%9b%ef%b8%8f-resize-and-stabilize-the-commits) +[small atomic commits]: https://github.blog/developer-skills/github/write-better-commits-build-better-projects/#%e2%9a%9b%ef%b8%8f-resize-and-stabilize-the-commits -#### Write maintainable code +### Write maintainable code Treat generated code as a *draft*, not a final product. @@ -104,7 +97,7 @@ It's ok to go into detail about non-obvious bugs. Preserve existing behavior. Consider platform differences and error cases. -#### Before opening a PR +### Before opening a PR Review your own PR before opening it: Does it make sense? Can you tell what the goal of the PR is? Does it achieve that goal? @@ -126,7 +119,7 @@ don't simply `--bless` them away. We recommend using a different model for adversarial local review before publishing your changes. You're still responsible for reviewing your own changes yourself. -#### Understand your own change +### Understand your own change We want you to understand and be able to explain your own change and its edge cases. Asking the LLM can be a starting point but it's not the same as explaining it yourself. @@ -148,7 +141,7 @@ We would much rather help you because you're not sure than have you guess wrong [`ast-grep`]: https://astgrep.com/ -#### Disclosure guidelines +### Disclosure guidelines Disclose the *extent* and *purpose* of your LLM use. We don't care which model you used, but we do care whether you used the LLM to implement the idea or to come up with it. @@ -167,80 +160,3 @@ We don't care which model you used, but we do care whether you used the LLM to i > 🤖 Generated with Claude Code > Co-Authored-By: Claude Opus 4.6 (1M context) - -## Automated checks and LLM review - -- If a more reliable tool, such as a linter or formatter, already exists for the language you're writing, we strongly suggest using that tool instead of or in addition to the LLM. -- Configure LLM review tools to reduce false positives and excessive focus on trivialities, as these are common, exhausting failure modes. -- Wherever possible, ask an LLM to *generate a linter*, which you then tell it to run. - This both saves on token costs, and allows people who are not using an LLM to run the analysis. -- LLMs sometimes prefer LLM-generated output, particularly output from the same - model. Treat LLM review as advisory, and do not rely on the model that - produced a change as its only reviewer. - -## Reviewing LLM-created code - -First, add the new `ai-assisted` label to the PR. - -### Rules - -We expect everyone to follow the new policy, not just authors. -That means it is **your responsibility** to check whether an `ai-assisted` PR touches an area that's disallowed by the policy. -You may request that the author redo it without LLM-generated code, in which case this section doesn't apply. - -The following areas are currently banned: -- Code that affects soundness. If the author is not an org member who is experienced in the domain, you are required to close the PR. -- Diagnostics. All user-facing diagnostics must be human-written. -- Docs. All public doc-comments, and all `SAFETY` comments, must be human-written. - -### Guidelines - -Point people to [#llm-mentoring] liberally. -Deal with low-quality PRs by closing the PR and asking the author to follow the policy. -Deal with borderline PRs by asking the author to put in the work themselves rather than offloading it to you. -For example, ask them to reproduce the bug, explain the change in their own -words, identify relevant edge cases, or add or justify tests. - -If you find yourself suggesting the same fixes on multiple PRs, -consider adding them to the dev-guide. - -#### Missing disclosure - -If you see a PR that is "obviously" LLM-created without disclosing that use, you have the option—but not the responsibility—to close it unilaterally. - -We suggest using the following wording: - -> This PR appears to be LLM-generated without disclosing use of an LLM, -> so I am going to close this PR. -> You are welcome to open additional PRs as long as they follow our [policy][forge-page]. -> For more information, see [#llm-mentoring] on Zulip. - -Examples of "obvious" LLM tells are: -- PR descriptions that are completely wrong/don't match the code. -- PR descriptions that state the exact tests that were run (e.g. `./x test --stage 1 tests/ui/.rs`) or useless tests such as `git diff --check`. -- Responses to reviewer questions that fall into one of the above categories. - -You do not have an obligation to detect LLM-created PRs; -you don't need to play detective. - -PR templates will have a "Did you use an LLM?" question so that this rarely comes up. -If the author deleted the question without answering it, you can close the PR, no questions asked. - -#### Missing solicited reviewer - -If the PR discloses use, but does not assign a reviewer following the [experiment guidelines], you can close it similarly: - -> You've opened an LLM-generated PR, but it's in the normal review queue, which breaks our [policy][experiment guidelines]. -> I am going to close this PR. -> Please do not re-open it until you find a project member who has volunteered to review it. -> For more information, see [#llm-mentoring] on Zulip. - -#### Missing tests, low-quality, or not self-reviewed - -If a PR is clearly not ready for review, you do not have to review it. -It's ok to simply skim the PR and tell the author "you need to add tests before I can review this". -If you notice on your skim that the PR is clearly the wrong approach, it's ok to close the PR and tell the author to talk with you in the [#llm-mentoring] channel before opening a new PR. - -[experiment guidelines]: https://forge.rust-lang.org/policies/llm-usage.html#experiment-llm-created-code-changes-intended-for-review -[#llm-mentoring]: https://rust-lang.zulipchat.com/join/rlfvpemsaacs3pfi6kwqnqjb/ -[forge-page]: https://forge.rust-lang.org/policies/llm-usage.html From 7cef419c671a6a89cfa17d580ed9f77983253c8f Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 11:57:35 +0200 Subject: [PATCH 12/98] be more clear about what i mean around linters --- src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md index 4feab70ec3dcc..7bb722195f37c 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md @@ -1,13 +1,20 @@ +# Reviewing with LLMs + ## Using an LLM to review code - If a more reliable tool, such as a linter or formatter, already exists for the language you're writing, we strongly suggest using that tool instead of or in addition to the LLM. - Configure LLM review tools to reduce false positives and excessive focus on trivialities, as these are common, exhausting failure modes. -- Wherever possible, ask an LLM to *generate a linter*, which you then tell it to run. +- Wherever possible, ask an LLM to *generate or configure a linter*, which you then tell it to run. This both saves on token costs, and allows people who are not using an LLM to run the analysis. + For example, if you have a codebase-specific wrapper around command spawning, + rather than getting an LLM to look for places where you should use the wrapper, + [configure clippy to disallow `Command::new`][disallowed-methods]. - LLMs sometimes prefer LLM-generated output, particularly output from the same model. Treat LLM review as advisory, and do not rely on the model that produced a change as its only reviewer. +[disallowed-methods]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-methods + ## Reviewing LLM-created code First, add the new `ai-assisted` label to the PR. From 49d14d6e73105eb67a5b159a72b4f9b46b9a24e0 Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 12:07:00 +0200 Subject: [PATCH 13/98] add more links --- src/doc/rustc-dev-guide/src/llm-guidance/writing.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md index c4ed09bc65936..8366b5c79d08c 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md @@ -55,9 +55,11 @@ For example: - Search for related issues and PRs. - Find relevant code, tests, git history, and Zulip discussion. - If this is a cross-cutting change, consult the "cross-cutting" section of [the contributing docs](./contributing.md#pull-requests). -- Make the smallest change that fixes the problem. +- [Make the smallest change that fixes the problem][small-cls]. Do not combine it with unrelated refactors or cleanups. +[small-cls]: https://google.github.io/eng-practices/review/developer/small-cls.html + ### While working When fixing a bug, verify that your test fails before and succeeds after your change. @@ -91,9 +93,11 @@ trying to keep data in sync between two different places is a code smell. When practical, [make invalid states unrepresentable](https://kentcdodds.com/blog/make-impossible-states-impossible), [not just checked at construction time](https://lexi-lambda.github.io/blog/2020/11/01/names-are-not-type-safety/). -Write comments that say *why* you have done a thing, not *what* you have done. +[Write comments that say *why*][mit-comment-style] you have done a thing, not *what* you have done. It's ok to go into detail about non-obvious bugs. +[mit-comment-style]: https://mitcommlab.mit.edu/broad/commkit/coding-and-comment-style/ + Preserve existing behavior. Consider platform differences and error cases. From 4fb41b1ebbab56949fa1a1e01dc053b68305cdec Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 12:16:40 +0200 Subject: [PATCH 14/98] move correctness suggestions to a better chapter --- src/doc/rustc-dev-guide/src/conventions.md | 24 +++++++++++++++++++ .../src/llm-guidance/writing.md | 17 +------------ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index 0440fb0c5e736..f30921f35bc38 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -141,6 +141,30 @@ if foo { If you want to leave a note in the codebase, use `// FIXME` instead. +### Follow the style of surrounding code. + +Use existing helpers and avoid duplicating logic or validation. + +### Represent data in [one normalized place](https://react.dev/learn/choosing-the-state-structure) + +Trying to keep data in sync between two different places is a code smell. + +### Make invalid states unrepresentable + +When practical, [make invalid states unrepresentable](https://kentcdodds.com/blog/make-impossible-states-impossible), [not just checked at construction time](https://lexi-lambda.github.io/blog/2020/11/01/names-are-not-type-safety/). + +### Write useful comments + +[Write comments that say *why*][mit-comment-style] you have done a thing, not *what* you have done. +It's ok to go into detail about non-obvious bugs. + +[mit-comment-style]: https://mitcommlab.mit.edu/broad/commkit/coding-and-comment-style/ + +### Preserve existing behavior. + +Consider platform differences and error cases. +Look for relevant tests that exercise the edge cases. + ## Using crates from crates.io diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md index 8366b5c79d08c..3a35896712bb8 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md @@ -84,22 +84,7 @@ Do not rely on the LLM as a source of truth. ### Write maintainable code Treat generated code as a *draft*, not a final product. - -Follow the style of surrounding code. -Use existing helpers and avoid duplicating logic or validation. - -Represent data in [one normalized place](https://react.dev/learn/choosing-the-state-structure); -trying to keep data in sync between two different places is a code smell. - -When practical, [make invalid states unrepresentable](https://kentcdodds.com/blog/make-impossible-states-impossible), [not just checked at construction time](https://lexi-lambda.github.io/blog/2020/11/01/names-are-not-type-safety/). - -[Write comments that say *why*][mit-comment-style] you have done a thing, not *what* you have done. -It's ok to go into detail about non-obvious bugs. - -[mit-comment-style]: https://mitcommlab.mit.edu/broad/commkit/coding-and-comment-style/ - -Preserve existing behavior. -Consider platform differences and error cases. +Follow the [correctness conventions](../conventions.md#cc). ### Before opening a PR From 6b52bdaaa3448458dc1b98e0ab7200a704671fa1 Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 12:23:16 +0200 Subject: [PATCH 15/98] address Sasha's review comments --- .../rustc-dev-guide/src/about-this-guide.md | 3 +- .../src/llm-guidance/reviewing.md | 42 +++++++++++++++---- 2 files changed, 35 insertions(+), 10 deletions(-) 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 57f6e676866d8..cc98ad7b2bf4c 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -72,7 +72,7 @@ You might also find the following sites useful: - [rustc API docs] -- rustdoc documentation for the compiler, devtools, and internal tools - [Forge] -- contains documentation about Rust infrastructure, team procedures, and more -- `rust-lang/rust`'s [LLM policy] +- [`rust-lang/rust`]'s [LLM policy] - [compiler-team] -- the home-base for the Rust compiler team, with description of the team procedures, active working groups, and the team calendar. - [std-dev-guide] -- a similar guide for developing the standard library. @@ -114,3 +114,4 @@ You might also find the following sites useful: [std-dev-guide]: https://std-dev-guide.rust-lang.org/ [rust-analyzer book]: https://rust-analyzer.github.io/book/ [z]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler +[`rust-lang/rust`]: https://github.com/rust-lang/rust/ diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md index 7bb722195f37c..44ae4b9e6c2af 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md @@ -28,7 +28,22 @@ You may request that the author redo it without LLM-generated code, in which cas The following areas are currently banned: - Code that affects soundness. If the author is not an org member who is experienced in the domain, you are required to close the PR. - Diagnostics. All user-facing diagnostics must be human-written. -- Docs. All public doc-comments, and all `SAFETY` comments, must be human-written. +- Docs. All public doc-comments, and all `// SAFETY` comments, must be human-written. + +"Code that affects soundness" is both broader and narrower than it sounds. +It's broader because almost all of the compiler is relevant to soundness; +it's narrower because there's quite a lot of rust-lang/rust that isn't the compiler +(library, bootstrap, compiletest, rustdoc, CI, ...). + +If in doubt, we suggest this criteria: +Do not allow LLM-generated code for parts of the compiler where [wrong code does not look wrong][joel-wrong]. +Ultimately, this is up to your judgement as a reviewer. + +[joel-wrong]: https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/ + +You are still expected to respect your [r+ rights](../compiler-team.html#r-rights). +Please do not merge PRs unless you are confident in that part of that code, +even if the maintainer does not wish to review LLM PRs. ### Guidelines @@ -47,10 +62,14 @@ If you see a PR that is "obviously" LLM-created without disclosing that use, you We suggest using the following wording: -> This PR appears to be LLM-generated without disclosing use of an LLM, -> so I am going to close this PR. -> You are welcome to open additional PRs as long as they follow our [policy][forge-page]. -> For more information, see [#llm-mentoring] on Zulip. +```markdown +This PR appears to be LLM-generated without disclosing use of an LLM, so I am going to close this PR. +You are welcome to open additional PRs as long as they follow our [policy][forge-page]. +For more information, see [#llm-mentoring] on Zulip. + +[#llm-mentoring]: https://rust-lang.zulipchat.com/join/rlfvpemsaacs3pfi6kwqnqjb/ +[forge-page]: https://forge.rust-lang.org/policies/llm-usage.html +``` Examples of "obvious" LLM tells are: - PR descriptions that are completely wrong/don't match the code. @@ -67,10 +86,15 @@ If the author deleted the question without answering it, you can close the PR, n If the PR discloses use, but does not assign a reviewer following the [experiment guidelines], you can close it similarly: -> You've opened an LLM-generated PR, but it's in the normal review queue, which breaks our [policy][experiment guidelines]. -> I am going to close this PR. -> Please do not re-open it until you find a project member who has volunteered to review it. -> For more information, see [#llm-mentoring] on Zulip. +```markdown +You've opened an LLM-generated PR, but it's in the normal review queue, which breaks our [policy][experiment guidelines]. +I am going to close this PR. +Please do not re-open it until you find a project member who has volunteered to review it. +For more information, see [#llm-mentoring] on Zulip. + +[#llm-mentoring]: https://rust-lang.zulipchat.com/join/rlfvpemsaacs3pfi6kwqnqjb/ +[forge-page]: https://forge.rust-lang.org/policies/llm-usage.html +``` #### Missing tests, low-quality, or not self-reviewed From ff5a4a4829acb9567309f3b10658eef276a7e02d Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 12:38:23 +0200 Subject: [PATCH 16/98] fix links --- src/doc/rustc-dev-guide/src/llm-guidance/writing.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md index 3a35896712bb8..4ea43ae008519 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md @@ -34,9 +34,9 @@ As before, you can use an LLM to review your work, but not to write it from scra If you don't know what counts as soundness-critical, discuss it with your reviewer. **Write your own PR description and comments**. +We want to hear from you, not from your agent. LLM-created PR descriptions are banned. LLM-created Github comments are banned. -We want to hear from you, not from your agent. ## Guidelines @@ -54,7 +54,7 @@ For example: - Search for related issues and PRs. - Find relevant code, tests, git history, and Zulip discussion. -- If this is a cross-cutting change, consult the "cross-cutting" section of [the contributing docs](./contributing.md#pull-requests). +- If this is a cross-cutting change, consult the "cross-cutting" section of [the contributing docs](../contributing.md#pull-requests). - [Make the smallest change that fixes the problem][small-cls]. Do not combine it with unrelated refactors or cleanups. @@ -63,7 +63,7 @@ For example: ### While working When fixing a bug, verify that your test fails before and succeeds after your change. -Consult [adding new tests](./tests/adding.md) and [best practices](./tests/best-practices.md) for test procedures. +Consult [adding new tests](../tests/adding.md) and [best practices](../tests/best-practices.md) for test procedures. Tests are absolutely required; either existing tests or new tests you write. Untested LLM PRs will not be merged. @@ -96,13 +96,13 @@ Remove outdated or prototyping code and debugging. Re-read the whole diff, *not* just your conversation with the agent. Your reviewer is going to see your code, not your conversation. -[Run tests](tests/running.md) to verify your change works. +[Run tests](../tests/running.md) to verify your change works. Do NOT report which UI tests you ran in the PR description; that's noise, since CI will run them anyway. If you did manual testing or benchmarking, do report that, but note that all LLM PRs must have automated tests. -[Review diagnostic snapshots](tests/adding.md#step-4-review-the-output); +[Review diagnostic snapshots](../tests/adding.md#step-4-review-the-output); don't simply `--bless` them away. We recommend using a different model for adversarial local review before publishing your changes. @@ -148,4 +148,4 @@ We don't care which model you used, but we do care whether you used the LLM to i > 🤖 Generated with Claude Code -> Co-Authored-By: Claude Opus 4.6 (1M context) +> `Co-Authored-By: Claude Opus 4.6 (1M context) ` From df4f543804601e3660bc4cc74eaadc379f139ee5 Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 12:47:39 +0200 Subject: [PATCH 17/98] tweaks --- src/doc/rustc-dev-guide/src/conventions.md | 17 ++++++++++++----- .../src/llm-guidance/writing.md | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index f30921f35bc38..023db80481e78 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -141,15 +141,15 @@ if foo { If you want to leave a note in the codebase, use `// FIXME` instead. -### Follow the style of surrounding code. +### Follow the style of surrounding code Use existing helpers and avoid duplicating logic or validation. -### Represent data in [one normalized place](https://react.dev/learn/choosing-the-state-structure) +### [Avoid duplicated sources of truth](https://react.dev/learn/choosing-the-state-structure) Trying to keep data in sync between two different places is a code smell. -### Make invalid states unrepresentable +### Use types to enforce invariants When practical, [make invalid states unrepresentable](https://kentcdodds.com/blog/make-impossible-states-impossible), [not just checked at construction time](https://lexi-lambda.github.io/blog/2020/11/01/names-are-not-type-safety/). @@ -160,11 +160,16 @@ It's ok to go into detail about non-obvious bugs. [mit-comment-style]: https://mitcommlab.mit.edu/broad/commkit/coding-and-comment-style/ -### Preserve existing behavior. +### Preserve existing behavior Consider platform differences and error cases. Look for relevant tests that exercise the edge cases. +### Work in small steps + +Work in small, independently testable steps. +Run the relevant tests after every meaningful change, so you know where you first went wrong. + ## Using crates from crates.io @@ -183,11 +188,13 @@ you rename a method, then put that rename into its own commit, along with the renames of all the uses. **More commits is usually better.** If you are doing a large change, -it's almost always better to break it up into smaller steps that can be independently understood. +it's almost always better to break it up into smaller steps that can be [independently understood][atomic commits]. The one thing to be aware of is that if you introduce some code following one strategy, then change it dramatically (versus adding to it) in a later commit, that 'back-and-forth' can be confusing. +[atomic commits]: https://github.blog/developer-skills/github/write-better-commits-build-better-projects/#%e2%9a%9b%ef%b8%8f-resize-and-stabilize-the-commits + **Format liberally.** While only the final commit of a PR must be correctly formatted, it is both easier to review and less noisy to format each commit individually using `./x fmt`. diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md index 4ea43ae008519..c3115e602be0d 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md @@ -70,21 +70,26 @@ Untested LLM PRs will not be merged. Mass renames or rewrites should *strongly* prefer using a proper syntax rewrite tool, such as [`ast-grep`]. You may use an LLM for generating the instructions for that tool, but you should be very cautious about performing the rewrite directly with an LLM. -Work in small steps. -Run tests after every meaningful change, so you know where you first went wrong. -Do not write all your code at once; that will make it very hard to know what broke. -Ideally, commit your changes in [small atomic commits] as you go. +Consider [performance] as you write. + +[performance]: ../contributing.md#performance + +Think before adding dependencies; +consult our [guidance for new dependencies][crates-io]. + +[crates-io]: ../crates-io.md Verify your understanding against the existing code, documentation, and tests. You can get better advice from your LLM by telling *it* to read the relevant materials. Do not rely on the LLM as a source of truth. -[small atomic commits]: https://github.blog/developer-skills/github/write-better-commits-build-better-projects/#%e2%9a%9b%ef%b8%8f-resize-and-stabilize-the-commits - ### Write maintainable code Treat generated code as a *draft*, not a final product. -Follow the [correctness conventions](../conventions.md#cc). +Follow our [correctness and maintainability conventions](../conventions.md#cc). + +Avoid unnecessary abstractions and compatibility layers. +Rustc does not have a stable API; you do not need to preserve backwards compatibility for internal compiler APIs. ### Before opening a PR From beca161c45390f06345e61d96564ae1a4f3168cd Mon Sep 17 00:00:00 2001 From: jyn Date: Wed, 29 Jul 2026 12:54:54 +0200 Subject: [PATCH 18/98] headings --- .../rustc-dev-guide/src/llm-guidance/writing.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md index c3115e602be0d..aaf37b030cf62 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md @@ -16,6 +16,8 @@ Keep in mind this quote: ## Rules +### Before you write code + Before anything else, find a reviewer who volunteers to review your PR. If you do not know where to find a reviewer, ask in [#llm-mentoring] on Zulip. Your first message should say: @@ -25,14 +27,21 @@ Your first message should say: - (optional) ideas you have so far for a solution - (optional) how you expect to test your solution -Disclose your use of LLMs, following the disclosure guidelines below. -Write the disclosure yourself. -You may use an LLM to privately review a disclosure you have written, but not to draft or rewrite it. +Mentors are here to help. +Talking to them early helps you avoid wasted work. + +### While working Write your own doc-comments, `// SAFETY` comments, diagnostic wording, and soundness-critical code. As before, you can use an LLM to review your work, but not to write it from scratch. If you don't know what counts as soundness-critical, discuss it with your reviewer. +### When opening a PR + +Disclose your use of LLMs, following the disclosure guidelines below. +Write the disclosure yourself. +You may use an LLM to privately review a disclosure you have written, but not to draft or rewrite it. + **Write your own PR description and comments**. We want to hear from you, not from your agent. LLM-created PR descriptions are banned. From a2d28afb2840a40664e87414a9fbcd755598638f Mon Sep 17 00:00:00 2001 From: jyn Date: Thu, 30 Jul 2026 23:43:40 +0200 Subject: [PATCH 19/98] don't treat model names as a good example of disclosure --- src/doc/rustc-dev-guide/src/llm-guidance/writing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md index aaf37b030cf62..6719b5e786002 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md @@ -153,7 +153,7 @@ We don't care which model you used, but we do care whether you used the LLM to i > LLM disclosure: I wrote the three commits by hand after viewing profiling data. I used an LLM to review the commits before submitting. The LLM identified that `ImplString::is_negative` was no longer used, so I removed that field by hand. -> Created with the help of Claude Code, which: +> Created with the help of an LLM, which: > - traced the missing cache hits to the unconditional `return(pass)` by inspecting Fastly vs CloudFront headers, > - reviewed the git history to understand why the snippet was added, and > - made the VCL change. From daafdb59851981953989d2e44ba614510d125186 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 1 Aug 2026 17:42:49 -0700 Subject: [PATCH 20/98] Document `./x build --timings` --- .../src/building/bootstrapping/what-bootstrapping-does.md | 2 +- src/doc/rustc-dev-guide/src/profiling.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md index 0623d176403e4..011afa2de948c 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md @@ -372,7 +372,7 @@ Finally, `MAGIC_EXTRA_RUSTFLAGS` bypasses the - `RUSTDOCFLAGS`, `RUSTDOCFLAGS_BOOTSTRAP` and `RUSTDOCFLAGS_NOT_BOOTSTRAP` are analogous to `RUSTFLAGS`, but for `rustdoc`. -- `CARGOFLAGS` will pass arguments to cargo itself (e.g. `--timings`). +- `CARGOFLAGS` will pass arguments to cargo itself. `CARGOFLAGS_BOOTSTRAP` and `CARGOFLAGS_NOT_BOOTSTRAP` work analogously to `RUSTFLAGS_BOOTSTRAP`. - `--test-args` will pass arguments through to the test runner. For `tests/ui`, diff --git a/src/doc/rustc-dev-guide/src/profiling.md b/src/doc/rustc-dev-guide/src/profiling.md index 66eabe7d8c930..ed4e15e9c0851 100644 --- a/src/doc/rustc-dev-guide/src/profiling.md +++ b/src/doc/rustc-dev-guide/src/profiling.md @@ -19,7 +19,7 @@ Depending on what you're trying to measure, there are several different approach - If you want a nice visual representation of the compile times of your crate graph, you can use [cargo's `--timings` flag](https://doc.rust-lang.org/nightly/cargo/reference/timings.html), e.g. `cargo build --timings`. - You can use this flag on the compiler itself with `CARGOFLAGS="--timings" ./x build` + You can use this flag on the compiler itself with `./x build compiler --timings` - If you want to profile memory usage, you can use various tools depending on what operating system you are using. From fbaa0345dd6433b3503bbc548fe8ee5839c7e239 Mon Sep 17 00:00:00 2001 From: jyn Date: Sun, 2 Aug 2026 12:43:20 +0200 Subject: [PATCH 21/98] document that commit messages must be human-authored --- src/doc/rustc-dev-guide/src/llm-guidance/writing.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md index 6719b5e786002..6af83fd4246cb 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md @@ -100,6 +100,11 @@ Follow our [correctness and maintainability conventions](../conventions.md#cc). Avoid unnecessary abstractions and compatibility layers. Rustc does not have a stable API; you do not need to preserve backwards compatibility for internal compiler APIs. +### Commit structure + +See ["How to structure your PR"](../contributing.md#er). +Commit messages must be authored by you, not your LLM. + ### Before opening a PR Review your own PR before opening it: From 77a8b9f863422da6ae1c6c54774eec9240d4a7b9 Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Wed, 5 Aug 2026 19:37:32 +0200 Subject: [PATCH 22/98] move index file up to make external links to ".../llm-guidance.html" work --- .../src/{llm-guidance/index.md => llm-guidance.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/doc/rustc-dev-guide/src/{llm-guidance/index.md => llm-guidance.md} (100%) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/index.md b/src/doc/rustc-dev-guide/src/llm-guidance.md similarity index 100% rename from src/doc/rustc-dev-guide/src/llm-guidance/index.md rename to src/doc/rustc-dev-guide/src/llm-guidance.md From 142707e1162b2dd0bf5837741b387962f49fb5c8 Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Wed, 5 Aug 2026 19:45:37 +0200 Subject: [PATCH 23/98] Update relative links --- src/doc/rustc-dev-guide/src/SUMMARY.md | 2 +- src/doc/rustc-dev-guide/src/llm-guidance.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 32dc0051a9de1..09960ae453df1 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -52,7 +52,7 @@ - [About the compiler team](./compiler-team.md) - [Using Git](./git.md) - [Mastering @rustbot](./rustbot.md) -- [Running LLMs](./llm-guidance/index.md) +- [Running LLMs](./llm-guidance.md) - [Writing code with LLMs](./llm-guidance/writing.md) - [Reviewing code with LLMs](./llm-guidance/reviewing.md) - [Walkthrough: a typical contribution](./walkthrough.md) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance.md b/src/doc/rustc-dev-guide/src/llm-guidance.md index 3709e7ead854c..c1b34362d2f47 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance.md @@ -4,7 +4,7 @@ This section is a list of guidelines for working with LLMs, as well as a summary This is not the policy itself; see [Forge][LLM policy]. If the two conflict, Forge is canonical. -If you are writing code using an LLM, see [Writing LLM-created code](./writing.md). -If you are reviewing LLM-created code, or reviewing using an LLM, see [Reviewing with LLMs](./reviewing.md). +If you are writing code using an LLM, see [Writing LLM-created code](llm-guidance/writing.md). +If you are reviewing LLM-created code, or reviewing using an LLM, see [Reviewing with LLMs](llm-guidance/reviewing.md). [LLM policy]: https://forge.rust-lang.org/policies/llm-usage.html From fb0210d00b52b04a5bae5ed303ff72f193107e2b Mon Sep 17 00:00:00 2001 From: beetrees Date: Mon, 3 Aug 2026 15:03:22 +0100 Subject: [PATCH 24/98] PowerPC inline ASM: Fix scalar floats being in the wrong vector lane on little endian --- compiler/rustc_codegen_llvm/src/asm.rs | 56 +- tests/assembly-llvm/asm/powerpc-types.rs | 652 +++++++++-------------- 2 files changed, 280 insertions(+), 428 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index d2dfa9a45de8b..3ba28427023e7 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -1,7 +1,7 @@ use std::assert_matches; use std::fmt::Write; -use rustc_abi::{BackendRepr, Float, Integer, Primitive, Scalar, Size}; +use rustc_abi::{BackendRepr, Endian, Float, Integer, Primitive, Scalar, Size}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; use rustc_codegen_ssa::traits::*; @@ -12,6 +12,7 @@ use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, span_bug}; use rustc_span::{Pos, Span, Symbol, sym}; use rustc_target::asm::*; +use rustc_target::spec::HasTargetSpec; use smallvec::SmallVec; use tracing::debug; @@ -1244,24 +1245,16 @@ fn llvm_fixup_input<'ll, 'tcx>( ( PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg), BackendRepr::Scalar(s), - ) if s.primitive() == Primitive::Float(Float::F32) => { - let value = bx.insert_element( - bx.const_undef(bx.type_vector(bx.type_f32(), 4)), + ) if let Primitive::Float(float @ (Float::F32 | Float::F64)) = s.primitive() => { + let num_lanes = 16 / float.size().bytes(); + bx.insert_element( + bx.const_undef(bx.type_vector(bx.type_from_float(float), num_lanes)), value, - bx.const_usize(0), - ); - bx.bitcast(value, bx.type_vector(bx.type_f32(), 4)) - } - ( - PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg), - BackendRepr::Scalar(s), - ) if s.primitive() == Primitive::Float(Float::F64) => { - let value = bx.insert_element( - bx.const_undef(bx.type_vector(bx.type_f64(), 2)), - value, - bx.const_usize(0), - ); - bx.bitcast(value, bx.type_vector(bx.type_f64(), 2)) + bx.const_usize(match bx.target_spec().endian { + Endian::Little => num_lanes - 1, + Endian::Big => 0, + }), + ) } _ => value, } @@ -1416,16 +1409,15 @@ fn llvm_fixup_output<'ll, 'tcx>( ( PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg), BackendRepr::Scalar(s), - ) if s.primitive() == Primitive::Float(Float::F32) => { - let value = bx.bitcast(value, bx.type_vector(bx.type_f32(), 4)); - bx.extract_element(value, bx.const_usize(0)) - } - ( - PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg), - BackendRepr::Scalar(s), - ) if s.primitive() == Primitive::Float(Float::F64) => { - let value = bx.bitcast(value, bx.type_vector(bx.type_f64(), 2)); - bx.extract_element(value, bx.const_usize(0)) + ) if let Primitive::Float(float @ (Float::F32 | Float::F64)) = s.primitive() => { + let num_lanes = 16 / float.size().bytes(); + bx.extract_element( + value, + bx.const_usize(match bx.target_spec().endian { + Endian::Little => num_lanes - 1, + Endian::Big => 0, + }), + ) } _ => value, } @@ -1566,11 +1558,9 @@ fn llvm_fixup_output_type<'ll, 'tcx>( ( PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg), BackendRepr::Scalar(s), - ) if s.primitive() == Primitive::Float(Float::F32) => cx.type_vector(cx.type_f32(), 4), - ( - PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg), - BackendRepr::Scalar(s), - ) if s.primitive() == Primitive::Float(Float::F64) => cx.type_vector(cx.type_f64(), 2), + ) if let Primitive::Float(float @ (Float::F32 | Float::F64)) = s.primitive() => { + cx.type_vector(cx.type_from_float(float), 16 / float.size().bytes()) + } _ => layout.llvm_type(cx), } } diff --git a/tests/assembly-llvm/asm/powerpc-types.rs b/tests/assembly-llvm/asm/powerpc-types.rs index 211c817a325cb..c1c750914246d 100644 --- a/tests/assembly-llvm/asm/powerpc-types.rs +++ b/tests/assembly-llvm/asm/powerpc-types.rs @@ -1,43 +1,97 @@ +// ignore-tidy-file-linelength (some revision //@ lines are over 100 chars long) + //@ add-minicore -//@ revisions: powerpc powerpc_altivec powerpc_vsx powerpc64 powerpc64_vsx +//@ revisions: powerpc powerpc_altivec powerpc_vsx powerpc_power8 powerpc64 powerpc64_vsx powerpc64_power8 powerpc64le //@ assembly-output: emit-asm //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu //@[powerpc] needs-llvm-components: powerpc //@[powerpc_altivec] compile-flags: --target powerpc-unknown-linux-gnu -C target-feature=+altivec --cfg altivec //@[powerpc_altivec] needs-llvm-components: powerpc +//@[powerpc_altivec] filecheck-flags: --check-prefix altivec //@[powerpc_vsx] compile-flags: --target powerpc-unknown-linux-gnu -C target-feature=+altivec,+vsx --cfg altivec --cfg vsx //@[powerpc_vsx] needs-llvm-components: powerpc +//@[powerpc_vsx] filecheck-flags: --check-prefix altivec --check-prefix vsx +//@[powerpc_power8] compile-flags: --target powerpc-unknown-linux-gnu -C target-feature=+altivec,+vsx,+power8-vector --cfg altivec --cfg vsx --cfg power8 +//@[powerpc_power8] needs-llvm-components: powerpc +//@[powerpc_power8] filecheck-flags: --check-prefix altivec --check-prefix vsx --check-prefix power8 //@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu --cfg altivec //@[powerpc64] needs-llvm-components: powerpc -//@[powerpc64_vsx] compile-flags: --target powerpc64-unknown-linux-gnu -C target-feature=+vsx --cfg altivec --cfg vsx +//@[powerpc64] filecheck-flags: --check-prefix altivec +//@[powerpc64_vsx] compile-flags: --target powerpc64-unknown-linux-gnu -C target-feature=+vsx --cfg powerpc64 --cfg altivec --cfg vsx //@[powerpc64_vsx] needs-llvm-components: powerpc +//@[powerpc64_vsx] filecheck-flags: --check-prefix powerpc64 --check-prefix altivec --check-prefix vsx +//@[powerpc64_power8] compile-flags: --target powerpc64-unknown-linux-gnu -C target-feature=+vsx,+power8-vector --cfg powerpc64 --cfg altivec --cfg vsx --cfg power8 +//@[powerpc64_power8] needs-llvm-components: powerpc +//@[powerpc64_power8] filecheck-flags: --check-prefix powerpc64 --check-prefix altivec --check-prefix vsx --check-prefix power8 +//@[powerpc64le] compile-flags: --target powerpc64le-unknown-linux-gnu --cfg powerpc64 --cfg altivec --cfg vsx --cfg power8 +//@[powerpc64le] needs-llvm-components: powerpc +//@[powerpc64le] filecheck-flags: --check-prefix powerpc64 --check-prefix altivec --check-prefix vsx --check-prefix power8 //@ compile-flags: -Zmerge-functions=disabled +//@ compile-flags: --check-cfg=cfg(altivec,vsx,power8) -#![feature(no_core, asm_experimental_arch)] +#![feature(no_core)] #![crate_type = "rlib"] #![no_core] -#![allow(asm_sub_register, non_camel_case_types)] +#![allow(asm_sub_register, non_camel_case_types, unused_imports)] +#![deny(unexpected_cfgs)] extern crate minicore; use minicore::simd::*; use minicore::*; +#[cfg_attr(powerpc64, cfg(not(target_arch = "powerpc64")))] +#[cfg_attr(not(powerpc64), cfg(target_arch = "powerpc64"))] +compile_error!("powerpc64 cfg and target arch mismatch"); #[cfg_attr(altivec, cfg(not(target_feature = "altivec")))] #[cfg_attr(not(altivec), cfg(target_feature = "altivec"))] compile_error!("altivec cfg and target feature mismatch"); #[cfg_attr(vsx, cfg(not(target_feature = "vsx")))] #[cfg_attr(not(vsx), cfg(target_feature = "vsx"))] compile_error!("vsx cfg and target feature mismatch"); +#[cfg_attr(power8, cfg(not(target_feature = "power8-vector")))] +#[cfg_attr(not(power8), cfg(target_feature = "power8-vector"))] +compile_error!("power8-vector cfg and target feature mismatch"); + +// Check floating point scalars are put in the right vector lane. This uses power8 for consistent +// assembly between powerpc64le and big-endian powerpc/powerpc64. + +// power8-LABEL: f32_to_f64: +// power8: .cfi_startproc +// power8-NEXT: xscvdpspn [[#INPUT:]], 1 +// powerpc64le-NEXT: vmrgow [[#INPUT - 32]], [[#INPUT - 32]], [[#INPUT - 32]] +// power8-NEXT: #APP +// power8-NEXT: xscvspdp 1, [[#INPUT]] +// power8-NEXT: #NO_APP +// power8-NEXT: blr +#[cfg(power8)] +#[unsafe(no_mangle)] +pub fn f32_to_f64(x: f32) -> f64 { + let res; + unsafe { + asm!("xscvspdp {}, {}", out(vsreg) res, in(vsreg) x, options(pure, nostack, nomem)); + }; + res +} -type ptr = *const i32; - -extern "C" { - fn extern_func(); - static extern_static: u8; +// power8-LABEL: f64_to_f32: +// power8: .cfi_startproc +// power8-NEXT: #APP +// power8-NEXT: xscvdpsp [[#OUTPUT:]], 1 +// power8-NEXT: #NO_APP +// power8-NEXT: xscvspdpn 1, [[#OUTPUT]] +// power8-NEXT: blr +#[cfg(power8)] +#[unsafe(no_mangle)] +pub fn f64_to_f32(x: f64) -> f32 { + let res; + unsafe { + asm!("xscvdpsp {}, {}", out(vsreg) res, in(vsreg) x, options(pure, nostack, nomem)); + }; + res } macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe fn $func(x: $ty) -> $ty { let y; asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); @@ -46,7 +100,7 @@ macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { };} macro_rules! check_reg { ($func:ident, $ty:ty, $rego:tt, $regc:tt, $mov:literal) => { - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe fn $func(x: $ty) -> $ty { let y; asm!(concat!($mov, " ", $rego, ", ", $rego), lateout($regc) y, in($regc) x); @@ -116,179 +170,115 @@ check!(reg_f32, f32, freg, "fmr"); // CHECK: #NO_APP check!(reg_f64, f64, freg, "fmr"); -// powerpc_altivec-LABEL: vreg_i8x16: -// powerpc_altivec: #APP -// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i8x16: -// powerpc64: #APP -// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64: #NO_APP +// altivec-LABEL: vreg_i8x16: +// altivec: #APP +// altivec: vmr {{[0-9]+}}, {{[0-9]+}} +// altivec: #NO_APP #[cfg(altivec)] check!(vreg_i8x16, i8x16, vreg, "vmr"); -// powerpc_altivec-LABEL: vreg_i16x8: -// powerpc_altivec: #APP -// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i16x8: -// powerpc64: #APP -// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64: #NO_APP +// altivec-LABEL: vreg_i16x8: +// altivec: #APP +// altivec: vmr {{[0-9]+}}, {{[0-9]+}} +// altivec: #NO_APP #[cfg(altivec)] check!(vreg_i16x8, i16x8, vreg, "vmr"); -// powerpc_altivec-LABEL: vreg_i32x4: -// powerpc_altivec: #APP -// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i32x4: -// powerpc64: #APP -// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64: #NO_APP +// altivec-LABEL: vreg_i32x4: +// altivec: #APP +// altivec: vmr {{[0-9]+}}, {{[0-9]+}} +// altivec: #NO_APP #[cfg(altivec)] check!(vreg_i32x4, i32x4, vreg, "vmr"); -// powerpc_vsx-LABEL: vreg_i64x2: -// powerpc_vsx: #APP -// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_i64x2: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_i64x2: +// vsx: #APP +// vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vreg_i64x2, i64x2, vreg, "vmr"); -// powerpc_altivec-LABEL: vreg_f32x4: -// powerpc_altivec: #APP -// powerpc_altivec: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_f32x4: -// powerpc64: #APP -// powerpc64: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64: #NO_APP +// altivec-LABEL: vreg_f32x4: +// altivec: #APP +// altivec: vmr {{[0-9]+}}, {{[0-9]+}} +// altivec: #NO_APP #[cfg(altivec)] check!(vreg_f32x4, f32x4, vreg, "vmr"); -// powerpc_vsx-LABEL: vreg_f64x2: -// powerpc_vsx: #APP -// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64x2: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_f64x2: +// vsx: #APP +// vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vreg_f64x2, f64x2, vreg, "vmr"); -// powerpc_vsx-LABEL: vreg_f32: -// powerpc_vsx: #APP -// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f32: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_f32: +// vsx: #APP +// vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vreg_f32, f32, vreg, "vmr"); -// powerpc_vsx-LABEL: vreg_f64: -// powerpc_vsx: #APP -// powerpc_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_f64: +// vsx: #APP +// vsx: vmr {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vreg_f64, f64, vreg, "vmr"); -// powerpc_vsx-LABEL: vsreg_i8x16: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i8x16: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i8x16: +// vsx: #APP +// vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vsreg_i8x16, i8x16, vsreg, "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_i16x8: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i16x8: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i16x8: +// vsx: #APP +// vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vsreg_i16x8, i16x8, vsreg, "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_i32x4: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i32x4: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i32x4: +// vsx: #APP +// vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vsreg_i32x4, i32x4, vsreg, "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_i64x2: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i64x2: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i64x2: +// vsx: #APP +// vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vsreg_i64x2, i64x2, vsreg, "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f32x4: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f32x4: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f32x4: +// vsx: #APP +// vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vsreg_f32x4, f32x4, vsreg, "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f64x2: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f64x2: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f64x2: +// vsx: #APP +// vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vsreg_f64x2, f64x2, vsreg, "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f32: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f32: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f32: +// vsx: #APP +// vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vsreg_f32, f32, vsreg, "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f64: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f64: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f64: +// vsx: #APP +// vsx: xvsqrtdp {{[0-9]+}}, {{[0-9]+}} +// vsx: #NO_APP #[cfg(vsx)] check!(vsreg_f64, f64, vsreg, "xvsqrtdp"); @@ -366,354 +356,226 @@ check_reg!(reg_f32_f18, f32, "18", "f18", "fmr"); // CHECK: #NO_APP check_reg!(reg_f64_f18, f64, "18", "f18", "fmr"); -// powerpc_altivec-LABEL: vreg_i8x16_v0: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 0, 0 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i8x16_v0: -// powerpc64: #APP -// powerpc64: vmr 0, 0 -// powerpc64: #NO_APP +// altivec-LABEL: vreg_i8x16_v0: +// altivec: #APP +// altivec: vmr 0, 0 +// altivec: #NO_APP #[cfg(altivec)] check_reg!(vreg_i8x16_v0, i8x16, "0", "v0", "vmr"); -// powerpc_altivec-LABEL: vreg_i16x8_v0: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 0, 0 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i16x8_v0: -// powerpc64: #APP -// powerpc64: vmr 0, 0 -// powerpc64: #NO_APP +// altivec-LABEL: vreg_i16x8_v0: +// altivec: #APP +// altivec: vmr 0, 0 +// altivec: #NO_APP #[cfg(altivec)] check_reg!(vreg_i16x8_v0, i16x8, "0", "v0", "vmr"); -// powerpc_altivec-LABEL: vreg_i32x4_v0: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 0, 0 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i32x4_v0: -// powerpc64: #APP -// powerpc64: vmr 0, 0 -// powerpc64: #NO_APP +// altivec-LABEL: vreg_i32x4_v0: +// altivec: #APP +// altivec: vmr 0, 0 +// altivec: #NO_APP #[cfg(altivec)] check_reg!(vreg_i32x4_v0, i32x4, "0", "v0", "vmr"); -// powerpc_vsx-LABEL: vreg_i64x2_v0: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_i64x2_v0: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_i64x2_v0: +// vsx: #APP +// vsx: vmr 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vreg_i64x2_v0, i64x2, "0", "v0", "vmr"); -// powerpc_altivec-LABEL: vreg_f32x4_v0: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 0, 0 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_f32x4_v0: -// powerpc64: #APP -// powerpc64: vmr 0, 0 -// powerpc64: #NO_APP +// altivec-LABEL: vreg_f32x4_v0: +// altivec: #APP +// altivec: vmr 0, 0 +// altivec: #NO_APP #[cfg(altivec)] check_reg!(vreg_f32x4_v0, f32x4, "0", "v0", "vmr"); -// powerpc_vsx-LABEL: vreg_f64x2_v0: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64x2_v0: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_f64x2_v0: +// vsx: #APP +// vsx: vmr 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vreg_f64x2_v0, f64x2, "0", "v0", "vmr"); -// powerpc_vsx-LABEL: vreg_f32_v0: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f32_v0: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_f32_v0: +// vsx: #APP +// vsx: vmr 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vreg_f32_v0, f32, "0", "v0", "vmr"); -// powerpc_vsx-LABEL: vreg_f64_v0: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64_v0: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_f64_v0: +// vsx: #APP +// vsx: vmr 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vreg_f64_v0, f64, "0", "v0", "vmr"); -// powerpc_altivec-LABEL: vreg_i8x16_v18: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 18, 18 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i8x16_v18: -// powerpc64: #APP -// powerpc64: vmr 18, 18 -// powerpc64: #NO_APP +// altivec-LABEL: vreg_i8x16_v18: +// altivec: #APP +// altivec: vmr 18, 18 +// altivec: #NO_APP #[cfg(altivec)] check_reg!(vreg_i8x16_v18, i8x16, "18", "v18", "vmr"); -// powerpc_altivec-LABEL: vreg_i16x8_v18: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 18, 18 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i16x8_v18: -// powerpc64: #APP -// powerpc64: vmr 18, 18 -// powerpc64: #NO_APP +// altivec-LABEL: vreg_i16x8_v18: +// altivec: #APP +// altivec: vmr 18, 18 +// altivec: #NO_APP #[cfg(altivec)] check_reg!(vreg_i16x8_v18, i16x8, "18", "v18", "vmr"); -// powerpc_altivec-LABEL: vreg_i32x4_v18: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 18, 18 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_i32x4_v18: -// powerpc64: #APP -// powerpc64: vmr 18, 18 -// powerpc64: #NO_APP +// altivec-LABEL: vreg_i32x4_v18: +// altivec: #APP +// altivec: vmr 18, 18 +// altivec: #NO_APP #[cfg(altivec)] check_reg!(vreg_i32x4_v18, i32x4, "18", "v18", "vmr"); -// powerpc_vsx-LABEL: vreg_i64x2_v18: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 18, 18 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_i64x2_v18: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 18, 18 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_i64x2_v18: +// vsx: #APP +// vsx: vmr 18, 18 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vreg_i64x2_v18, i64x2, "18", "v18", "vmr"); -// powerpc_altivec-LABEL: vreg_f32x4_v18: -// powerpc_altivec: #APP -// powerpc_altivec: vmr 18, 18 -// powerpc_altivec: #NO_APP -// powerpc64-LABEL: vreg_f32x4_v18: -// powerpc64: #APP -// powerpc64: vmr 18, 18 -// powerpc64: #NO_APP +// altivec-LABEL: vreg_f32x4_v18: +// altivec: #APP +// altivec: vmr 18, 18 +// altivec: #NO_APP #[cfg(altivec)] check_reg!(vreg_f32x4_v18, f32x4, "18", "v18", "vmr"); -// powerpc_vsx-LABEL: vreg_f64x2_v18: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 18, 18 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64x2_v18: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 18, 18 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_f64x2_v18: +// vsx: #APP +// vsx: vmr 18, 18 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vreg_f64x2_v18, f64x2, "18", "v18", "vmr"); -// powerpc_vsx-LABEL: vreg_f32_v18: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 18, 18 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f32_v18: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 18, 18 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_f32_v18: +// vsx: #APP +// vsx: vmr 18, 18 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vreg_f32_v18, f32, "18", "v18", "vmr"); -// powerpc_vsx-LABEL: vreg_f64_v18: -// powerpc_vsx: #APP -// powerpc_vsx: vmr 18, 18 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vreg_f64_v18: -// powerpc64_vsx: #APP -// powerpc64_vsx: vmr 18, 18 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vreg_f64_v18: +// vsx: #APP +// vsx: vmr 18, 18 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vreg_f64_v18, f64, "18", "v18", "vmr"); -// powerpc_vsx-LABEL: vsreg_i8x16_vs0: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i8x16_vs0: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i8x16_vs0: +// vsx: #APP +// vsx: xvsqrtdp 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_i8x16_vs0, i8x16, "0", "vs0", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_i16x8_vs0: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i16x8_vs0: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i16x8_vs0: +// vsx: #APP +// vsx: xvsqrtdp 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_i16x8_vs0, i16x8, "0", "vs0", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_i32x4_vs0: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i32x4_vs0: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i32x4_vs0: +// vsx: #APP +// vsx: xvsqrtdp 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_i32x4_vs0, i32x4, "0", "vs0", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_i64x2_vs0: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i64x2_vs0: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i64x2_vs0: +// vsx: #APP +// vsx: xvsqrtdp 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_i64x2_vs0, i64x2, "0", "vs0", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f32x4_vs0: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f32x4_vs0: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f32x4_vs0: +// vsx: #APP +// vsx: xvsqrtdp 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_f32x4_vs0, f32x4, "0", "vs0", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f64x2_vs0: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f64x2_vs0: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f64x2_vs0: +// vsx: #APP +// vsx: xvsqrtdp 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_f64x2_vs0, f64x2, "0", "vs0", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f32_vs0: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f32_vs0: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f32_vs0: +// vsx: #APP +// vsx: xvsqrtdp 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_f32_vs0, f32, "0", "vs0", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f64_vs0: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 0, 0 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f64_vs0: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 0, 0 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f64_vs0: +// vsx: #APP +// vsx: xvsqrtdp 0, 0 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_f64_vs0, f64, "0", "vs0", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_i8x16_v40: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 40, 40 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i8x16_v40: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 40, 40 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i8x16_v40: +// vsx: #APP +// vsx: xvsqrtdp 40, 40 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_i8x16_v40, i8x16, "40", "vs40", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_i16x8_v40: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 40, 40 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i16x8_v40: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 40, 40 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i16x8_v40: +// vsx: #APP +// vsx: xvsqrtdp 40, 40 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_i16x8_v40, i16x8, "40", "vs40", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_i32x4_v40: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 40, 40 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i32x4_v40: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 40, 40 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i32x4_v40: +// vsx: #APP +// vsx: xvsqrtdp 40, 40 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_i32x4_v40, i32x4, "40", "vs40", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_i64x2_v40: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 40, 40 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_i64x2_v40: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 40, 40 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_i64x2_v40: +// vsx: #APP +// vsx: xvsqrtdp 40, 40 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_i64x2_v40, i64x2, "40", "vs40", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f32x4_v40: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 40, 40 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f32x4_v40: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 40, 40 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f32x4_v40: +// vsx: #APP +// vsx: xvsqrtdp 40, 40 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_f32x4_v40, f32x4, "40", "vs40", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f64x2_v40: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 40, 40 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f64x2_v40: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 40, 40 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f64x2_v40: +// vsx: #APP +// vsx: xvsqrtdp 40, 40 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_f64x2_v40, f64x2, "40", "vs40", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f32_v40: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 40, 40 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f32_v40: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 40, 40 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f32_v40: +// vsx: #APP +// vsx: xvsqrtdp 40, 40 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_f32_v40, f32, "40", "vs40", "xvsqrtdp"); -// powerpc_vsx-LABEL: vsreg_f64_v40: -// powerpc_vsx: #APP -// powerpc_vsx: xvsqrtdp 40, 40 -// powerpc_vsx: #NO_APP -// powerpc64_vsx-LABEL: vsreg_f64_v40: -// powerpc64_vsx: #APP -// powerpc64_vsx: xvsqrtdp 40, 40 -// powerpc64_vsx: #NO_APP +// vsx-LABEL: vsreg_f64_v40: +// vsx: #APP +// vsx: xvsqrtdp 40, 40 +// vsx: #NO_APP #[cfg(vsx)] check_reg!(vsreg_f64_v40, f64, "40", "vs40", "xvsqrtdp"); From a669f67baa9374bf5662941e6d05b2fe43b3dd5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Aug 2026 14:56:34 +0200 Subject: [PATCH 25/98] derive(Diagnostic): #[note] etc also work on bool fields --- .../rustc-dev-guide/src/diagnostics/diagnostic-structs.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md index 9631ccc083243..6a450909eb8a4 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md @@ -135,12 +135,12 @@ tcx.dcx().emit_err(FieldAlreadyDeclared { - `code = "..."` (_Optional_) - Specifies the error code. - `#[note("message")]` (_Optional_) - - _Applied to struct or struct fields of type `Span`, `Option<()>` or `()`._ + - _Applied to struct or struct fields of type `Span`, `Option<()>`, `bool`, or `()`._ - Adds a note subdiagnostic. - Value is the note's message. - If applied to a `Span` field, creates a spanned note. - `#[help("message")]` (_Optional_) - - _Applied to struct or struct fields of type `Span`, `Option<()>` or `()`._ + - _Applied to struct or struct fields of type `Span`, `Option<()>`, `bool`, or `()`._ - Adds a help subdiagnostic. - Value is the help message. - If applied to a `Span` field, creates a spanned help. @@ -149,7 +149,7 @@ tcx.dcx().emit_err(FieldAlreadyDeclared { - Adds a label subdiagnostic. - Value is the label's message. - `#[warning("message")]` (_Optional_) - - _Applied to struct or struct fields of type `Span`, `Option<()>` or `()`._ + - _Applied to struct or struct fields of type `Span`, `Option<()>`, `bool`, or `()`._ - Adds a warning subdiagnostic. - Value is the warning's message. - `#[suggestion{,_hidden,_short,_verbose}("message", code = "...", applicability = "...")]` From 4ee0e67145e4d7f188f1dcf5f37f02eaf90a0d8b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 6 Aug 2026 20:49:44 +0200 Subject: [PATCH 26/98] remove derives from SVE macros they projected into a scalable vector, which hits assertions --- library/stdarch/crates/core_arch/src/aarch64/sve/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/aarch64/sve/mod.rs b/library/stdarch/crates/core_arch/src/aarch64/sve/mod.rs index f11ca660b15e2..41fd12d3517b4 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/sve/mod.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/sve/mod.rs @@ -39,7 +39,7 @@ impl SveInto for T { macro_rules! impl_sve_type { ($(($v:vis, $elem_type:ty, $name:ident, $elt:literal))*) => ($( #[doc = concat!("Scalable vector of type ", stringify!($elem_type))] - #[derive(Clone, Copy, Debug)] + #[derive(Clone, Copy)] #[rustc_scalable_vector($elt)] #[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] $v struct $name($elem_type); @@ -52,21 +52,21 @@ macro_rules! impl_sve_tuple_type { )*); (@ ($v:vis, $vec_type:ty, 2, $name:ident)) => ( #[doc = concat!("Two-element tuple of scalable vectors of type ", stringify!($vec_type))] - #[derive(Clone, Copy, Debug)] + #[derive(Clone, Copy)] #[rustc_scalable_vector] #[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] $v struct $name($vec_type, $vec_type); ); (@ ($v:vis, $vec_type:ty, 3, $name:ident)) => ( #[doc = concat!("Three-element tuple of scalable vectors of type ", stringify!($vec_type))] - #[derive(Clone, Copy, Debug)] + #[derive(Clone, Copy)] #[rustc_scalable_vector] #[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] $v struct $name($vec_type, $vec_type, $vec_type); ); (@ ($v:vis, $vec_type:ty, 4, $name:ident)) => ( #[doc = concat!("Four-element tuple of scalable vectors of type ", stringify!($vec_type))] - #[derive(Clone, Copy, Debug)] + #[derive(Clone, Copy)] #[rustc_scalable_vector] #[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] $v struct $name($vec_type, $vec_type, $vec_type, $vec_type); From 909d6010afe468ca90631219f4d16d4b659b110a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 5 Aug 2026 12:29:26 +0200 Subject: [PATCH 27/98] forward rustflags to rustdoc --- library/stdarch/ci/dox.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/library/stdarch/ci/dox.sh b/library/stdarch/ci/dox.sh index 9803f7e371119..d65192688f81a 100755 --- a/library/stdarch/ci/dox.sh +++ b/library/stdarch/ci/dox.sh @@ -22,6 +22,7 @@ dox() { export CARGO_UNSTABLE_BUILD_STD=core # amdgpu needs a target-cpu, any is fine export RUSTFLAGS="${RUSTFLAGS} -Ctarget-cpu=gfx900" + export RUSTDOCFLAGS="${RUSTDOCFLAGS} -Ctarget-cpu=gfx900" fi cargo build --verbose --target "${1}" --manifest-path crates/core_arch/Cargo.toml From 32deaa20e8785b1fb5b9a6c58993d4031efe0f4e Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 6 Aug 2026 14:14:00 +0100 Subject: [PATCH 28/98] Fix wasm CI --- library/stdarch/crates/core_arch/src/wasm32/simd128.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch/crates/core_arch/src/wasm32/simd128.rs b/library/stdarch/crates/core_arch/src/wasm32/simd128.rs index e1a3754965907..b52702f44e622 100644 --- a/library/stdarch/crates/core_arch/src/wasm32/simd128.rs +++ b/library/stdarch/crates/core_arch/src/wasm32/simd128.rs @@ -4323,7 +4323,7 @@ mod tests { let vec = i64x2_load_extend_i32x2(arr.as_ptr()); compare_bytes(vec, i64x2(-1, 1)); let vec = i64x2_load_extend_u32x2(arr.as_ptr() as *const u32); - compare_bytes(vec, i64x2(u32::max_value().into(), 1)); + compare_bytes(vec, i64x2(u32::MAX.into(), 1)); } } From dc0c3cb306c6461b31de5b1ffd1f56a0aa09d900 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 6 Aug 2026 15:25:17 +0100 Subject: [PATCH 29/98] Point wasmtime into the new build-dir layout --- library/stdarch/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch/ci/run.sh b/library/stdarch/ci/run.sh index ea012b42f983b..8c75df6afbe4f 100755 --- a/library/stdarch/ci/run.sh +++ b/library/stdarch/ci/run.sh @@ -82,7 +82,7 @@ cargo_test() { else dir="debug" fi - export CARGO_TARGET_WASM32_WASIP1_RUNNER="wasmtime -Wexceptions --dir /checkout/target/wasm32-wasip1/$dir/deps::." + export CARGO_TARGET_WASM32_WASIP1_RUNNER="wasmtime -Wexceptions --dir /checkout/target/wasm32-wasip1/$dir/build::." cmd="$cmd --nocapture" ;; esac From ad73022fb33d112e5fa4ba531f4f677339c06a39 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 6 Aug 2026 16:35:15 +0100 Subject: [PATCH 30/98] Fix stdarch-test wasm disassembly for the new deps layout --- .../stdarch/crates/stdarch-test/src/wasm.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/stdarch/crates/stdarch-test/src/wasm.rs b/library/stdarch/crates/stdarch-test/src/wasm.rs index bf411c12148e2..feadaa1215980 100644 --- a/library/stdarch/crates/stdarch-test/src/wasm.rs +++ b/library/stdarch/crates/stdarch-test/src/wasm.rs @@ -2,6 +2,7 @@ use crate::Function; use std::collections::HashSet; +use std::path::Path; pub(crate) fn disassemble_myself() -> HashSet { // Use `std::env::args` to find the path to our executable. Assume the @@ -11,6 +12,27 @@ pub(crate) fn disassemble_myself() -> HashSet { let me = std::env::args() .next() .expect("failed to find current wasm file"); + let me = Path::new(&me); + let me = if me.exists() { + // Old build-dir layout + me.to_path_buf() + } else { + // Cargo's build-dir layout stores an artifact named + // `-.wasm` at `//out/-.wasm`. + // The build directory is mounted as the WASI working directory, so + // reconstruct that guest-visible path from the executable name. + let file_name = me + .file_name() + .and_then(|name| name.to_str()) + .expect("current wasm file has a file name"); + let stem = file_name + .strip_suffix(".wasm") + .expect("current wasm file does not have a .wasm extension"); + let (crate_name, hash) = stem + .rsplit_once('-') + .expect("current wasm file name does not contain an artifact hash"); + Path::new(crate_name).join(hash).join("out").join(file_name) + }; let output = wasmprinter::print_file(&me).unwrap(); let mut ret: HashSet = HashSet::new(); From cf87891ce9c59051f89bcef33af04e0d6a26621e Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 6 Aug 2026 15:44:30 +0100 Subject: [PATCH 31/98] Speculative x86_64-pc-windows-msvc fix --- library/stdarch/crates/core_arch/src/x86/sse2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch/crates/core_arch/src/x86/sse2.rs b/library/stdarch/crates/core_arch/src/x86/sse2.rs index 5e8fe959c301a..66ebec22e11de 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse2.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse2.rs @@ -3332,7 +3332,7 @@ mod tests { core_arch::{simd::*, x86::*}, hint::black_box, }; - use std::{boxed, f32, f64, mem, ptr}; + use std::{boxed, mem, ptr}; use stdarch_test::simd_test; const NAN: f64 = f64::NAN; From b0a00236fa7f4537616a8d6897de84d32d4ef641 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 7 Aug 2026 13:17:14 +0200 Subject: [PATCH 32/98] amdgpu doc comment fix --- library/stdarch/crates/core_arch/src/amdgpu/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/stdarch/crates/core_arch/src/amdgpu/mod.rs b/library/stdarch/crates/core_arch/src/amdgpu/mod.rs index 374f582696947..264240c505c3e 100644 --- a/library/stdarch/crates/core_arch/src/amdgpu/mod.rs +++ b/library/stdarch/crates/core_arch/src/amdgpu/mod.rs @@ -360,6 +360,7 @@ pub unsafe fn sched_barrier() { /// sched_group_barrier::<8, 5, 0>() /// ``` /// +#[doc(cfg(target_arch = "amdgpu"))] #[doc = include_str!("intrinsic_is_convergent.md")] #[inline] #[unstable(feature = "stdarch_amdgpu", issue = "149988")] From 11114b41bd5c3c0d9c1bf787a3b8cf305141e354 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 7 Aug 2026 13:26:05 +0200 Subject: [PATCH 33/98] use doc(cfg) on some x86 types with examples --- library/stdarch/crates/core_arch/src/x86/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/stdarch/crates/core_arch/src/x86/mod.rs b/library/stdarch/crates/core_arch/src/x86/mod.rs index fbf1002eab8ba..fb6ecd36162d7 100644 --- a/library/stdarch/crates/core_arch/src/x86/mod.rs +++ b/library/stdarch/crates/core_arch/src/x86/mod.rs @@ -40,6 +40,7 @@ types! { /// # Examples /// /// ``` + /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] @@ -56,6 +57,7 @@ types! { /// # if is_x86_feature_detected!("sse2") { unsafe { foo() } } /// # } /// ``` + #[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))] pub struct __m128i(2 x i64); /// 128-bit wide set of four `f32` types, x86-specific @@ -83,6 +85,7 @@ types! { /// # Examples /// /// ``` + /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] @@ -99,6 +102,7 @@ types! { /// # if is_x86_feature_detected!("sse") { unsafe { foo() } } /// # } /// ``` + #[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))] pub struct __m128(4 x f32); /// 128-bit wide set of two `f64` types, x86-specific @@ -126,6 +130,7 @@ types! { /// # Examples /// /// ``` + /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] @@ -142,6 +147,7 @@ types! { /// # if is_x86_feature_detected!("sse2") { unsafe { foo() } } /// # } /// ``` + #[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))] pub struct __m128d(2 x f64); /// 256-bit wide integer vector type, x86-specific @@ -173,6 +179,7 @@ types! { /// # Examples /// /// ``` + /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] @@ -189,6 +196,7 @@ types! { /// # if is_x86_feature_detected!("avx") { unsafe { foo() } } /// # } /// ``` + #[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))] pub struct __m256i(4 x i64); /// 256-bit wide set of eight `f32` types, x86-specific @@ -216,6 +224,7 @@ types! { /// # Examples /// /// ``` + /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] @@ -232,6 +241,7 @@ types! { /// # if is_x86_feature_detected!("avx") { unsafe { foo() } } /// # } /// ``` + #[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))] pub struct __m256(8 x f32); /// 256-bit wide set of four `f64` types, x86-specific @@ -259,6 +269,7 @@ types! { /// # Examples /// /// ``` + /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] @@ -275,6 +286,7 @@ types! { /// # if is_x86_feature_detected!("avx") { unsafe { foo() } } /// # } /// ``` + #[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))] pub struct __m256d(4 x f64); } From 2a018f4dce2bfe6d3391dd6fa3e97fd3dca2cba4 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 9 Aug 2026 14:08:59 +0200 Subject: [PATCH 34/98] ignore example code blocks on nvptx and amdgpu --- library/stdarch/crates/core_arch/src/amdgpu/mod.rs | 8 ++++---- library/stdarch/crates/core_arch/src/nvptx/mod.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/amdgpu/mod.rs b/library/stdarch/crates/core_arch/src/amdgpu/mod.rs index 264240c505c3e..856fb840aa7dd 100644 --- a/library/stdarch/crates/core_arch/src/amdgpu/mod.rs +++ b/library/stdarch/crates/core_arch/src/amdgpu/mod.rs @@ -351,13 +351,13 @@ pub unsafe fn sched_barrier() { /// Combining multiple `sched_group_barrier` intrinsics enables an ordering of specific instruction types during instruction scheduling. /// For example, the following enforces a sequence of 1 VMEM read, followed by 1 VALU instruction, followed by 5 MFMA instructions. /// -/// ```rust +/// ```ignore /// // 1 VMEM read -/// sched_group_barrier::<32, 1, 0>() +/// sched_group_barrier::<32, 1, 0>(); /// // 1 VALU -/// sched_group_barrier::<2, 1, 0>() +/// sched_group_barrier::<2, 1, 0>(); /// // 5 MFMA -/// sched_group_barrier::<8, 5, 0>() +/// sched_group_barrier::<8, 5, 0>(); /// ``` /// #[doc(cfg(target_arch = "amdgpu"))] diff --git a/library/stdarch/crates/core_arch/src/nvptx/mod.rs b/library/stdarch/crates/core_arch/src/nvptx/mod.rs index d22f3a25bf70e..df682b6c6e4aa 100644 --- a/library/stdarch/crates/core_arch/src/nvptx/mod.rs +++ b/library/stdarch/crates/core_arch/src/nvptx/mod.rs @@ -157,7 +157,7 @@ unsafe extern "C" { /// * `format`: A pointer to the format specifier input (uses common `printf` format). /// * `valist`: A pointer to the valist input. /// - /// ``` + /// ```ignore /// #[repr(C)] /// struct PrintArgs(f32, f32, f32, i32); /// From 64f0b1fe96203bd0ba4dc84c66aa3fbd5534e7c6 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 9 Aug 2026 14:14:13 +0200 Subject: [PATCH 35/98] use cfg to only compile/run x86 examples on x86 --- .../stdarch/crates/core_arch/src/x86/mod.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/x86/mod.rs b/library/stdarch/crates/core_arch/src/x86/mod.rs index fb6ecd36162d7..e6875a628fbf0 100644 --- a/library/stdarch/crates/core_arch/src/x86/mod.rs +++ b/library/stdarch/crates/core_arch/src/x86/mod.rs @@ -40,13 +40,12 @@ types! { /// # Examples /// /// ``` - /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] /// use std::arch::x86_64::*; /// - /// # fn main() { /// # #[target_feature(enable = "sse2")] /// # #[allow(unused_unsafe)] // temporary, to unstick CI /// # unsafe fn foo() { unsafe { @@ -85,13 +84,12 @@ types! { /// # Examples /// /// ``` - /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] /// use std::arch::x86_64::*; /// - /// # fn main() { /// # #[target_feature(enable = "sse")] /// # #[allow(unused_unsafe)] // temporary, to unstick CI /// # unsafe fn foo() { unsafe { @@ -130,13 +128,12 @@ types! { /// # Examples /// /// ``` - /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] /// use std::arch::x86_64::*; /// - /// # fn main() { /// # #[target_feature(enable = "sse2")] /// # #[allow(unused_unsafe)] // temporary, to unstick CI /// # unsafe fn foo() { unsafe { @@ -179,13 +176,12 @@ types! { /// # Examples /// /// ``` - /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] /// use std::arch::x86_64::*; /// - /// # fn main() { /// # #[target_feature(enable = "avx")] /// # #[allow(unused_unsafe)] // temporary, to unstick CI /// # unsafe fn foo() { unsafe { @@ -224,13 +220,12 @@ types! { /// # Examples /// /// ``` - /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] /// use std::arch::x86_64::*; /// - /// # fn main() { /// # #[target_feature(enable = "avx")] /// # #[allow(unused_unsafe)] // temporary, to unstick CI /// # unsafe fn foo() { unsafe { @@ -269,13 +264,12 @@ types! { /// # Examples /// /// ``` - /// #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { /// #[cfg(target_arch = "x86")] /// use std::arch::x86::*; /// #[cfg(target_arch = "x86_64")] /// use std::arch::x86_64::*; /// - /// # fn main() { /// # #[target_feature(enable = "avx")] /// # #[allow(unused_unsafe)] // temporary, to unstick CI /// # unsafe fn foo() { unsafe { From f4d4ee74899e5ae79f4a103be9ec4dcfac3a179e Mon Sep 17 00:00:00 2001 From: Nia Deckers Date: Thu, 4 Jun 2026 13:45:31 +0200 Subject: [PATCH 36/98] allocator: refactor for stabilisation yk what we can do btree later raaaaagh pain and suffering *unleaks your box* whats thiSegmentation fault (core dumped) straight up testing it. and by it, well, let's just say. "my allocator" linked and listed the unnecesary bits? gone. reduced to atoms --- library/alloc/src/alloc.rs | 6 + library/alloc/src/boxed.rs | 30 +-- library/alloc/src/boxed/convert.rs | 4 +- library/alloc/src/collections/linked_list.rs | 24 ++- library/alloc/src/rc.rs | 27 +-- library/alloc/src/str.rs | 12 ++ library/alloc/src/sync.rs | 29 +-- library/alloctests/tests/arc.rs | 45 ----- library/alloctests/tests/boxed.rs | 7 - library/core/src/alloc/mod.rs | 173 +++++++++++------- library/std/src/alloc.rs | 6 + tests/ui/allocator/156920-allocator-clone.rs | 23 +++ .../allocator/156920-allocator-clone.stderr | 17 ++ tests/ui/allocator/157089-box-pin-in.rs | 20 ++ tests/ui/allocator/157089-box-pin-in.stderr | 29 +++ tests/ui/allocator/159445-unsize-pin-box.rs | 27 +++ .../ui/allocator/159445-unsize-pin-box.stderr | 27 +++ tests/ui/box/leak-alloc.rs | 2 +- tests/ui/box/leak-alloc.stderr | 8 +- 19 files changed, 337 insertions(+), 179 deletions(-) create mode 100644 tests/ui/allocator/156920-allocator-clone.rs create mode 100644 tests/ui/allocator/156920-allocator-clone.stderr create mode 100644 tests/ui/allocator/157089-box-pin-in.rs create mode 100644 tests/ui/allocator/157089-box-pin-in.stderr create mode 100644 tests/ui/allocator/159445-unsize-pin-box.rs create mode 100644 tests/ui/allocator/159445-unsize-pin-box.stderr diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 49bf941984af5..c0d7d8b605227 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -58,6 +58,12 @@ unsafe extern "Rust" { #[lang = "global_alloc_ty"] pub struct Global; +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl core::alloc::AllocatorClone for Global {} + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl core::alloc::StaticAllocator for Global {} + /// Allocates memory with the global allocator. /// /// This function forwards calls to the [`GlobalAlloc::alloc`] method diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index cd2508a76a10e..bf91ac9dc3e74 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -206,10 +206,10 @@ use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; -use crate::alloc::{AllocError, Allocator, Global, Layout}; +use crate::alloc::{AllocError, Allocator, Global, Layout, StaticAllocator}; use crate::raw_vec::RawVec; #[cfg(not(no_global_oom_handling))] -use crate::str::from_boxed_utf8_unchecked; +use crate::str::from_boxed_utf8_unchecked_in; /// Conversion related impls for `Box<_>` (`From`, `downcast`, etc) mod convert; @@ -715,7 +715,7 @@ impl Box { #[inline(always)] pub fn pin_in(x: T, alloc: A) -> Pin where - A: 'static + Allocator, + A: StaticAllocator, { Self::into_pin(Self::new_in(x, alloc)) } @@ -1897,11 +1897,12 @@ impl Box { /// `'static`. /// /// This function is mainly useful for data that lives for the remainder of the program's life, - /// i.e., memory that is meant to leak. Reconstructing ("unleaking") a `Box` from the mutable - /// reference returned here (e.g. via [`Box::from_raw`]) is a grey area (meaning it is possible - /// under specific circumstances but many seemingly harmless ways of doing it are undefined - /// behavior) and should be avoided. If the memory should eventually be freed, prefer to use - /// [`Box::into_raw`] or [`Box::into_non_null`] instead. + /// i.e., memory that is meant to leak. If the memory should eventually be freed, prefer to use + /// [`Box::into_raw`] or [`Box::into_non_null`] instead. Reconstructing ("unleaking") a `Box` from + /// the mutable reference returned here (e.g. via [`Box::from_raw`]) is only possible if the + /// allocator is `Global`, and even then it is a grey area (meaning it is possible under specific + /// circumstances but many seemingly harmless ways of doing it are undefined behavior) and should + /// be avoided. /// /// Note: this is an associated function, which means that you have /// to call it as `Box::leak(b)` instead of `b.leak()`. This @@ -1976,7 +1977,7 @@ impl Box { #[stable(feature = "box_into_pin", since = "1.63.0")] pub fn into_pin(boxed: Self) -> Pin where - A: 'static, + A: StaticAllocator, { // It's not possible to move or replace the insides of a `Pin>` // when `T: !Unpin`, so it's safe to pin it directly without any @@ -2065,6 +2066,8 @@ where #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] +// NB: This is not `AllocatorClone` since we don't care about allocator +// equivalence when cloning boxes. impl Clone for Box { /// Returns a new box with a `clone()` of this box's contents. /// @@ -2150,11 +2153,10 @@ impl Clone for Box<[T], A> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_slice_clone", since = "1.3.0")] -impl Clone for Box { +impl Clone for Box { fn clone(&self) -> Self { - // this makes a copy of the data - let buf: Box<[u8]> = self.as_bytes().into(); - unsafe { from_boxed_utf8_unchecked(buf) } + let buf = Box::clone_from_ref_in(self.as_bytes(), self.1.clone()); + unsafe { from_boxed_utf8_unchecked_in(buf) } } } @@ -2385,7 +2387,7 @@ impl, U: ?Sized, A: Allocator> CoerceUnsized> fo // wrapped in `Pin`, since the same conversion could have been carried out // safely as `Box::pin((*p).clone())`. #[unstable(feature = "pin_coerce_unsized_trait", issue = "150112")] -unsafe impl PinSafePointer for Box {} +unsafe impl PinSafePointer for Box {} // It is quite crucial that we only allow the `Global` allocator here. // Handling arbitrary custom allocators (which can affect the `Box` layout heavily!) diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs index d6a8e78991b84..4f5dd89e6e3b3 100644 --- a/library/alloc/src/boxed/convert.rs +++ b/library/alloc/src/boxed/convert.rs @@ -5,7 +5,7 @@ use core::fmt; use core::mem; use core::pin::Pin; -use crate::alloc::Allocator; +use crate::alloc::{Allocator, StaticAllocator}; #[cfg(not(no_global_oom_handling))] use crate::borrow::Cow; use crate::boxed::Box; @@ -38,7 +38,7 @@ impl From for Box { #[stable(feature = "pin", since = "1.33.0")] impl From> for Pin> where - A: 'static, + A: StaticAllocator, { /// Converts a `Box` into a `Pin>`. If `T` does not implement [`Unpin`], then /// `*boxed` will be pinned in memory and unable to be moved. diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index ca3b2eab30402..788609f740d07 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -12,6 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use core::alloc::AllocatorClone; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; @@ -340,7 +341,7 @@ impl LinkedList { at: usize, ) -> Self where - A: Clone, + A: AllocatorClone, { // The split node is the new head node of the second part if let Some(mut split_node) = split_node { @@ -383,7 +384,7 @@ impl LinkedList { at: usize, ) -> Self where - A: Clone, + A: AllocatorClone, { // The split node is the new tail node of the first part and owns // the head of the second part. @@ -994,7 +995,7 @@ impl LinkedList { #[stable(feature = "rust1", since = "1.0.0")] pub fn split_off(&mut self, at: usize) -> LinkedList where - A: Clone, + A: AllocatorClone, { let len = self.len(); assert!(at <= len, "Cannot split off at a nonexistent index"); @@ -1748,7 +1749,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn remove_current_as_list(&mut self) -> Option> where - A: Clone, + A: AllocatorClone, { let mut unlinked_node = self.current?; unsafe { @@ -1776,7 +1777,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn split_after(&mut self) -> LinkedList where - A: Clone, + A: AllocatorClone, { let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 }; if self.index == self.list.len { @@ -1795,7 +1796,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn split_before(&mut self) -> LinkedList where - A: Clone, + A: AllocatorClone, { let split_off_idx = self.index; self.index = 0; @@ -2167,12 +2168,15 @@ impl Clone for LinkedList { /// resources of `self`'s elements as well. fn clone_from(&mut self, source: &Self) { let mut source_iter = source.iter(); - if self.len() > source.len() { - self.split_off(source.len()); - } - for (elem, source_elem) in self.iter_mut().zip(&mut source_iter) { + for elem in self.iter_mut() { + let Some(source_elem) = source_iter.next() else { + break; + }; elem.clone_from(source_elem); } + while self.len() > source.len() { + self.pop_back(); + } if !source_iter.is_empty() { self.extend(source_iter.cloned()); } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 4629a0b500107..ebde6bb02f369 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -268,7 +268,7 @@ use core::{borrow, fmt, hint}; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; -use crate::alloc::{AllocError, Allocator, Global, Layout}; +use crate::alloc::{AllocError, Allocator, AllocatorClone, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; #[cfg(not(no_global_oom_handling))] @@ -1775,7 +1775,7 @@ impl Rc { #[stable(feature = "rc_weak", since = "1.4.0")] pub fn downgrade(this: &Self) -> Weak where - A: Clone, + A: AllocatorClone, { this.inner().inc_weak(); // Make sure we do not create a dangling Weak @@ -1856,7 +1856,7 @@ impl Rc { #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn increment_strong_count_in(ptr: *const T, alloc: A) where - A: Clone, + A: AllocatorClone, { // Retain Rc, but don't touch refcount by wrapping in ManuallyDrop let rc = unsafe { mem::ManuallyDrop::new(Rc::::from_raw_in(ptr, alloc)) }; @@ -2032,7 +2032,7 @@ impl Rc { } #[cfg(not(no_global_oom_handling))] -impl Rc { +impl Rc { /// Makes a mutable reference into the given `Rc`. /// /// If there are other `Rc` pointers to the same allocation, then `make_mut` will @@ -2313,7 +2313,7 @@ impl Rc { // Free the allocation without dropping its contents let (bptr, alloc) = Box::into_raw_with_allocator(src); - let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, alloc.by_ref()); + let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, &alloc); drop(src); Self::from_ptr_in(ptr, alloc) @@ -2509,7 +2509,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Rc { +impl Clone for Rc { /// Makes a clone of the `Rc` pointer. /// /// This creates another pointer to the same allocation, increasing the @@ -2534,10 +2534,10 @@ impl Clone for Rc { } #[unstable(feature = "ergonomic_clones", issue = "132290")] -impl UseCloned for Rc {} +impl UseCloned for Rc {} #[unstable(feature = "share_trait", issue = "156756")] -impl Share for Rc {} +impl Share for Rc {} #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] @@ -3558,7 +3558,7 @@ impl Weak { #[stable(feature = "rc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> where - A: Clone, + A: AllocatorClone, { let inner = self.inner()?; @@ -3703,7 +3703,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Weak { } #[stable(feature = "rc_weak", since = "1.4.0")] -impl Clone for Weak { +impl Clone for Weak { /// Makes a clone of the `Weak` pointer that points to the same allocation. /// /// # Examples @@ -3725,7 +3725,7 @@ impl Clone for Weak { } #[unstable(feature = "ergonomic_clones", issue = "132290")] -impl UseCloned for Weak {} +impl UseCloned for Weak {} #[stable(feature = "rc_weak", since = "1.4.0")] impl fmt::Debug for Weak { @@ -4425,7 +4425,7 @@ impl UniqueRc { } } -impl UniqueRc { +impl UniqueRc { /// Creates a new weak reference to the `UniqueRc`. /// /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted @@ -4614,3 +4614,6 @@ unsafe impl Allocator for Rc { unsafe { (**self).shrink(ptr, old_layout, new_layout) } } } + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl AllocatorClone for Rc {} diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index ee9e82368899f..a24cca9cd56f8 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -906,6 +906,18 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { unsafe { Box::from_raw(Box::into_raw(v) as *mut str) } } +/// Internal; same as `from_boxed_utf8_unchecked` but allocator-generic. Name +/// probably not suitable for being made `pub` as-is. +#[must_use] +#[inline] +#[cfg(not(no_global_oom_handling))] +pub(crate) unsafe fn from_boxed_utf8_unchecked_in( + v: Box<[u8], A>, +) -> Box { + let (ptr, alloc) = Box::into_raw_with_allocator(v); + unsafe { Box::from_raw_in(ptr as *mut str, alloc) } +} + /// Converts leading ascii bytes in `s` by calling the `convert` function. /// /// For better average performance, this happens in chunks of `2*size_of::()`. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 18fc19cba27d1..8505442382185 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -35,7 +35,7 @@ use core::{borrow, fmt, hint}; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; -use crate::alloc::{AllocError, Allocator, Global, Layout}; +use crate::alloc::{AllocError, Allocator, AllocatorClone, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::is_dangling; @@ -1939,7 +1939,7 @@ impl Arc { #[stable(feature = "arc_weak", since = "1.4.0")] pub fn downgrade(this: &Self) -> Weak where - A: Clone, + A: AllocatorClone, { // This Relaxed is OK because we're checking the value in the CAS // below. @@ -2070,7 +2070,7 @@ impl Arc { #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn increment_strong_count_in(ptr: *const T, alloc: A) where - A: Clone, + A: AllocatorClone, { // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop let arc = unsafe { mem::ManuallyDrop::new(Arc::from_raw_in(ptr, alloc)) }; @@ -2258,7 +2258,7 @@ impl Arc { // Free the allocation without dropping its contents let (bptr, alloc) = Box::into_raw_with_allocator(src); - let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, alloc.by_ref()); + let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop, &alloc); drop(src); Self::from_ptr_in(ptr, alloc) @@ -2384,7 +2384,7 @@ impl ArcFromSlice for Arc<[T]> { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Arc { +impl Clone for Arc { /// Makes a clone of the `Arc` pointer. /// /// This creates another pointer to the same allocation, increasing the @@ -2438,10 +2438,10 @@ impl Clone for Arc { } #[unstable(feature = "ergonomic_clones", issue = "132290")] -impl UseCloned for Arc {} +impl UseCloned for Arc {} #[unstable(feature = "share_trait", issue = "156756")] -impl Share for Arc {} +impl Share for Arc {} #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Arc { @@ -2471,7 +2471,7 @@ unsafe impl DerefPure for Arc {} impl LegacyReceiver for Arc {} #[cfg(not(no_global_oom_handling))] -impl Arc { +impl Arc { /// Makes a mutable reference into the given `Arc`. /// /// If there are other `Arc` pointers to the same allocation, then `make_mut` will @@ -3310,7 +3310,7 @@ impl Weak { #[stable(feature = "arc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> where - A: Clone, + A: AllocatorClone, { #[inline] fn checked_increment(n: usize) -> Option { @@ -3445,7 +3445,7 @@ impl Weak { } #[stable(feature = "arc_weak", since = "1.4.0")] -impl Clone for Weak { +impl Clone for Weak { /// Makes a clone of the `Weak` pointer that points to the same allocation. /// /// # Examples @@ -3477,7 +3477,7 @@ impl Clone for Weak { } #[unstable(feature = "ergonomic_clones", issue = "132290")] -impl UseCloned for Weak {} +impl UseCloned for Weak {} #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { @@ -4065,7 +4065,7 @@ impl From> for Arc { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From> for Arc<[T], A> { +impl From> for Arc<[T], A> { /// Allocates a reference-counted slice and moves `v`'s items into it. /// /// # Example @@ -4874,7 +4874,7 @@ impl UniqueArc { } } -impl UniqueArc { +impl UniqueArc { /// Creates a new weak reference to the `UniqueArc`. /// /// Attempting to upgrade this weak reference will fail before the `UniqueArc` has been converted @@ -5003,3 +5003,6 @@ unsafe impl Allocator for Arc { unsafe { (**self).shrink(ptr, old_layout, new_layout) } } } + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl AllocatorClone for Arc {} diff --git a/library/alloctests/tests/arc.rs b/library/alloctests/tests/arc.rs index 3cec3c962ab06..4299fea4120d8 100644 --- a/library/alloctests/tests/arc.rs +++ b/library/alloctests/tests/arc.rs @@ -346,51 +346,6 @@ fn issue_158875_make_mut_dont_leak_allocator() { assert_eq!(Rc::strong_count(&alloc), 1); // if this is >1, we have a memory leak! } -/// Test that `Arc::make_mut` does not cause a UAF if the allocator panics on -/// clone when it steals the data. -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn issue_155746_make_mut_panic_safety() { - use std::alloc::{Allocator, System}; - use std::panic::AssertUnwindSafe; - - #[derive(Default)] - struct PanickingCloneAlloc { - do_panic: Rc>, - } - unsafe impl Allocator for PanickingCloneAlloc { - fn allocate( - &self, - layout: std::alloc::Layout, - ) -> Result, std::alloc::AllocError> { - System.allocate(layout) - } - - unsafe fn deallocate(&self, ptr: std::ptr::NonNull, layout: std::alloc::Layout) { - unsafe { System.deallocate(ptr, layout) } - } - } - impl Clone for PanickingCloneAlloc { - fn clone(&self) -> Self { - if self.do_panic.get() { panic!() } else { Self { do_panic: self.do_panic.clone() } } - } - } - - let alloc = PanickingCloneAlloc::default(); - let mut arc = Arc::new_in(vec![vec![1]], alloc.clone()); - - let _weak = Arc::downgrade(&arc); // create a weak so make_mut steals the data - - alloc.do_panic.set(true); - std::panic::catch_unwind(AssertUnwindSafe(|| { - Arc::make_mut(&mut arc); - })) - .unwrap_err(); - - assert_eq!(*arc, [[1]]); - assert_eq!(Arc::strong_count(&arc), 1); // if this is 0, we have a UAF! -} - #[test] #[should_panic = "capacity overflow"] fn new_uninit_slice_capacity_overflow() { diff --git a/library/alloctests/tests/boxed.rs b/library/alloctests/tests/boxed.rs index c73b7109fb387..74db1c7de31e7 100644 --- a/library/alloctests/tests/boxed.rs +++ b/library/alloctests/tests/boxed.rs @@ -211,13 +211,6 @@ unsafe impl Allocator for ConstAllocator { } Ok(new_ptr) } - - fn by_ref(&self) -> &Self - where - Self: Sized, - { - self - } } #[allow(unused)] diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 339bc310c0b61..7816709ac4663 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -74,7 +74,8 @@ impl fmt::Display for AllocError { /// * Moving, subtyping, unsize-coercing, or trait-upcasting an allocator does not change /// what the allocator is equivalent to. /// * Copying or cloning allocator results in an allocator that's -/// equivalent to the initial allocator. +/// equivalent to the initial allocator, should the [`AllocatorClone`] trait +/// be implemented. /// /// Additionally, implementors of `Allocator` may specify additional equivalences /// between allocators. It is the responsibility of such implementors to make sure @@ -87,12 +88,6 @@ impl fmt::Display for AllocError { /// * All `Global` allocator instances are equivalent with each other. /// * All `System` allocator instances are equivalent with each other. /// -/// Note: Currently, the interaction between cloning and unsize-coercing allocators -/// is unsound, and there is ongoing discussion on how to revise the `Allocator` trait -/// to fix this. See [#156920]. -/// -/// [#156920]: https://github.com/rust-lang/rust/issues/156920 -/// /// ### Currently allocated memory /// /// Some of the methods require that a memory block is *currently allocated* by some specific allocator. @@ -102,8 +97,6 @@ impl fmt::Display for AllocError { /// called on an allocator that's equivalent to this specific allocator; and /// * the memory block has not subsequently been [*invalidated*]. /// -/// [*invalidated*]: #invalidating-memory-blocks -/// /// ### Invalidating memory blocks /// /// A memory block that is currently allocated becomes *invalidated* when one @@ -164,8 +157,8 @@ impl fmt::Display for AllocError { /// is [*currently allocated*] by the allocator points to valid memory, /// until that memory block is [*invalidated*]. The implementor must also /// not violate this invariant of `Allocator` via allocator equivalences -/// that are in the implementor's control (e.g., via a misbehaving -/// `impl Clone for Box`). +/// that are in the implementor's control (e.g., via an incorrect `unsafe +/// impl AllocatorClone for MyAllocator`). /// /// Additionally, any memory block returned by the allocator must /// satisfy the allocation invariants described in `core::ptr`. @@ -175,17 +168,37 @@ impl fmt::Display for AllocError { /// This ensures that pointer arithmetic within the allocation /// (for example, `ptr.add(len)`) cannot overflow the address space. /// +/// None of the allocating or deallocating methods may unwind. This restriction +/// may be lifted in the future by ensuring unwinding out of an allocating function always +/// aborts. If an implementor of `Allocator` also has drop glue or directly implements `Drop`, +/// dropping the allocator must not result in an unwind. +/// +/// Lastly, the methods on this trait must be *correct*; i.e. the layout requested +/// must be respected, calls must zero out memory if the documentation so requires, +/// and returning an `AllocError` from a reallocating method must indeed ensure that +/// the old pointer was not invalidated, and de/reallocating calls must accept layouts +/// in the ranges defined by their documentation. +/// /// [*currently allocated*]: #currently-allocated-memory /// [*invalidated*]: #invalidating-memory-blocks +// NOTE: the above bound on allocating methods not unwinding, alongside the similar +// bound on `AllocatorClone`, are currently load-bearing in std! see the below issues +// and make sure they cannot be triggered before relaxing this: +// https://rust.tf/156490 +// https://rust.tf/159982 #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] pub const unsafe trait Allocator { /// Attempts to allocate a block of memory. /// - /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. + /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment + /// guarantees of `layout`. The returned block may have a larger size than specified + /// by `layout.size()`, and may or may not have its contents initialized. /// - /// The returned block may have a larger size than specified by `layout.size()`, and may or may - /// not have its contents initialized. + /// It is recommended that overallocating as per the above is only performed if doing so + /// is cheap; there is no guarantee that the caller is able to take advantage of the + /// returned excess. Implementors are free to e.g. provide an alternate method to query + /// available excess if doing so is expensive and should be left to the caller. /// /// Note that the returned block of memory is considered [*currently allocated*] /// with this allocator (and equivalent allocators). @@ -200,7 +213,7 @@ pub const unsafe trait Allocator { /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet /// allocator's size or alignment constraints. /// - /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// Implementations are encouraged to return `Err` on memory exhaustion rather than /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// @@ -217,7 +230,7 @@ pub const unsafe trait Allocator { /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet /// allocator's size or alignment constraints. /// - /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// Implementations are encouraged to return `Err` on memory exhaustion rather than /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// @@ -239,6 +252,13 @@ pub const unsafe trait Allocator { /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and /// * `layout` must [*fit*] that block of memory. /// + /// Note that it is *immediate* language UB for a deallocation or reallocation to + /// invalidate any outstanding references, smart pointers, etc.; thus, notably, an + /// allocator that has been moved into its own [*currently allocated*] memory may + /// not have its backing memory be freed, even if the allocator is never used again + /// afterwards. This is due to the fact that such a deallocation would invalidate the + /// `&self` reference passed to this method. + /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting unsafe fn deallocate(&self, ptr: NonNull, layout: Layout); @@ -252,6 +272,7 @@ pub const unsafe trait Allocator { /// If this returns `Ok`, then the memory block referenced by `ptr` has been [*invalidated*]. /// The old `ptr` must not be used to access the memory, even if the allocation was grown in-place. /// The newly returned pointer is the only valid pointer for accessing this memory now. + /// All bytes past `old_layout.size()` should be assumed to be uninitialised. /// /// If this method returns `Err`, then the memory block has not been *invalidated*, /// and the contents of the memory block are unaltered. @@ -273,7 +294,7 @@ pub const unsafe trait Allocator { /// Returns `Err` if the new layout does not meet the allocator's size and alignment /// constraints of the allocator, or if growing otherwise fails. /// - /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// Implementations are encouraged to return `Err` on memory exhaustion rather than /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// @@ -313,12 +334,9 @@ pub const unsafe trait Allocator { /// The memory block will contain the following contents after a successful call to /// `grow_zeroed`: /// * Bytes `0..old_layout.size()` are preserved from the original allocation. - /// * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on - /// the allocator implementation. `old_size` refers to the size of the memory block prior - /// to the `grow_zeroed` call, which may be larger than the size that was originally - /// requested when it was allocated. - /// * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory - /// block returned by the `grow_zeroed` call. + /// * Bytes `old_layout.size()..new_size` are zeroed. `new_size` refers to the size + /// of the memory block returned by the `grow_zeroed` call, which may be larger than + /// `new_layout.size()`. /// /// # Safety /// @@ -336,7 +354,7 @@ pub const unsafe trait Allocator { /// Returns `Err` if the new layout does not meet the allocator's size and alignment /// constraints of the allocator, or if growing otherwise fails. /// - /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// Implementations are encouraged to return `Err` on memory exhaustion rather than /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// @@ -380,6 +398,7 @@ pub const unsafe trait Allocator { /// If this returns `Ok`, then the memory block referenced by `ptr` has been [*invalidated*]. /// The old `ptr` must not be used to access the memory, even if the allocation was shrunk in-place. /// The newly returned pointer is the only valid pointer for accessing this memory now. + /// All bytes past `new_layout.size()` should be assumed to be uninitialised. /// /// If this method returns `Err`, then the memory block has not been *invalidated*, /// and the contents of the memory block are unaltered. @@ -401,7 +420,7 @@ pub const unsafe trait Allocator { /// Returns `Err` if the new layout does not meet the allocator's size and alignment /// constraints of the allocator, or if shrinking otherwise fails. /// - /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// Implementations are encouraged to return `Err` on memory exhaustion rather than /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// @@ -434,17 +453,6 @@ pub const unsafe trait Allocator { Ok(new_ptr) } - - /// Creates a "by reference" adapter for this instance of `Allocator`. - /// - /// The returned adapter also implements `Allocator` and will simply borrow this. - #[inline(always)] - fn by_ref(&self) -> &Self - where - Self: Sized, - { - self - } } /// An [`Allocator`] that can be registered as the standard library’s default @@ -482,40 +490,10 @@ pub const unsafe trait Allocator { /// /// # Safety /// -/// In addition to the safety requirements of `Allocator`, global allocators are -/// subject to some additional constraints: -/// -/// * It's undefined behavior if global allocators unwind. This restriction may -/// be lifted in the future, but currently a panic from any of these -/// functions may lead to memory unsafety. -/// -/// * You must not rely on allocations actually happening, even if there are explicit -/// heap allocations in the source. The optimizer may detect unused allocations that it can either -/// eliminate entirely or move to the stack and thus never invoke the allocator. The -/// optimizer may further assume that allocation is infallible, so code that used to fail due -/// to allocator failures may now suddenly work because the optimizer worked around the -/// need for an allocation. More concretely, the following code example is unsound, irrespective -/// of whether your custom allocator allows counting how many allocations have happened. -/// -/// ```rust,ignore (unsound and has placeholders) -/// drop(Box::new(42)); -/// let number_of_heap_allocs = /* call private allocator API */; -/// unsafe { std::hint::assert_unchecked(number_of_heap_allocs > 0); } -/// ``` -/// -/// Note that the optimizations mentioned above are not the only -/// optimization that can be applied. You may generally not rely on heap allocations -/// happening if they can be removed without changing program behavior. -/// Whether allocations happen or not is not part of the program behavior, even if it -/// could be detected via an allocator that tracks allocations by printing or otherwise -/// having side effects. -/// -/// # Re-entrance -/// -/// When implementing a global allocator, one has to be careful not to create an infinitely recursive -/// implementation by accident, as many constructs in the Rust standard library may allocate in -/// their implementation. For example, on some platforms, [`std::sync::Mutex`] may allocate, so using -/// it is highly problematic in a global allocator. +/// When implementing a global allocator, one has to be careful not to create an infinitely +/// recursive implementation by accident, as many constructs in the Rust standard library may +/// allocate in their implementation. For example, on some platforms, [`std::sync::Mutex`] may +/// allocate, so using it is highly problematic in a global allocator. /// /// For this reason, one should generally stick to library features available through /// [`core`], and avoid using [`std`] in a global allocator. A few features from [`std`] are @@ -535,7 +513,52 @@ pub const unsafe trait Allocator { /// [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark #[unstable(feature = "allocator_api", issue = "32838")] #[expect(multiple_supertrait_upcastable)] -pub unsafe trait GlobalAllocator: Allocator + Sync + 'static {} +pub unsafe trait GlobalAllocator: StaticAllocator + Sync + 'static {} + +/// Marks a type's [`Clone`] implementation as sound with regard to [`Allocator`] equivalence. +/// Implementors must ensure that, upon cloning, the two allocators are equivalent +/// (i.e. it is possible to free memory with one that was allocated with the other). +/// Further, mutable accesses such as moving or dropping the allocator must not invalidate +/// its currently allocated blocks at least so long as clones exist. +/// +/// Additionally, the bound that allocators do not unwind when (de)allocating also applies +/// to guaranteeing allocators will not unwind when cloned. +/// +/// It must also be the case that types which are `AllocatorClone` are either explicitly not +/// copyable (such as by containing a `!Copy` field) or that copying them also respects allocator +/// equivalence as if it had been a clone. +#[unstable(feature = "allocator_api", issue = "32838")] +pub unsafe trait AllocatorClone: Allocator + Clone {} + +/// Marks that an allocator and its supertypes will never invalidate currently allocated +/// memory unless explicitly deallocated via a call to a deallocating method, even if +/// dropped or if the allocator's lifetime expires. +/// +/// This is a necessity in conjunction with [`Pin`], as only allocators that promise +/// memory is never reused without a destructor running may be used to back a pinned pointer. +/// +/// # Safety +/// +/// Implementors must ensure that memory cannot be freed except via a call to +/// `Allocator::deallocate`, and that subtype coercion preserves this invariant. +/// +/// These requirements trivially apply to allocators that always maintain global state, such as +/// `System` or `Global`. However, due to subtype coercion, it is *not* sound to implement +/// for an arbitrary `Allocator + 'static` due to [edge-case interactions][unsound] with +/// `Pin::clone`. Namely, an impl of `StaticAllocator for MyAllocator + 'long` guarantees that an +/// impl of `StaticAllocator for MyAllocator + 'short` would be sound to write. +/// +/// The following must thus be guaranteed: +/// - the `Drop` impl of the allocator does not invalidate any allocations; +/// - the allocator does not expose a safe API surface that allows invalidating +/// its allocations; +/// - the allocator's lifetime expiring does not invalidate any allocations; +/// - the above also hold for all equivalent allocators (see [`Allocator`] docs). +/// +/// [`Pin`]: ../../core/pin/struct.Pin.html +/// [unsound]: https://github.com/rust-lang/rust/issues/157089 +#[unstable(feature = "allocator_api", issue = "32838")] +pub unsafe trait StaticAllocator: Allocator {} #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] @@ -647,3 +670,11 @@ where unsafe { (**self).shrink(ptr, old_layout, new_layout) } } } + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl AllocatorClone for &A {} + +// If an allocator is `StaticAllocator` all equivalent allocators must also uphold +// its semantics, and references are equivalent to the allocator they reference. +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl StaticAllocator for &A {} diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 9d39fbf770e91..558ab0f2fc66d 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -145,6 +145,12 @@ use crate::{hint, mem, ptr}; #[derive_const(Clone, Default)] pub struct System; +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl core::alloc::AllocatorClone for System {} + +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl core::alloc::StaticAllocator for System {} + impl System { #[inline] fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { diff --git a/tests/ui/allocator/156920-allocator-clone.rs b/tests/ui/allocator/156920-allocator-clone.rs new file mode 100644 index 0000000000000..2b9966b68eca8 --- /dev/null +++ b/tests/ui/allocator/156920-allocator-clone.rs @@ -0,0 +1,23 @@ +#![feature(allocator_api)] + +use std::{ + alloc::{Allocator, Global, System}, + sync::Arc, +}; + +pub trait MyAlloc: Allocator {} +impl MyAlloc for A {} + +impl Clone for Box { + fn clone(&self) -> Self { + Box::new(System) + } +} + +fn main() { + let evil_arc: Arc> = Arc::new_in(69420, Box::new(Global)); + // clone() returns `System` instead of `Global`, but `Arc` requires equivalent allocators + // Make sure to not accidentally call <&Arc>::clone here. + let _ = as Clone>::clone(&evil_arc); + //~^ ERROR: the trait bound `Box: AllocatorClone` is not satisfied [E0277] +} diff --git a/tests/ui/allocator/156920-allocator-clone.stderr b/tests/ui/allocator/156920-allocator-clone.stderr new file mode 100644 index 0000000000000..afa202f06af80 --- /dev/null +++ b/tests/ui/allocator/156920-allocator-clone.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `Box: AllocatorClone` is not satisfied + --> $DIR/156920-allocator-clone.rs:21:14 + | +LL | let _ = as Clone>::clone(&evil_arc); + | ^^^^^^^^^ the nightly-only, unstable trait `AllocatorClone` is not implemented for `Box` + | + = help: the following other types implement trait `AllocatorClone`: + &A + Arc + Rc + System + std::alloc::Global + = note: required for `Arc>` to implement `Clone` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/allocator/157089-box-pin-in.rs b/tests/ui/allocator/157089-box-pin-in.rs new file mode 100644 index 0000000000000..307a933bba6f6 --- /dev/null +++ b/tests/ui/allocator/157089-box-pin-in.rs @@ -0,0 +1,20 @@ +#![feature(allocator_api)] + +use std::{ + alloc::{AllocError, Allocator, Layout}, + pin::Pin, + ptr::NonNull, +}; + +struct UntrustedAlloc; +unsafe impl Allocator for UntrustedAlloc { + fn allocate(&self, _: Layout) -> Result, AllocError> { + Err(AllocError) + } + unsafe fn deallocate(&self, _: NonNull, _: Layout) {} +} + +pub fn main() { + let _: Pin> = Box::pin_in(1, UntrustedAlloc); + //~^ ERROR: the trait bound `UntrustedAlloc: StaticAllocator` is not satisfied [E0277] +} diff --git a/tests/ui/allocator/157089-box-pin-in.stderr b/tests/ui/allocator/157089-box-pin-in.stderr new file mode 100644 index 0000000000000..f25736d819a1f --- /dev/null +++ b/tests/ui/allocator/157089-box-pin-in.stderr @@ -0,0 +1,29 @@ +error[E0277]: the trait bound `UntrustedAlloc: StaticAllocator` is not satisfied + --> $DIR/157089-box-pin-in.rs:18:59 + | +LL | let _: Pin> = Box::pin_in(1, UntrustedAlloc); + | ----------- ^^^^^^^^^^^^^^ unsatisfied trait bound + | | + | required by a bound introduced by this call + | +help: the nightly-only, unstable trait `StaticAllocator` is not implemented for `UntrustedAlloc` + --> $DIR/157089-box-pin-in.rs:9:1 + | +LL | struct UntrustedAlloc; + | ^^^^^^^^^^^^^^^^^^^^^ +help: the following other types implement trait `StaticAllocator` + --> $SRC_DIR/core/src/alloc/mod.rs:LL:COL + | + = note: `&A` + --> $SRC_DIR/std/src/alloc.rs:LL:COL + | + = note: `System` + --> $SRC_DIR/alloc/src/alloc.rs:LL:COL + | + = note: `std::alloc::Global` +note: required by a bound in `Box::::pin_in` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/allocator/159445-unsize-pin-box.rs b/tests/ui/allocator/159445-unsize-pin-box.rs new file mode 100644 index 0000000000000..391c8c95813a0 --- /dev/null +++ b/tests/ui/allocator/159445-unsize-pin-box.rs @@ -0,0 +1,27 @@ +#![feature(allocator_api)] + +use std::{ + alloc::{AllocError, Allocator, Layout}, + any::Any, + pin::Pin, + ptr::NonNull, +}; + +struct BadAlloc; +unsafe impl Allocator for BadAlloc { + fn allocate(&self, _: Layout) -> Result, AllocError> { + unimplemented!() + } + unsafe fn deallocate(&self, _: NonNull, _: Layout) { + unimplemented!() + } +} + +fn main() { + // no requirements for the allocator, we are just pinning a `Box` + let base: Pin> = Pin::new(Box::new_in(1i32, BadAlloc)); + + // unsize coercion (must fail) + let _: Pin> = base; + //~^ ERROR: the trait bound `BadAlloc: StaticAllocator` is not satisfied [E0277] +} diff --git a/tests/ui/allocator/159445-unsize-pin-box.stderr b/tests/ui/allocator/159445-unsize-pin-box.stderr new file mode 100644 index 0000000000000..7740591c1b8b0 --- /dev/null +++ b/tests/ui/allocator/159445-unsize-pin-box.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `BadAlloc: StaticAllocator` is not satisfied + --> $DIR/159445-unsize-pin-box.rs:25:42 + | +LL | let _: Pin> = base; + | ^^^^ unsatisfied trait bound + | +help: the nightly-only, unstable trait `StaticAllocator` is not implemented for `BadAlloc` + --> $DIR/159445-unsize-pin-box.rs:10:1 + | +LL | struct BadAlloc; + | ^^^^^^^^^^^^^^^ +help: the following other types implement trait `StaticAllocator` + --> $SRC_DIR/core/src/alloc/mod.rs:LL:COL + | + = note: `&A` + --> $SRC_DIR/std/src/alloc.rs:LL:COL + | + = note: `System` + --> $SRC_DIR/alloc/src/alloc.rs:LL:COL + | + = note: `std::alloc::Global` + = note: required for `Box` to implement `PinCoerceUnsized` + = note: required for the cast from `Pin>` to `Pin>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/box/leak-alloc.rs b/tests/ui/box/leak-alloc.rs index 3f0f39f448b91..e87650f42ab61 100644 --- a/tests/ui/box/leak-alloc.rs +++ b/tests/ui/box/leak-alloc.rs @@ -21,7 +21,7 @@ fn use_value(_: u32) {} fn main() { let alloc = Alloc {}; - let boxed = Box::new_in(10, alloc.by_ref()); + let boxed = Box::new_in(10, &alloc); let theref = Box::leak(boxed); drop(alloc); //~^ ERROR cannot move out of `alloc` because it is borrowed diff --git a/tests/ui/box/leak-alloc.stderr b/tests/ui/box/leak-alloc.stderr index bdaa9449f913e..ad8eb17fd28d0 100644 --- a/tests/ui/box/leak-alloc.stderr +++ b/tests/ui/box/leak-alloc.stderr @@ -3,8 +3,8 @@ error[E0505]: cannot move out of `alloc` because it is borrowed | LL | let alloc = Alloc {}; | ----- binding `alloc` declared here -LL | let boxed = Box::new_in(10, alloc.by_ref()); - | ----- borrow of `alloc` occurs here +LL | let boxed = Box::new_in(10, &alloc); + | ------ borrow of `alloc` occurs here LL | let theref = Box::leak(boxed); LL | drop(alloc); | ^^^^^ move out of `alloc` occurs here @@ -18,8 +18,8 @@ note: if `Alloc` implemented `Clone`, you could clone the value LL | struct Alloc {} | ^^^^^^^^^^^^ consider implementing `Clone` for this type ... -LL | let boxed = Box::new_in(10, alloc.by_ref()); - | ----- you could clone this value +LL | let boxed = Box::new_in(10, &alloc); + | ----- you could clone this value error: aborting due to 1 previous error From 7cab1f0cff8b5d394534da56155f3397f3fa9bf3 Mon Sep 17 00:00:00 2001 From: Nia Deckers Date: Sun, 9 Aug 2026 18:15:20 +0200 Subject: [PATCH 37/98] here's your damn trait name --- tests/ui/allocator/159445-unsize-pin-box.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/allocator/159445-unsize-pin-box.stderr b/tests/ui/allocator/159445-unsize-pin-box.stderr index 7740591c1b8b0..0fb3d0f176eb2 100644 --- a/tests/ui/allocator/159445-unsize-pin-box.stderr +++ b/tests/ui/allocator/159445-unsize-pin-box.stderr @@ -19,7 +19,7 @@ help: the following other types implement trait `StaticAllocator` --> $SRC_DIR/alloc/src/alloc.rs:LL:COL | = note: `std::alloc::Global` - = note: required for `Box` to implement `PinCoerceUnsized` + = note: required for `Box` to implement `PinSafePointer` = note: required for the cast from `Pin>` to `Pin>` error: aborting due to 1 previous error From 7ed549afe60527f0741a1f6a6d4ce250c21946e5 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 10 Aug 2026 04:40:01 +0000 Subject: [PATCH 38/98] Prepare for merging from rust-lang/rust This updates the rust-version file to 969b803cbe1d4499f841ae0a49c637d8c70a0458. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 1a74dff9d23d8..5e795b08df4a2 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -da86f4d0726be475afbbffe40cb2f65741c51ad3 +969b803cbe1d4499f841ae0a49c637d8c70a0458 From 25c1ae6c7652e04abdca92c739d2af315ff419c6 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 10 Aug 2026 08:13:56 -0700 Subject: [PATCH 39/98] stability.md: add missing brackets to `unstable_removed` attribute --- src/doc/rustc-dev-guide/src/stability.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/stability.md b/src/doc/rustc-dev-guide/src/stability.md index f80dc48cd4c28..3aebc860bc5c5 100644 --- a/src/doc/rustc-dev-guide/src/stability.md +++ b/src/doc/rustc-dev-guide/src/stability.md @@ -217,7 +217,7 @@ Currently, the items that can be annotated with `#[unstable_feature_bound]` are: ## renamed and removed features Unstable features can get renamed and removed. If you rename a feature, you can add `old_name = "old_name"` to the `#[unstable]` attribute. -If you remove a feature, the `#!unstable_removed(feature = "foo", reason = "brief description", link = "link", since = "1.90.0")` +If you remove a feature, the `#![unstable_removed(feature = "foo", reason = "brief description", link = "link", since = "1.90.0")]` attribute should be used to produce a good error message for users of the removed feature. The `link` field can be used to link to the most relevant information on the removal of the feature such as a GitHub issue, comment or PR. From 0ece90b62b45988cd01ce0a95e317ea2796304de Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:32:41 +0100 Subject: [PATCH 40/98] Add assumptions on binders shorthand to the glossary --- src/doc/rustc-dev-guide/src/appendix/glossary.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md index 527da87b7b7e1..486238c86fc71 100644 --- a/src/doc/rustc-dev-guide/src/appendix/glossary.md +++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md @@ -6,6 +6,7 @@ Term | Meaning arena, arena allocation | An _arena_ is a large memory buffer from which other memory allocations are made. This style of allocation is called _arena allocation_. See [this chapter](../memory.md) for more info. AFIDT | Short for _async function in `dyn Trait`_. See also [AFIT](#afit). AFIT | Short for _async function in trait_. They desugar to [RPITITs](#rpitit). + Assbind | Short for ["Assumptions on Binders"](https://github.com/rust-lang/project-assumptions-on-binders) (See: [Zulip thread](https://rust-lang.zulipchat.com/#narrow/channel/260443-project-const-generics/topic/talkies.3F.20in.20this.20economy/near/615646513)). AST | The _abstract syntax tree_ (an [IR](#ir)) produced by the parser; reflects the surface / user syntax very closely. APIT | Short for _argument-position `impl Trait`_. Also known as universial `impl Trait` (as opposed to existential) or anonymous type parameter. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#anonymous-type-parameters)). ATPIT | Short for _associated-type-position `impl Trait`_. Also known as [ITIAT](#itiat). From 98cb632c2ea8f715458eb49cd367bd44765bc10e Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Tue, 11 Aug 2026 17:59:24 +0000 Subject: [PATCH 41/98] Prepare for merging from rust-lang/rust This updates the rust-version file to e64c8a664d9da54fc239cd4404cbf67f0d624326. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 5e795b08df4a2..6a21f4bf92e28 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -969b803cbe1d4499f841ae0a49c637d8c70a0458 +e64c8a664d9da54fc239cd4404cbf67f0d624326 From 9b06d77a4685ca554486457fbbe70aa75c9fbf93 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:05:39 +0200 Subject: [PATCH 42/98] fix attribute links --- .../rustc-dev-guide/src/hir/attribute-parsing.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/hir/attribute-parsing.md b/src/doc/rustc-dev-guide/src/hir/attribute-parsing.md index fd0ddc7210711..bc0240faec661 100644 --- a/src/doc/rustc-dev-guide/src/hir/attribute-parsing.md +++ b/src/doc/rustc-dev-guide/src/hir/attribute-parsing.md @@ -5,15 +5,15 @@ Inert attributes are parsed during AST lowering to the HIR, while active attribu For more information about the difference, see [the page about attributes][attributes_page]. During [AST lowering][lowering], inert attributes are converted from an unparsed `TokenStream` to a parsed representation. -The parsed form [is defined][hir_attrs] in the `rustc_hir` crate, and the parsers [are defined][attr_parsing] in the `rustc_attr_parsing` crate. +The parsed form is defined in the [`rustc_attr_ir`][attrs] crate, and the parsers are defined in the [`rustc_attr_parsing`][attr_parsing] crate. ## A step by step guide of adding a new inert attribute parser 1. Add the attribute name to the [BUILTIN_ATTRIBUTES]. This list defines the set of inert attributes. -2. Add a variant to `AttributeKind` in the [hir definition of attributes][hir_attrs]. +2. Add a variant to [`AttributeKind`] in the [definition of attributes][attrs]. This will define the parsed form of the attribute that the attribute parser will produce. -3. Add your variant to the match in `rustc_hir/attrs/encode_cross_crate.rs`, which should return whether your attribute should be visible in dependent crates. +3. Add your variant to the match in `rustc_attr_ir/encode_cross_crate.rs`, which should return whether your attribute should be visible in dependent crates. This is usually `No` for codegen related attributes, and `Yes` for analysis related attributes. 4. Create a new struct in `rustc_attr_parsing/attributes/*.rs` that will hold the state for your attribute parser. For most parsers, this will be an empty struct. @@ -57,9 +57,9 @@ This macro can be used in the following ways: * `find_attr!(tcx, , Variant(...))` to find an attribute on a def id. * `find_attr!(tcx, , Variant(...))` to find an attribute on a HIR id. * `find_attr!(tcx, crate, Variant(...))` to find an attribute on the current crate. -* `find_attr!(attrs, Variant(...))` to find an attribute in attrs, a `&[hir::Attribute]`. +* `find_attr!(attrs, Variant(...))` to find an attribute in attrs, a `&[rustc_attr_ir::Attribute]`. -`Variant` is a pattern matching one of the `AttributeKind` variants, and can take one of the following shapes: +`Variant` is a pattern matching one of the [`AttributeKind`] variants, and can take one of the following shapes: * `find_attr!(..., Variant)` will return a boolean representing whether the attribute is present. * `find_attr!(..., Variant(a, b, _) => (a, b))` will return the value after the `=>`, constructed from fields bound by the pattern. @@ -74,10 +74,11 @@ In other words, we expect attributes parsed with `parse_limited` to be reparsed [attributes_page]: ../attributes.md [lowering]: ./lowering.md -[hir_attrs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/attrs/index.html +[attrs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_ir/index.html [attr_parsing]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/ [attribute_parsers]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/context/static.ATTRIBUTE_PARSERS.html [builtin_attributes]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_feature/builtin_attrs/static.BUILTIN_ATTRIBUTES.html [template!]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/macro.template.html -[find_attr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/macro.find_attr.html +[find_attr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_ir/macro.find_attr.html [parse_limited]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/interface/struct.AttributeParser.html#method.parse_limited +[`AttributeKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_ir/enum.AttributeKind.html \ No newline at end of file From 1745a93a864b371ab1e31317eb54a912de2b0fb6 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 11 Aug 2026 23:57:48 +0200 Subject: [PATCH 43/98] vectorcall fix --- library/stdarch/crates/stdarch-test/src/disassembly.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/stdarch/crates/stdarch-test/src/disassembly.rs b/library/stdarch/crates/stdarch-test/src/disassembly.rs index 7cf657baa0d71..85aab498619d2 100644 --- a/library/stdarch/crates/stdarch-test/src/disassembly.rs +++ b/library/stdarch/crates/stdarch-test/src/disassembly.rs @@ -198,8 +198,11 @@ fn parse(output: &str) -> HashSet { }; } + // When using vectorcall the `ret` can have an argument, so match only the first part. + let is_ret = matches!(parts.first().map(String::as_str), Some("ret" | "retq")); + instructions.push(parts.join(" ")); - if matches!(&**instructions.last().unwrap(), "ret" | "retq") { + if is_ret { cached_header = None; break; } From b4ea05ef36b845f06f805ffffdfa1322a60c8505 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 9 Aug 2026 14:37:17 +0200 Subject: [PATCH 44/98] update aarch64/arm64ec assembly tests I believe this is effectively equivalent, just a different spelling of the same semantics --- .../src/arm_shared/neon/generated.rs | 240 ++++++++++++++---- .../spec/neon/arm_shared.spec.yml | 56 ++-- 2 files changed, 229 insertions(+), 67 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs index b3715308c9736..3a47ede1acc88 100644 --- a/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs +++ b/library/stdarch/crates/core_arch/src/arm_shared/neon/generated.rs @@ -15285,11 +15285,17 @@ pub fn vget_low_f16(a: float16x8_t) -> float16x4_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15307,11 +15313,17 @@ pub fn vget_high_f32(a: float32x4_t) -> float32x2_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15333,11 +15345,17 @@ pub fn vget_high_f32(a: float32x4_t) -> float32x2_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15355,11 +15373,17 @@ pub fn vget_high_p16(a: poly16x8_t) -> poly16x4_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15381,11 +15405,17 @@ pub fn vget_high_p16(a: poly16x8_t) -> poly16x4_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15403,11 +15433,17 @@ pub fn vget_high_p8(a: poly8x16_t) -> poly8x8_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15430,11 +15466,17 @@ pub fn vget_high_p8(a: poly8x16_t) -> poly8x8_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15452,11 +15494,17 @@ pub fn vget_high_s16(a: int16x8_t) -> int16x4_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15478,11 +15526,17 @@ pub fn vget_high_s16(a: int16x8_t) -> int16x4_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15500,11 +15554,17 @@ pub fn vget_high_s32(a: int32x4_t) -> int32x2_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15526,11 +15586,17 @@ pub fn vget_high_s32(a: int32x4_t) -> int32x2_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15548,11 +15614,17 @@ pub fn vget_high_s8(a: int8x16_t) -> int8x8_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15575,11 +15647,17 @@ pub fn vget_high_s8(a: int8x16_t) -> int8x8_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15597,11 +15675,17 @@ pub fn vget_high_u16(a: uint16x8_t) -> uint16x4_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15623,11 +15707,17 @@ pub fn vget_high_u16(a: uint16x8_t) -> uint16x4_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15645,11 +15735,17 @@ pub fn vget_high_u32(a: uint32x4_t) -> uint32x2_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15671,11 +15767,17 @@ pub fn vget_high_u32(a: uint32x4_t) -> uint32x2_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15693,11 +15795,17 @@ pub fn vget_high_u8(a: uint8x16_t) -> uint8x8_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15720,11 +15828,17 @@ pub fn vget_high_u8(a: uint8x16_t) -> uint8x8_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15742,11 +15856,17 @@ pub fn vget_high_p64(a: poly64x2_t) -> poly64x1_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15767,11 +15887,17 @@ pub fn vget_high_p64(a: poly64x2_t) -> poly64x1_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15789,11 +15915,17 @@ pub fn vget_high_s64(a: int64x2_t) -> int64x1_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15814,11 +15946,17 @@ pub fn vget_high_s64(a: int64x2_t) -> int64x1_t { #[cfg(target_endian = "little")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") @@ -15836,11 +15974,17 @@ pub fn vget_high_u64(a: uint64x2_t) -> uint64x1_t { #[cfg(target_endian = "big")] #[target_feature(enable = "neon")] #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmov"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vmov))] #[cfg_attr( - all(test, any(target_arch = "aarch64", target_arch = "arm64ec")), + all(test, target_arch = "aarch64", target_endian = "little", not(windows)), + assert_instr(mov) +)] +#[cfg_attr( + all(test, target_arch = "aarch64", target_endian = "big"), assert_instr(ext) )] +#[cfg_attr(all(test, target_arch = "arm64ec"), assert_instr(dup))] +#[cfg_attr(all(test, target_arch = "aarch64", windows), assert_instr(dup))] #[cfg_attr( not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0") diff --git a/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml b/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml index 7473742a963fa..7a7656e4c14b3 100644 --- a/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml +++ b/library/stdarch/crates/stdarch-gen-arm/spec/neon/arm_shared.spec.yml @@ -55,6 +55,18 @@ not-arm: ¬-arm neon-target-aarch64-arm64ec: &neon-target-aarch64-arm64ec FnCall: [all, [test, {FnCall: [any, ['target_arch = "aarch64"', 'target_arch = "arm64ec"']]}]] +neon-target-aarch64-le: &neon-target-aarch64-le + FnCall: [all, [test, 'target_arch = "aarch64"', 'target_endian = "little"', {FnCall: [not, [windows]]}]] + +neon-target-aarch64-be: &neon-target-aarch64-be + FnCall: [all, [test, 'target_arch = "aarch64"', 'target_endian = "big"']] + +neon-target-arm64ec: &neon-target-arm64ec + FnCall: [all, [test, 'target_arch = "arm64ec"']] + +neon-target-aarch64-windows: &neon-target-aarch64-windows + FnCall: [all, [test, 'target_arch = "aarch64"', windows]] + # #[cfg_attr(not(target_arch = "arm"), stable(feature = "neon_intrinsics", since = "1.59.0"))] neon-not-arm-stable: &neon-not-arm-stable FnCall: [cfg_attr, [{ FnCall: [not, ['target_arch = "arm"']]}, {FnCall: [stable, ['feature = "neon_intrinsics"', 'since = "1.59.0"']]}]] @@ -15076,18 +15088,21 @@ intrinsics: return_type: "{neon_type[2]}" attr: - *neon-v7 - - FnCall: [cfg_attr, [*test-is-arm, { FnCall: [assert_instr, ['"{type[3]}"']]}]] - - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, ['{type[4]}']]}]] + - FnCall: [cfg_attr, [*test-is-arm, { FnCall: [assert_instr, ['vmov']]}]] + - FnCall: [cfg_attr, [*neon-target-aarch64-le, {FnCall: [assert_instr, ['mov']]}]] + - FnCall: [cfg_attr, [*neon-target-aarch64-be, {FnCall: [assert_instr, ['ext']]}]] + - FnCall: [cfg_attr, [*neon-target-arm64ec, {FnCall: [assert_instr, ['dup']]}]] + - FnCall: [cfg_attr, [*neon-target-aarch64-windows, {FnCall: [assert_instr, ['dup']]}]] - *neon-not-arm-stable - *neon-cfg-arm-unstable safety: safe big_endian_inverse: true types: - - ['vget_high_s64', 'int64x2_t', 'int64x1_t', 'vmov', 'ext', 'int64x1_t([simd_extract!(a, 1)])'] - - ['vget_high_u64', 'uint64x2_t', 'uint64x1_t', 'vmov', 'ext', 'uint64x1_t([simd_extract!(a, 1)])'] - - ['vget_high_p64', 'poly64x2_t', 'poly64x1_t', 'vmov', 'ext', 'transmute(u64x1::new(simd_extract!(a, 1)))'] + - ['vget_high_s64', 'int64x2_t', 'int64x1_t', 'int64x1_t([simd_extract!(a, 1)])'] + - ['vget_high_u64', 'uint64x2_t', 'uint64x1_t', 'uint64x1_t([simd_extract!(a, 1)])'] + - ['vget_high_p64', 'poly64x2_t', 'poly64x1_t', 'transmute(u64x1::new(simd_extract!(a, 1)))'] compose: - - Identifier: ['{type[5]}', UnsafeSymbol] + - Identifier: ['{type[3]}', UnsafeSymbol] - name: "{type[0]}" doc: "Duplicate vector element to vector or scalar" @@ -15113,24 +15128,27 @@ intrinsics: return_type: "{neon_type[2]}" attr: - *neon-v7 - - FnCall: [cfg_attr, [*test-is-arm, { FnCall: [assert_instr, ['"{type[3]}"']]}]] - - FnCall: [cfg_attr, [*neon-target-aarch64-arm64ec, {FnCall: [assert_instr, ['{type[4]}']]}]] + - FnCall: [cfg_attr, [*test-is-arm, { FnCall: [assert_instr, ['vmov']]}]] + - FnCall: [cfg_attr, [*neon-target-aarch64-le, {FnCall: [assert_instr, ['mov']]}]] + - FnCall: [cfg_attr, [*neon-target-aarch64-be, {FnCall: [assert_instr, ['ext']]}]] + - FnCall: [cfg_attr, [*neon-target-arm64ec, {FnCall: [assert_instr, ['dup']]}]] + - FnCall: [cfg_attr, [*neon-target-aarch64-windows, {FnCall: [assert_instr, ['dup']]}]] - *neon-not-arm-stable - *neon-cfg-arm-unstable safety: safe big_endian_inverse: true types: - - ['vget_high_s8', 'int8x16_t', 'int8x8_t', 'vmov', 'ext', '[8, 9, 10, 11, 12, 13, 14, 15]'] - - ['vget_high_u8', 'uint8x16_t', 'uint8x8_t', 'vmov', 'ext', '[8, 9, 10, 11, 12, 13, 14, 15]'] - - ['vget_high_p8', 'poly8x16_t', 'poly8x8_t', 'vmov', 'ext', '[8, 9, 10, 11, 12, 13, 14, 15]'] - - ['vget_high_s16', 'int16x8_t', 'int16x4_t', 'vmov', 'ext', '[4, 5, 6, 7]'] - - ['vget_high_u16', 'uint16x8_t', 'uint16x4_t', 'vmov', 'ext', '[4, 5, 6, 7]'] - - ['vget_high_p16', 'poly16x8_t', 'poly16x4_t', 'vmov', 'ext', '[4, 5, 6, 7]'] - - ['vget_high_s32', 'int32x4_t', 'int32x2_t', 'vmov', 'ext', '[2, 3]'] - - ['vget_high_u32', 'uint32x4_t', 'uint32x2_t', 'vmov', 'ext', '[2, 3]'] - - ['vget_high_f32', 'float32x4_t', 'float32x2_t', 'vmov', 'ext', '[2, 3]'] - compose: - - FnCall: ['simd_shuffle!', [a, a, '{type[5]}']] + - ['vget_high_s8', 'int8x16_t', 'int8x8_t', '[8, 9, 10, 11, 12, 13, 14, 15]'] + - ['vget_high_u8', 'uint8x16_t', 'uint8x8_t', '[8, 9, 10, 11, 12, 13, 14, 15]'] + - ['vget_high_p8', 'poly8x16_t', 'poly8x8_t', '[8, 9, 10, 11, 12, 13, 14, 15]'] + - ['vget_high_s16', 'int16x8_t', 'int16x4_t', '[4, 5, 6, 7]'] + - ['vget_high_u16', 'uint16x8_t', 'uint16x4_t', '[4, 5, 6, 7]'] + - ['vget_high_p16', 'poly16x8_t', 'poly16x4_t', '[4, 5, 6, 7]'] + - ['vget_high_s32', 'int32x4_t', 'int32x2_t', '[2, 3]'] + - ['vget_high_u32', 'uint32x4_t', 'uint32x2_t', '[2, 3]'] + - ['vget_high_f32', 'float32x4_t', 'float32x2_t', '[2, 3]'] + compose: + - FnCall: ['simd_shuffle!', [a, a, '{type[3]}']] - name: "{type[0]}" doc: "Duplicate vector element to vector or scalar" From eb750a765d26a5b0307b1740e3bf43648d878696 Mon Sep 17 00:00:00 2001 From: albab-hasan Date: Wed, 12 Aug 2026 13:32:45 +0600 Subject: [PATCH 45/98] give layout errors from `size_of_val` and `align_of_val` a span `size_and_align_of_dst` asked for the pointee layout with the spanless `layout_of`, so a `SizeOverflow` from these intrinsics printed a bare error with no location. it takes a span now and both call sites pass the span of the with `-Cdebuginfo=2` the same error comes froion signature, which was spanless too. it now uses the span `dbg_scope_fn` already computes. --- .../src/debuginfo/metadata.rs | 9 ++++---- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 15 ++++++++----- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/place.rs | 6 +++-- compiler/rustc_codegen_ssa/src/size_of_val.rs | 7 +++--- ...f-val-raw-too-big-64.full-debuginfo.stderr | 8 +++++++ ...-of-val-raw-too-big-64.no-debuginfo.stderr | 8 +++++++ tests/ui/layout/size-of-val-raw-too-big-64.rs | 22 +++++++++++++++++++ tests/ui/layout/size-of-val-raw-too-big.rs | 2 +- .../ui/layout/size-of-val-raw-too-big.stderr | 4 ++++ 10 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 tests/ui/layout/size-of-val-raw-too-big-64.full-debuginfo.stderr create mode 100644 tests/ui/layout/size-of-val-raw-too-big-64.no-debuginfo.stderr create mode 100644 tests/ui/layout/size-of-val-raw-too-big-64.rs diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 6e64fa7d04a93..33f6eca6be9cc 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -143,6 +143,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( ptr_type: Ty<'tcx>, pointee_type: Ty<'tcx>, unique_type_id: UniqueTypeId<'tcx>, + span: Span, ) -> DINodeCreationResult<'ll> { // The debuginfo generated by this function is only valid if `ptr_type` is really just // a (wide) pointer. Make sure it is not called for e.g. `Box`. @@ -153,7 +154,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( let pointee_type_di_node = match pointee_type.kind() { // `&[T]` will look like `{ data_ptr: *const T, length: usize }` - ty::Slice(element_type) => type_di_node(cx, *element_type), + ty::Slice(element_type) => spanned_type_di_node(cx, *element_type, span), // `&str` will look like `{ data_ptr: *const u8, length: usize }` ty::Str => type_di_node(cx, cx.tcx.types.u8), @@ -163,7 +164,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( // and thin pointers `&Foo` will just look like `*const Foo`. // // in all those cases, we just use the pointee_type - _ => type_di_node(cx, pointee_type), + _ => spanned_type_di_node(cx, pointee_type, span), }; return_if_di_node_created_in_meantime!(cx, unique_type_id); @@ -468,7 +469,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id), ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id), ty::RawPtr(pointee_type, _) | ty::Ref(_, pointee_type, _) => { - build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id) + build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id, span) } // Some `Box` are newtyped pointers, make debuginfo aware of that. // Only works if the allocator argument is a 1-ZST and hence irrelevant for layout @@ -477,7 +478,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( if def.is_box() && args.get(1).is_none_or(|arg| cx.layout_of(arg.expect_ty()).is_1zst()) => { - build_pointer_or_reference_di_node(cx, t, t.expect_boxed_ty(), unique_type_id) + build_pointer_or_reference_di_node(cx, t, t.expect_boxed_ty(), unique_type_id, span) } ty::FnDef(..) | ty::FnPtr(..) => build_subroutine_type_di_node(cx, unique_type_id), ty::Closure(..) => build_closure_env_di_node(cx, unique_type_id), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 580b7a89484d4..d6d9946450899 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -141,7 +141,7 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let file_metadata = file_metadata(self, &loc.file); let function_type_metadata = - create_subroutine_type(self, &get_function_signature(self, fn_abi)); + create_subroutine_type(self, &get_function_signature(self, fn_abi, span)); let mut name = String::with_capacity(64); type_names::push_item_name(tcx, def_id, false, &mut name); @@ -233,6 +233,7 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn get_function_signature<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + span: Span, ) -> Vec> { if cx.sess().opts.debuginfo != DebugInfo::Full { return vec![]; @@ -244,7 +245,7 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { signature.push(if fn_abi.ret.is_ignore() { None } else { - Some(type_di_node(cx, fn_abi.ret.layout.ty)) + Some(spanned_type_di_node(cx, fn_abi.ret.layout.ty, span)) }); // Arguments types @@ -269,11 +270,15 @@ impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } _ => t, }; - Some(type_di_node(cx, t)) + Some(spanned_type_di_node(cx, t, span)) })); } else { - signature - .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty)))); + signature.extend( + fn_abi + .args + .iter() + .map(|arg| Some(spanned_type_di_node(cx, arg.layout.ty, span))), + ); } signature diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index cc48f418d03db..77ab3bdce4689 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -164,13 +164,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::size_of_val => { let tp_ty = fn_args.type_at(0); let (_, meta) = args[0].val.pointer_parts(); - let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); + let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta, span); OperandValue::Immediate(llsize) } sym::align_of_val => { let tp_ty = fn_args.type_at(0); let (_, meta) = args[0].val.pointer_parts(); - let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); + let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta, span); OperandValue::Immediate(llalign) } sym::vtable_size | sym::vtable_align => { diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 14a5f71fbceaa..60480d1853853 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -8,6 +8,7 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, mir}; +use rustc_span::DUMMY_SP; use tracing::{debug, instrument}; use super::operand::OperandValue; @@ -227,8 +228,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let unaligned_offset = bx.cx().const_usize(offset.bytes()); - // Get the alignment of the field - let (_, mut unsized_align) = size_of_val::size_and_align_of_dst(bx, field.ty, meta); + // Get the alignment of the field. No span is available here to blame a layout error on. + let (_, mut unsized_align) = + size_of_val::size_and_align_of_dst(bx, field.ty, meta, DUMMY_SP); // For packed types, we need to cap alignment. if let ty::Adt(def, _) = self.layout.ty.kind() diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 3c4369330da59..0ef0179eac6c4 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -5,7 +5,7 @@ use rustc_hir::attrs::lang_items::LangItem; use rustc_middle::bug; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty}; -use rustc_span::DUMMY_SP; +use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, trace}; use crate::common::IntPredicate; @@ -16,8 +16,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, t: Ty<'tcx>, info: Option, + span: Span, ) -> (Bx::Value, Bx::Value) { - let layout = bx.layout_of(t); + let layout = bx.spanned_layout_of(t, span); trace!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t, info, layout); if layout.is_sized() { let size = bx.const_usize(layout.size.bytes()); @@ -107,7 +108,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Recurse to get the size of the dynamically sized field (must be // the last field). let field_ty = layout.field(bx, i).ty; - let (unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info); + let (unsized_size, mut unsized_align) = size_and_align_of_dst(bx, field_ty, info, span); // # First compute the dynamic alignment diff --git a/tests/ui/layout/size-of-val-raw-too-big-64.full-debuginfo.stderr b/tests/ui/layout/size-of-val-raw-too-big-64.full-debuginfo.stderr new file mode 100644 index 0000000000000..1fd685b2b51c2 --- /dev/null +++ b/tests/ui/layout/size-of-val-raw-too-big-64.full-debuginfo.stderr @@ -0,0 +1,8 @@ +error: values of the type `[u8; 9223372036854775807]` are too big for the target architecture + --> $DIR/size-of-val-raw-too-big-64.rs:18:1 + | +LL | pub fn check(x: *const Example) -> usize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/layout/size-of-val-raw-too-big-64.no-debuginfo.stderr b/tests/ui/layout/size-of-val-raw-too-big-64.no-debuginfo.stderr new file mode 100644 index 0000000000000..268c0ad964f3a --- /dev/null +++ b/tests/ui/layout/size-of-val-raw-too-big-64.no-debuginfo.stderr @@ -0,0 +1,8 @@ +error: values of the type `[u8; 9223372036854775807]` are too big for the target architecture + --> $DIR/size-of-val-raw-too-big-64.rs:20:14 + | +LL | unsafe { std::intrinsics::size_of_val(x) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/layout/size-of-val-raw-too-big-64.rs b/tests/ui/layout/size-of-val-raw-too-big-64.rs new file mode 100644 index 0000000000000..41c1f468764ea --- /dev/null +++ b/tests/ui/layout/size-of-val-raw-too-big-64.rs @@ -0,0 +1,22 @@ +// FIXME(#61117): Remove revisions once x86_64-gnu-debug CI job sets rust.debuginfo-level-tests=2 +//@ revisions: no-debuginfo full-debuginfo +//@[no-debuginfo] compile-flags: -Cdebuginfo=0 +//@[full-debuginfo] compile-flags: -Cdebuginfo=2 +//@ build-fail +//@ compile-flags: --crate-type lib +//@ only-64bit Layout computation rejects this layout for different reasons on 32-bit. + +#![feature(core_intrinsics)] +#![allow(internal_features)] + +#[repr(C)] +pub struct Example([u8; isize::MAX as usize], [u16]); + +// The `size_of_val` intrinsic is the first thing to ask for the layout of `Example` when there is +// no debuginfo, while with full debuginfo the type is described for the signature of `check` +// first. Both point at the code that requires the layout. +pub fn check(x: *const Example) -> usize { + //[full-debuginfo]~^ ERROR are too big for the target architecture + unsafe { std::intrinsics::size_of_val(x) } + //[no-debuginfo]~^ ERROR are too big for the target architecture +} diff --git a/tests/ui/layout/size-of-val-raw-too-big.rs b/tests/ui/layout/size-of-val-raw-too-big.rs index 566b01255fae1..53a958c11de89 100644 --- a/tests/ui/layout/size-of-val-raw-too-big.rs +++ b/tests/ui/layout/size-of-val-raw-too-big.rs @@ -1,4 +1,3 @@ -//~ ERROR values of the type `Example` are too big for the target architecture //@ build-fail //@ compile-flags: --crate-type lib //@ only-32bit Layout computation rejects this layout for different reasons on 64-bit. @@ -16,4 +15,5 @@ pub struct Example([u8; isize::MAX as usize], [u16]); // does abort compilation. pub fn check(x: *const Example) -> usize { unsafe { std::intrinsics::size_of_val(x) } + //~^ ERROR values of the type `Example` are too big for the target architecture } diff --git a/tests/ui/layout/size-of-val-raw-too-big.stderr b/tests/ui/layout/size-of-val-raw-too-big.stderr index 886bba9ec9d34..a20de4688f286 100644 --- a/tests/ui/layout/size-of-val-raw-too-big.stderr +++ b/tests/ui/layout/size-of-val-raw-too-big.stderr @@ -1,4 +1,8 @@ error: values of the type `Example` are too big for the target architecture + --> $DIR/size-of-val-raw-too-big.rs:17:14 + | +LL | unsafe { std::intrinsics::size_of_val(x) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error From 4f9e9713b71171e4f42f7c747a18e8aeed562082 Mon Sep 17 00:00:00 2001 From: albab-hasan Date: Wed, 12 Aug 2026 15:16:11 +0600 Subject: [PATCH 46/98] skip the debuginfo revision on the gcc backend the span for that revision comes from the llvm debuginfo. which cg_gcc does not build so it reported the intrinsic call instead and the baseline did not match. --- .../ui/layout/size-of-val-raw-too-big-64.full-debuginfo.stderr | 2 +- tests/ui/layout/size-of-val-raw-too-big-64.no-debuginfo.stderr | 2 +- tests/ui/layout/size-of-val-raw-too-big-64.rs | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ui/layout/size-of-val-raw-too-big-64.full-debuginfo.stderr b/tests/ui/layout/size-of-val-raw-too-big-64.full-debuginfo.stderr index 1fd685b2b51c2..8d88c14f43c8d 100644 --- a/tests/ui/layout/size-of-val-raw-too-big-64.full-debuginfo.stderr +++ b/tests/ui/layout/size-of-val-raw-too-big-64.full-debuginfo.stderr @@ -1,5 +1,5 @@ error: values of the type `[u8; 9223372036854775807]` are too big for the target architecture - --> $DIR/size-of-val-raw-too-big-64.rs:18:1 + --> $DIR/size-of-val-raw-too-big-64.rs:20:1 | LL | pub fn check(x: *const Example) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/layout/size-of-val-raw-too-big-64.no-debuginfo.stderr b/tests/ui/layout/size-of-val-raw-too-big-64.no-debuginfo.stderr index 268c0ad964f3a..6f4ec923c6a0c 100644 --- a/tests/ui/layout/size-of-val-raw-too-big-64.no-debuginfo.stderr +++ b/tests/ui/layout/size-of-val-raw-too-big-64.no-debuginfo.stderr @@ -1,5 +1,5 @@ error: values of the type `[u8; 9223372036854775807]` are too big for the target architecture - --> $DIR/size-of-val-raw-too-big-64.rs:20:14 + --> $DIR/size-of-val-raw-too-big-64.rs:22:14 | LL | unsafe { std::intrinsics::size_of_val(x) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/layout/size-of-val-raw-too-big-64.rs b/tests/ui/layout/size-of-val-raw-too-big-64.rs index 41c1f468764ea..86d93b9f7ef80 100644 --- a/tests/ui/layout/size-of-val-raw-too-big-64.rs +++ b/tests/ui/layout/size-of-val-raw-too-big-64.rs @@ -2,6 +2,8 @@ //@ revisions: no-debuginfo full-debuginfo //@[no-debuginfo] compile-flags: -Cdebuginfo=0 //@[full-debuginfo] compile-flags: -Cdebuginfo=2 +// the span for this revision comes from the LLVM debuginfo, which the gcc backend does not build +//@[full-debuginfo] ignore-backends: gcc //@ build-fail //@ compile-flags: --crate-type lib //@ only-64bit Layout computation rejects this layout for different reasons on 32-bit. From 644a82617bb817cf42edf45e7c622203efd0e756 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 5 Aug 2026 11:17:41 +0100 Subject: [PATCH 47/98] sve: re-enable `sveorv` testing after LLVM upgrade This was disabled in rust-lang/stdarch#2160 due to an LLVM bug (llvm/llvm-project#203921) that was fixed in LLVM 23, which rustc now uses on nightly (rust-lang/rust#158734). --- library/stdarch/crates/intrinsic-test/src/arm/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs index 4054d02502bfa..17deff43efb5a 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs @@ -111,10 +111,6 @@ impl SupportedArchitecture for Arm { // zeroed vectors in Rust, which are inherently going to be different than the // undefined vectors returned by the C intrinsics. .filter(|i| !i.name.starts_with("svundef")) - // Skip `sveorv` intrinsics - the code produced by `intrinsic-test` for these - // miscompiles and the Rust intrinsic call gets replaced by a constant zero (see - // llvm/llvm-project#203921). - .filter(|i| !i.name.starts_with("sveorv")) // These load intrinsics expect each element in the scalable vector `bases` argument to // be able to be cast to a pointer, which we don't support generating tests for yet. .filter(|i| !(i.name.starts_with("svld") && i.name.contains("_gather_"))) From 668088038d23d3c4aea351c2d1ea56ad12be64b1 Mon Sep 17 00:00:00 2001 From: sayantn Date: Tue, 14 Jul 2026 04:09:03 +0530 Subject: [PATCH 48/98] Simplify scalable vector testing --- .../crates/intrinsic-test/src/arm/mod.rs | 137 ++++++++++-------- .../crates/intrinsic-test/src/arm/types.rs | 74 ++-------- 2 files changed, 94 insertions(+), 117 deletions(-) diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs index 4054d02502bfa..fdea2c6eee790 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs @@ -233,72 +233,91 @@ const fn svprfop_from_i32(value: i32) -> svprfop { } } -macro_rules! debug_print_integral { - ($($name:ident => ($ty:ty, $svptrue_fn:ident, $svcnt_fn:ident, $svst_fn:ident)),*) => { - $( - #[inline] - #[target_feature(enable = "sve")] - #[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] - pub fn $name(v: $ty) -> String { - unsafe { - let __pred = $svptrue_fn(); - let __num_elems = $svcnt_fn() as usize; - let mut __buf = std::vec::Vec::with_capacity(__num_elems); - $svst_fn(__pred, __buf.as_mut_ptr(), v); - __buf.set_len(__num_elems); - format!( - "[{}]", - __buf.iter().map(|el| el.to_string()).collect::>().join(", ") - ) - } - } - )* +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svint8_to_slice(a: &svint8_t) -> &[i8] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntb() as usize) } } -debug_print_integral! { - debug_print_f32 => (svfloat32_t, svptrue_b32, svcntw, svst1_f32), - debug_print_f64 => (svfloat64_t, svptrue_b64, svcntd, svst1_f64), - debug_print_s8 => (svint8_t, svptrue_b8, svcntb, svst1_s8), - debug_print_s16 => (svint16_t, svptrue_b16, svcnth, svst1_s16), - debug_print_s32 => (svint32_t, svptrue_b32, svcntw, svst1_s32), - debug_print_s64 => (svint64_t, svptrue_b64, svcntd, svst1_s64), - debug_print_u8 => (svuint8_t, svptrue_b8, svcntb, svst1_u8), - debug_print_u16 => (svuint16_t, svptrue_b16, svcnth, svst1_u16), - debug_print_u32 => (svuint32_t, svptrue_b32, svcntw, svst1_u32), - debug_print_u64 => (svuint64_t, svptrue_b64, svcntd, svst1_u64) +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svuint8_to_slice(a: &svuint8_t) -> &[u8] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntb() as usize) + } } -macro_rules! debug_print_bool { - ($($name:ident => ($ty:ty, $svst_fn:ident, $svdup_fn:ident)),*) => { - $( - #[inline] - #[target_feature(enable = "sve")] - #[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] - pub fn $name(v: $ty) -> String { - unsafe { - let __num_elems = svcntb() as usize; - let mut __buf = std::vec::Vec::with_capacity(__num_elems); - $svst_fn(v, __buf.as_mut_ptr(), $svdup_fn(1)); - __buf.set_len(__num_elems); - format!( - "[{}]", - __buf.iter() - .map(|el| *el == 1) - .map(|el| el.to_string()) - .collect::>() - .join(", ") - ) - } - } - )* +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svint16_to_slice(a: &svint16_t) -> &[i16] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcnth() as usize) } } -debug_print_bool! { - debug_print_b8 => (svbool_t, svst1_u8, svdup_n_u8), - debug_print_b16 => (svbool_t, svst1_u16, svdup_n_u16), - debug_print_b32 => (svbool_t, svst1_u32, svdup_n_u32), - debug_print_b64 => (svbool_t, svst1_u64, svdup_n_u64) +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svuint16_to_slice(a: &svuint16_t) -> &[u16] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcnth() as usize) + } } + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svint32_to_slice(a: &svint32_t) -> &[i32] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntw() as usize) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svuint32_to_slice(a: &svuint32_t) -> &[u32] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntw() as usize) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svint64_to_slice(a: &svint64_t) -> &[i64] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntd() as usize) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svuint64_to_slice(a: &svuint64_t) -> &[u64] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntd() as usize) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svfloat32_to_slice(a: &svfloat32_t) -> &[NanEqF32] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntw() as usize) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svfloat64_to_slice(a: &svfloat64_t) -> &[NanEqF64] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntd() as usize) + } +} + +#[repr(transparent)] +#[derive(Copy,Clone,PartialEq,Eq)] +struct b8(u8); + +impl std::fmt::Debug for b8 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:08b}", self.0) + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +fn svbool_to_slice(a: &svbool_t) -> &[b8] { + unsafe { + core::slice::from_raw_parts(core::ptr::from_ref(a).cast(), svcntd() as usize) + } +} + "#; diff --git a/library/stdarch/crates/intrinsic-test/src/arm/types.rs b/library/stdarch/crates/intrinsic-test/src/arm/types.rs index 7481bb4aeb30d..cced3bc40c0e1 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/types.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/types.rs @@ -1,5 +1,4 @@ use super::intrinsic::ArmType; -use crate::common::PREDICATE_LOCAL; use crate::common::intrinsic_helpers::{ IntrinsicType, Sign, SimdLen, TypeDefinition, TypeKind, default_fixed_vector_comparison, }; @@ -114,17 +113,6 @@ impl TypeDefinition for ArmType { return default_fixed_vector_comparison(self, num_lanes); } - if self.kind() == TypeKind::Bool { - // There isn't a `svcmpeq` for `svbool_t` and there aren't `svboolxN_t` types, so just - // do an XOR and test it is empty. - return format!( - r#" -let __eq = sveor_b_z({PREDICATE_LOCAL}, __rust_return_value, __c_return_value); -assert!(!svptest_any({PREDICATE_LOCAL}, __eq), "{{}}", id); - "# - ); - } - // Returns `of` when `num_vectors == 1` otherwise returns the appropriate `svget` invocation // for `of`. let get = |num_vectors: u32, idx: u32, from: &'static str| -> String { @@ -139,56 +127,26 @@ assert!(!svptest_any({PREDICATE_LOCAL}, __eq), "{{}}", id); ) }; + let prefix = match self.kind { + TypeKind::Bool => "svbool".to_owned(), + kind => format!("sv{}{}", kind.c_prefix(), self.inner_size()), + }; + let n = self.num_vectors(); (0..n) .format_with("\n", |i, fmt| { - match self.kind() { - TypeKind::Float | TypeKind::BFloat => { - // Floats need special handling because `NaN != NaN` normally - this - // effectively does `(rust == c) || (isnan(rust) && isnan(c))` - fmt(&format_args!( - r#" -let __rust_eq_return_value = {rust_return_value}; -let __c_eq_return_value = {c_return_value}; -let __eq_sans_nan = svcmpeq_{ty}{bl}({PREDICATE_LOCAL}, __rust_eq_return_value, __c_eq_return_value); -let __rust_nan = svcmpuo_{ty}{bl}({PREDICATE_LOCAL}, __rust_eq_return_value, __rust_eq_return_value); -let __c_nan = svcmpuo_{ty}{bl}({PREDICATE_LOCAL}, __c_eq_return_value, __c_eq_return_value); -let __both_nan = svand_b_z({PREDICATE_LOCAL}, __rust_nan, __c_nan); -let __eq = svorr_b_z({PREDICATE_LOCAL}, __eq_sans_nan, __both_nan); -if !svptest_any(__pred, __eq) {{ - let __rust_pretty = debug_print_{ty}{bl}(__rust_eq_return_value); - let __c_pretty = debug_print_{ty}{bl}(__c_eq_return_value); - panic!("{{}}-{i_plus_one}/{n}\nRust: {{__rust_pretty}}\nC: {{__c_pretty}}", id); -}} -"#, - ty = self.rust_intrinsic_name_prefix(), - bl = self.inner_size(), - rust_return_value = get(n, i, "__rust_return_value"), - c_return_value = get(n, i, "__c_return_value"), - i_plus_one = i + 1, // so that the output is "1/2" and "2/2" - )) - } - _ => { - // Most types can just use `svcmpeq` - fmt(&format_args!( - r#" -let __rust_eq_return_value = {rust_return_value}; -let __c_eq_return_value = {c_return_value}; -let __eq = svcmpeq_{ty}{bl}({PREDICATE_LOCAL}, __rust_eq_return_value, __c_eq_return_value); -if !svptest_any(__pred, __eq) {{ - let __rust_pretty = debug_print_{ty}{bl}(__rust_eq_return_value); - let __c_pretty = debug_print_{ty}{bl}(__c_eq_return_value); - panic!("{{}}-{i_plus_one}/{n}\nRust: {{__rust_pretty}}\nC: {{__c_pretty}}", id); -}} + fmt(&format_args!( + r#" +assert_eq!( + {prefix}_to_slice(&{rust_return_value}), + {prefix}_to_slice(&{c_return_value}), + "{{id}}-({i_plus_one}/{n})" +); "#, - ty = self.rust_intrinsic_name_prefix(), - bl = self.inner_size(), - rust_return_value = get(n, i, "__rust_return_value"), - c_return_value = get(n, i, "__c_return_value"), - i_plus_one = i + 1, // so that the output is "1/2" and "2/2" - )) - } - } + rust_return_value = get(n, i, "__rust_return_value"), + c_return_value = get(n, i, "__c_return_value"), + i_plus_one = i + 1, // so that the output is "1/2" and "2/2" + )) }) .to_string() } From 761241c8eb07ed404c530aa2a5e89aa087bc799f Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Wed, 12 Aug 2026 13:41:45 +0100 Subject: [PATCH 49/98] Add preferred assumptions on binders shorthand to the glossary Removing the old one as it would otherwise be highly-visible and was already deprecated --- src/doc/rustc-dev-guide/src/appendix/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md index 486238c86fc71..0ddb65a2e2b20 100644 --- a/src/doc/rustc-dev-guide/src/appendix/glossary.md +++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md @@ -3,10 +3,10 @@ Term | Meaning -----------------------------------------------|-------- 1-ZST | A *one-aligned [zero-sized type](#zst)*. A type of size zero with an [alignment][size-align] of one. +abby | Short for [_assumptions on binders_](https://github.com/rust-lang/project-assumptions-on-binders). Alternatively: `a-bi`, though this is very close to ABI. arena, arena allocation | An _arena_ is a large memory buffer from which other memory allocations are made. This style of allocation is called _arena allocation_. See [this chapter](../memory.md) for more info. AFIDT | Short for _async function in `dyn Trait`_. See also [AFIT](#afit). AFIT | Short for _async function in trait_. They desugar to [RPITITs](#rpitit). - Assbind | Short for ["Assumptions on Binders"](https://github.com/rust-lang/project-assumptions-on-binders) (See: [Zulip thread](https://rust-lang.zulipchat.com/#narrow/channel/260443-project-const-generics/topic/talkies.3F.20in.20this.20economy/near/615646513)). AST | The _abstract syntax tree_ (an [IR](#ir)) produced by the parser; reflects the surface / user syntax very closely. APIT | Short for _argument-position `impl Trait`_. Also known as universial `impl Trait` (as opposed to existential) or anonymous type parameter. ([see the reference](https://doc.rust-lang.org/reference/types/impl-trait.html#anonymous-type-parameters)). ATPIT | Short for _associated-type-position `impl Trait`_. Also known as [ITIAT](#itiat). From 5097d8bcfe26b17bd22c90fed2601e3d8e40e9dd Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 12 Aug 2026 01:44:03 +0000 Subject: [PATCH 50/98] clippy::manual_isolate_lowest_one --- library/stdarch/crates/core_arch/src/x86/bmi1.rs | 2 +- library/stdarch/crates/core_arch/src/x86_64/bmi.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/stdarch/crates/core_arch/src/x86/bmi1.rs b/library/stdarch/crates/core_arch/src/x86/bmi1.rs index 21da03667f849..ccacd34f3ca01 100644 --- a/library/stdarch/crates/core_arch/src/x86/bmi1.rs +++ b/library/stdarch/crates/core_arch/src/x86/bmi1.rs @@ -60,7 +60,7 @@ pub const fn _andn_u32(a: u32, b: u32) -> u32 { #[stable(feature = "simd_x86", since = "1.27.0")] #[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")] pub const fn _blsi_u32(x: u32) -> u32 { - x & x.wrapping_neg() + x.isolate_lowest_one() } /// Gets mask up to lowest set bit. diff --git a/library/stdarch/crates/core_arch/src/x86_64/bmi.rs b/library/stdarch/crates/core_arch/src/x86_64/bmi.rs index f082953f9df90..d7f96bbc6708a 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/bmi.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/bmi.rs @@ -63,7 +63,7 @@ pub const fn _andn_u64(a: u64, b: u64) -> u64 { #[stable(feature = "simd_x86", since = "1.27.0")] #[rustc_const_unstable(feature = "stdarch_const_x86", issue = "149298")] pub const fn _blsi_u64(x: u64) -> u64 { - x & x.wrapping_neg() + x.isolate_lowest_one() } /// Gets mask up to lowest set bit. From 03e4d310c30868e0fc82ac8e0f723899cfcfe05a Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 12 Aug 2026 01:44:31 +0000 Subject: [PATCH 51/98] Allow some noisy clippy lints --- library/stdarch/crates/core_arch/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/stdarch/crates/core_arch/src/lib.rs b/library/stdarch/crates/core_arch/src/lib.rs index 0991ec1acf902..57eca221e1aba 100644 --- a/library/stdarch/crates/core_arch/src/lib.rs +++ b/library/stdarch/crates/core_arch/src/lib.rs @@ -60,7 +60,9 @@ clippy::shadow_reuse, clippy::similar_names, clippy::unusual_byte_groupings, - clippy::wrong_self_convention + clippy::wrong_self_convention, + clippy::zero_prefixed_literal, + clippy::tabs_in_doc_comments )] #![cfg_attr(test, allow(unused_imports))] #![no_std] From 742c085b67af5d8ee4b930acdba19b01f6639f47 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 19 Jul 2026 18:24:50 +0200 Subject: [PATCH 52/98] Use 2 word unwinder_private_data on Emscripten The 20 word requirement was likely from the JS EH ABI which we no longer support. --- library/unwind/src/types.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/unwind/src/types.rs b/library/unwind/src/types.rs index 413cd677fe7e0..7634052c93f33 100644 --- a/library/unwind/src/types.rs +++ b/library/unwind/src/types.rs @@ -36,7 +36,6 @@ pub const unwinder_private_data_size: usize = cfg_select! { target_arch = "s390x" => 2, any(target_arch = "sparc", target_arch = "sparc64") => 2, any(target_arch = "riscv64", target_arch = "riscv32") => 2, - all(target_family = "wasm", target_os = "emscripten") => 20, target_family = "wasm" => 2, target_arch = "hexagon" => 5, any(target_arch = "loongarch32", target_arch = "loongarch64") => 2, From 1890b8287ab14fcc1e0229fdde7327e4842331df Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 3 Aug 2026 15:50:34 +0200 Subject: [PATCH 53/98] Move wasi libunwind link block to crate root This matches other targets. --- library/unwind/src/lib.rs | 4 ++++ library/unwind/src/libunwind.rs | 7 ------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index eba08aec4d109..cfe8a925052a4 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -215,6 +215,10 @@ cfg_select! { #[link(name = "gcc_s")] unsafe extern "C" {} +#[cfg(all(target_os = "wasi", panic = "unwind"))] +#[link(name = "unwind")] +unsafe extern "C" {} + #[cfg(all(target_os = "windows", target_env = "gnu", target_abi = "llvm"))] #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] #[link(name = "unwind", cfg(not(target_feature = "crt-static")))] diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index bfa6b1b33008f..faf091e505e0b 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -26,13 +26,6 @@ pub enum _Unwind_Context {} all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), link(name = "unwind", kind = "static", modifiers = "-bundle") )] -// Explicitly link the `unwind` library on WASI targets. -// -// This is provided in the self-contained sysroot for WASI targets by default. -// Note that Rust defaults to `-Cpanic=abort` on WASI targets meaning that this -// doesn't end up getting used by default, but this does mean that with -// `-Zbuild-std` this'll automatically link it in. -#[cfg_attr(target_os = "wasi", link(name = "unwind"))] unsafe extern "C-unwind" { pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; } From e08ce7fbbb3f98e5379b9f8be58f6f55d1550381 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 24 Jul 2026 15:32:31 +0200 Subject: [PATCH 54/98] Avoid defining dummy personality function for Motor OS --- library/std/src/sys/personality/mod.rs | 3 ++- library/unwind/src/lib.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs index daa53703994b0..31bd457adbe6b 100644 --- a/library/std/src/sys/personality/mod.rs +++ b/library/std/src/sys/personality/mod.rs @@ -14,7 +14,7 @@ mod dwarf; #[cfg(not(any(test, doctest)))] cfg_select! { - any(target_env = "msvc", target_family = "wasm", target_os = "motor") => { + any(target_env = "msvc", target_family = "wasm") => { // This is required by the compiler to exist (e.g., it's a lang item), // but it's never actually called by the compiler because // __CxxFrameHandler3 (msvc) / __gxx_wasm_personality_v0 (wasm) is the @@ -41,6 +41,7 @@ cfg_select! { // - os=uefi // - os=espidf // - os=hermit + // - os=motor // - nvptx64-nvidia-cuda // - arch=avr } diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index cfe8a925052a4..69b5e81a39215 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -48,6 +48,7 @@ cfg_select! { // no unwinder on the system! // - os=none ("bare metal" targets) // - os=hermit + // - os=motor // - os=uefi // - os=cuda // - nvptx64-nvidia-cuda From 37831ee36e6ef86915c1f8cbb2202a2122981f20 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 28 Jul 2026 13:54:27 +0200 Subject: [PATCH 55/98] Use dummy panic_unwind impl for Hermit And change the dummy impl to use __rust_abort to match panic_abort. --- library/panic_unwind/src/dummy.rs | 11 ++++++++--- library/panic_unwind/src/hermit.rs | 20 -------------------- library/panic_unwind/src/lib.rs | 5 +---- 3 files changed, 9 insertions(+), 27 deletions(-) delete mode 100644 library/panic_unwind/src/hermit.rs diff --git a/library/panic_unwind/src/dummy.rs b/library/panic_unwind/src/dummy.rs index a0d6876691833..3ba0bec71b7bf 100644 --- a/library/panic_unwind/src/dummy.rs +++ b/library/panic_unwind/src/dummy.rs @@ -4,12 +4,17 @@ use alloc::boxed::Box; use core::any::Any; -use core::intrinsics; + +unsafe extern "Rust" { + // This is defined in std::rt + #[rustc_std_internal_symbol] + safe fn __rust_abort() -> !; +} pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box { - intrinsics::abort() + __rust_abort() } pub(crate) unsafe fn panic(_data: Box) -> u32 { - intrinsics::abort() + __rust_abort() } diff --git a/library/panic_unwind/src/hermit.rs b/library/panic_unwind/src/hermit.rs deleted file mode 100644 index b36d1a019fddb..0000000000000 --- a/library/panic_unwind/src/hermit.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Unwinding for *hermit* target. -//! -//! Right now we don't support this, so this is just stubs. - -use alloc::boxed::Box; -use core::any::Any; - -unsafe extern "Rust" { - // This is defined in std::rt - #[rustc_std_internal_symbol] - safe fn __rust_abort() -> !; -} - -pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box { - __rust_abort() -} - -pub(crate) unsafe fn panic(_data: Box) -> u32 { - __rust_abort() -} diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 1644a2495d97e..3f409be039567 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -32,10 +32,6 @@ use core::any::Any; use core::panic::PanicPayload; cfg_select! { - target_os = "hermit" => { - #[path = "hermit.rs"] - mod imp; - } any( all(target_family = "windows", target_env = "gnu"), target_os = "psp", @@ -64,6 +60,7 @@ cfg_select! { // - os=none ("bare metal" targets) // - os=uefi // - os=espidf + // - os=hermit // - nvptx64-nvidia-cuda // - arch=avr #[path = "dummy.rs"] From 29d3b9e3284cfe90d3285108f66d74bfdd13d331 Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Tue, 4 Aug 2026 11:16:47 +0000 Subject: [PATCH 56/98] Port stdarch-gen-arm to stdarch-gen-common --- library/stdarch/.github/workflows/main.yml | 9 +- library/stdarch/Cargo.lock | 1 + .../stdarch/crates/stdarch-gen-arm/Cargo.toml | 1 + .../crates/stdarch-gen-arm/src/main.rs | 163 +++++++++--------- 4 files changed, 85 insertions(+), 89 deletions(-) diff --git a/library/stdarch/.github/workflows/main.yml b/library/stdarch/.github/workflows/main.yml index b5b45f5f0d023..5c2e2ae4a8e21 100644 --- a/library/stdarch/.github/workflows/main.yml +++ b/library/stdarch/.github/workflows/main.yml @@ -320,6 +320,8 @@ jobs: needs: [style] name: Check stdarch-gen-{arm, loongarch, hexagon} output runs-on: ubuntu-latest + env: + STDARCH_GEN_MODE: check steps: - uses: actions/checkout@v6 - name: Install Rust @@ -327,22 +329,15 @@ jobs: - name: Check arm spec run: | cargo run --bin=stdarch-gen-arm --release -- crates/stdarch-gen-arm/spec - git diff --exit-code - name: Check loongarch lsx - env: - STDARCH_GEN_MODE: check run: | cargo run -p stdarch-gen-loongarch --release -- lsx git diff --exit-code - name: Check loongarch lasx - env: - STDARCH_GEN_MODE: check run: | cargo run -p stdarch-gen-loongarch --release -- lasx git diff --exit-code - name: Check hexagon - env: - STDARCH_GEN_MODE: check run: | cargo run -p stdarch-gen-hexagon --release git diff --exit-code diff --git a/library/stdarch/Cargo.lock b/library/stdarch/Cargo.lock index 427981218f431..9923b630cd5bb 100644 --- a/library/stdarch/Cargo.lock +++ b/library/stdarch/Cargo.lock @@ -831,6 +831,7 @@ dependencies = [ "serde", "serde_with", "serde_yaml", + "stdarch-gen-common", "walkdir", ] diff --git a/library/stdarch/crates/stdarch-gen-arm/Cargo.toml b/library/stdarch/crates/stdarch-gen-arm/Cargo.toml index 84f6249bb9517..cb284d5f2c57b 100644 --- a/library/stdarch/crates/stdarch-gen-arm/Cargo.toml +++ b/library/stdarch/crates/stdarch-gen-arm/Cargo.toml @@ -17,6 +17,7 @@ proc-macro2 = "1.0" quote = "1.0" regex = "1.5" serde = { version = "1.0", features = ["derive"] } +stdarch-gen-common = { path = "../stdarch-gen-common" } serde_with = { version = "3.2.0", default-features = false, features = ["macros"] } serde_yaml = "0.8" walkdir = "2.3.2" diff --git a/library/stdarch/crates/stdarch-gen-arm/src/main.rs b/library/stdarch/crates/stdarch-gen-arm/src/main.rs index 717a1707aafe3..1ccdcd8531066 100644 --- a/library/stdarch/crates/stdarch-gen-arm/src/main.rs +++ b/library/stdarch/crates/stdarch-gen-arm/src/main.rs @@ -21,87 +21,91 @@ use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; +use stdarch_gen_common::{Mode, run_generator}; use walkdir::WalkDir; fn main() -> Result<(), String> { - parse_args() + let (in_path, out_base) = parse_args(); + let mode = Mode::from_env(); + + for filepath in WalkDir::new(&in_path) .into_iter() - .map(|(filepath, out)| { - File::open(&filepath) - .map(|f| (f, filepath, out)) - .map_err(|e| format!("could not read input file: {e}")) - }) - .map(|res| { - let (file, filepath, out) = res?; - serde_yaml::from_reader(file) - .map(|input: input::GeneratorInput| (input, filepath, out)) - .map_err(|e| format!("could not parse input file: {e}")) + .filter_map(Result::ok) + .filter(|f| f.file_type().is_file()) + .filter(|f| f.file_name().to_string_lossy().ends_with(".yml")) + .map(|f| f.into_path()) + { + // Directory the harness checks/blesses against. The committed output + // location for this spec file (`///`). + let committed = make_output_filepath(&filepath, &out_base) + .parent() + .expect("generated output path must have a parent directory") + .to_path_buf(); + + run_generator(&committed, mode, |scratch: &Path| { + generate_spec(&filepath, scratch) }) - .collect::, _>>()? - .into_iter() - .map(|(input, filepath, out)| { - let intrinsics = input.intrinsics.into_iter() - .map(|intrinsic| { - intrinsic.generate_variants(&input.ctx) - }) - .try_collect() - .map(|mut vv: Vec<_>| { - vv.sort_by_cached_key(|variants| { - variants.first().map_or_else(String::default, |variant| { - variant.signature.fn_name().to_string() - }) - }); - vv.into_iter().flatten().collect_vec() - })?; + .map_err(|e| e.to_string())?; + } + Ok(()) +} - if input.ctx.generate_load_store_tests { - let loads = intrinsics.iter() - .filter_map(|i| { - if matches!(i.test, Test::Load(..)) { - Some(i.clone()) - } else { - None - } - }).collect(); - let stores = intrinsics.iter() - .filter_map(|i| { - if matches!(i.test, Test::Store(..)) { - Some(i.clone()) - } else { - None - } - }).collect(); - load_store_tests::generate_load_store_tests(loads, stores, out.as_ref().map(|o| make_tests_filepath(&filepath, o)).as_ref())?; - } +/// Generate the output files for a single spec file into `out_dir`. +fn generate_spec(filepath: &Path, out_dir: &Path) -> Result<(), String> { + let file = File::open(filepath).map_err(|e| format!("could not read input file: {e}"))?; + let input: input::GeneratorInput = + serde_yaml::from_reader(file).map_err(|e| format!("could not parse input file: {e}"))?; - Ok(( - input::GeneratorInput { - intrinsics, - ctx: input.ctx, - }, - filepath, - out, - )) - }) - .try_for_each( - |result: context::Result<(input::GeneratorInput, PathBuf, Option)>| -> context::Result { - let (generated, filepath, out) = result?; + let intrinsics = input + .intrinsics + .into_iter() + .map(|intrinsic| intrinsic.generate_variants(&input.ctx)) + .try_collect() + .map(|mut vv: Vec<_>| { + vv.sort_by_cached_key(|variants| { + variants.first().map_or_else(String::default, |variant| { + variant.signature.fn_name().to_string() + }) + }); + vv.into_iter().flatten().collect_vec() + })?; - let w = match out { - Some(out) => Box::new( - File::create(make_output_filepath(&filepath, &out)) - .map_err(|e| format!("could not create output file: {e}"))?, - ) as Box, - None => Box::new(std::io::stdout()) as Box, - }; + if input.ctx.generate_load_store_tests { + let loads = intrinsics + .iter() + .filter_map(|i| match i.test { + Test::Load(..) => Some(i.clone()), + _ => None, + }) + .collect(); + let stores = intrinsics + .iter() + .filter_map(|i| match i.test { + Test::Store(..) => Some(i.clone()), + _ => None, + }) + .collect(); + // Reuse make_tests_filepath to derive the correct leaf name + // (`ld_st_tests_.rs`), then write it into out_dir. + let tests_name = make_tests_filepath(filepath, Path::new("")) + .file_name() + .expect("load/store test path must have a file name") + .to_owned(); + let tests_path = out_dir.join(tests_name); + load_store_tests::generate_load_store_tests(loads, stores, Some(&tests_path))?; + } - generate_file(generated, w) - .map_err(|e| format!("could not generate output file: {e}")) - }, - ) + let generated = input::GeneratorInput { + intrinsics, + ctx: input.ctx, + }; + let out_file = File::create(out_dir.join("generated.rs")) + .map_err(|e| format!("could not create output file: {e}"))?; + generate_file(generated, Box::new(out_file) as Box) + .map_err(|e| format!("could not generate output file: {e}")) } -fn parse_args() -> Vec<(PathBuf, Option)> { +fn parse_args() -> (PathBuf, PathBuf) { let mut args_it = std::env::args().skip(1); assert!( 1 <= args_it.len() && args_it.len() <= 2, @@ -117,31 +121,26 @@ fn parse_args() -> Vec<(PathBuf, Option)> { "invalid path {in_path:#?} given" ); - let out_dir = if let Some(dir) = args_it.next() { + let out_base = if let Some(dir) = args_it.next() { let out_path = Path::new(dir.as_str()).to_path_buf(); assert!( out_path.exists() && out_path.is_dir(), "invalid path {out_path:#?} given" ); - Some(out_path) + out_path } else { std::env::current_exe() + .ok() .map(|mut f| { f.pop(); f.push("../../crates/core_arch/src/"); - f.exists().then_some(f) + f }) - .ok() - .flatten() + .filter(|f| f.exists()) + .expect("could not locate crates/core_arch/src; pass OUTPUT_DIR command-line argument explicitly") }; - WalkDir::new(in_path) - .into_iter() - .filter_map(Result::ok) - .filter(|f| f.file_type().is_file()) - .filter(|f| f.file_name().to_string_lossy().ends_with(".yml")) - .map(|f| (f.into_path(), out_dir.clone())) - .collect() + (in_path, out_base) } fn generate_file( From 78f89807d65b5784517dc993fc33433c0764d521 Mon Sep 17 00:00:00 2001 From: Valentyn Kit Date: Wed, 12 Aug 2026 11:02:20 +0300 Subject: [PATCH 57/98] std: map ERROR_NEGATIVE_SEEK to ErrorKind::InvalidInput on Windows Windows error mapping doesn't have an arm for `ERROR_NEGATIVE_SEEK`, the code returned when using negative seek position, so it decodes to `ErrorKind::Uncategorized`. Unix already maps the equivalent `EINVAL` to `InvalidInput` This adds the missing arm, on Windows to match with Unix. --- library/std/src/sys/io/error/windows.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/io/error/windows.rs b/library/std/src/sys/io/error/windows.rs index 3e6e281c61a75..0ca3aee389b3e 100644 --- a/library/std/src/sys/io/error/windows.rs +++ b/library/std/src/sys/io/error/windows.rs @@ -65,6 +65,7 @@ pub fn decode_error_kind(errno: i32) -> io::ErrorKind { c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename, c::ERROR_CANT_RESOLVE_FILENAME => return FilesystemLoop, c::ERROR_IO_DEVICE => return InputOutputError, + c::ERROR_NEGATIVE_SEEK => return InvalidInput, _ => {} } From 5cdd04f8b63567da014a749cbb6c922fc5792a38 Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Wed, 12 Aug 2026 22:11:48 +0200 Subject: [PATCH 58/98] Fix mentions of "`ai-assisted`" label in llm guidance docs The actual label we created is called `llm-assisted` now. --- src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md index 44ae4b9e6c2af..d78bdf60db1e3 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md @@ -17,12 +17,12 @@ ## Reviewing LLM-created code -First, add the new `ai-assisted` label to the PR. +First, add the new `llm-assisted` label to the PR. ### Rules We expect everyone to follow the new policy, not just authors. -That means it is **your responsibility** to check whether an `ai-assisted` PR touches an area that's disallowed by the policy. +That means it is **your responsibility** to check whether an `llm-assisted` PR touches an area that's disallowed by the policy. You may request that the author redo it without LLM-generated code, in which case this section doesn't apply. The following areas are currently banned: From fd86d6de55128f9faf2457ca3bfdb8b9358d14df Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 7 Jul 2026 16:50:00 +0000 Subject: [PATCH 59/98] x86_64-win: Enable f128 on LLVM 23+ LLVM23 includes the ABI fix to make f128 work [1]. That version isn't yet stable, but at least the type will start getting picked up in top-of-tree CI. While addressing this, also update the comment regarding f16. [1]: https://github.com/llvm/llvm-project/commit/aa47e59245e24edb6d0c7d5f91b3a1c5a7bb35f1 --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index feccbd953cc1c..298b58dd0007f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -374,7 +374,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { cfg.has_reliable_f16 = match (target_arch, target_os) { // Unsupported (fixed in llvm22) (Arch::Arm64EC, _) if major < 22 => false, - // MinGW ABI bugs + // MinGW ABI bugs resolved in GCC 16 + // but our toolchain hasn't been updated. (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != CfgAbi::Llvm => { false } @@ -401,8 +402,10 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { (Arch::PowerPC | Arch::PowerPC64, _) => false, // ABI unsupported (fixed in llvm22) (Arch::Sparc, _) if major < 22 => false, - // MinGW ABI bugs - (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != CfgAbi::Llvm => { + // MinGW ABI bugs (fixed in llvm23) + (Arch::X86_64, Os::Windows) + if *target_env == Env::Gnu && *target_abi != CfgAbi::Llvm && major < 23 => + { false } // There are no known problems on other platforms, so the only requirement is that symbols From 55650a293fdde121b7b766e403035a6f606bb522 Mon Sep 17 00:00:00 2001 From: Yukang Date: Thu, 13 Aug 2026 09:46:31 +0800 Subject: [PATCH 60/98] Add regression test for try block label suggestions --- .../invalid-label-suggestion-issue-160987.rs | 14 ++++++++++++++ .../invalid-label-suggestion-issue-160987.stderr | 15 +++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/ui/try-block/invalid-label-suggestion-issue-160987.rs create mode 100644 tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr diff --git a/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs b/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs new file mode 100644 index 0000000000000..01e03bc03e9e7 --- /dev/null +++ b/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs @@ -0,0 +1,14 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/160987. +//! A label suggested for a try block must use valid syntax. + +//@ edition: 2024 + +#![feature(try_blocks)] + +fn main() { + try { + break; + //~^ ERROR `break` outside of a loop or labeled block + None?; + }; +} diff --git a/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr b/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr new file mode 100644 index 0000000000000..4d539e176a453 --- /dev/null +++ b/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr @@ -0,0 +1,15 @@ +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/invalid-label-suggestion-issue-160987.rs:10:9 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ try 'block: { +LL ~ break 'block; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0268`. From c48651ad30123d2e70279f52498b01ce457bd0b9 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 11 Aug 2026 20:00:59 -0400 Subject: [PATCH 61/98] io: Use `NonNull` for all `Custom` API related to `Box` `*mut T` is used in a few places where we have a `NonNull`. Use `NonNull` everywhere to save a few conversions. --- library/alloc/src/io/error.rs | 15 ++++++++++++--- library/core/src/io/error.rs | 25 +++++++++++++------------ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/library/alloc/src/io/error.rs b/library/alloc/src/io/error.rs index 055d743dee6a1..7b3e4b06ae38a 100644 --- a/library/alloc/src/io/error.rs +++ b/library/alloc/src/io/error.rs @@ -250,13 +250,15 @@ fn custom_owner_from_box( kind: ErrorKind, error: Box, ) -> CustomOwner { + use core::ptr::NonNull; + /// # Safety /// /// `ptr` must be valid to pass into `Box::from_raw`. - unsafe fn drop_box_raw(ptr: *mut T) { + unsafe fn drop_box_raw(ptr: NonNull) { // SAFETY // Caller ensures `ptr` is valid to pass into `Box::from_raw`. - drop(unsafe { Box::from_raw(ptr) }) + drop(unsafe { Box::from_non_null(ptr) }) } let error = Box::into_non_null(error); @@ -266,7 +268,14 @@ fn custom_owner_from_box( // * `drop_box_raw` is safe to call for the pointer `error` exactly once. // * `drop_box_raw` is safe to call on a pointer to this instance of `Custom`, // and will be stored in a `CustomOwner`. - let custom = unsafe { Custom::from_raw(kind, error, drop_box_raw, drop_box_raw) }; + let custom = unsafe { + Custom::from_raw( + kind, + error, + drop_box_raw::, + drop_box_raw::, + ) + }; let custom = Box::into_non_null(Box::new(custom)); diff --git a/library/core/src/io/error.rs b/library/core/src/io/error.rs index 72d9fc7b72006..567461f22960e 100644 --- a/library/core/src/io/error.rs +++ b/library/core/src/io/error.rs @@ -29,6 +29,7 @@ mod os_functions; use self::os_functions::{decode_error_kind, format_os_error, is_interrupted, set_functions}; use self::repr::Repr; +use crate::ptr::NonNull; use crate::{error, fmt, result}; /// A specialized [`Result`] type for I/O operations. @@ -583,9 +584,9 @@ impl OsFunctions { #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub struct Custom { kind: ErrorKind, - error: crate::ptr::NonNull, - error_drop: unsafe fn(*mut (dyn error::Error + Send + Sync)), - outer_drop: unsafe fn(*mut Self), + error: NonNull, + error_drop: unsafe fn(NonNull), + outer_drop: unsafe fn(NonNull), } // SAFETY: All members of `Custom` are `Send` @@ -608,7 +609,7 @@ impl Drop for Custom { fn drop(&mut self) { // SAFETY: `Custom::from_raw` ensures this call is safe. unsafe { - (self.error_drop)(self.error.as_ptr()); + (self.error_drop)(self.error); } } } @@ -623,15 +624,15 @@ impl Custom { #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub unsafe fn from_raw( kind: ErrorKind, - error: crate::ptr::NonNull, - error_drop: unsafe fn(*mut (dyn error::Error + Send + Sync)), - outer_drop: unsafe fn(*mut Self), + error: NonNull, + error_drop: unsafe fn(NonNull), + outer_drop: unsafe fn(NonNull), ) -> Custom { Custom { kind, error, error_drop, outer_drop } } #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] - pub fn into_raw(self) -> crate::ptr::NonNull { + pub fn into_raw(self) -> NonNull { let ptr = self.error; core::mem::forget(self); ptr @@ -656,7 +657,7 @@ impl Custom { #[repr(transparent)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] #[doc(hidden)] -pub struct CustomOwner(crate::ptr::NonNull); +pub struct CustomOwner(NonNull); // SAFETY: Custom is `Send` #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] @@ -671,7 +672,7 @@ impl Drop for CustomOwner { fn drop(&mut self) { // SAFETY: `CustomOwner::from_raw` ensures this call is safe. unsafe { - (self.0.as_ref().outer_drop)(self.0.as_ptr()); + (self.0.as_ref().outer_drop)(self.0); } } } @@ -682,12 +683,12 @@ impl CustomOwner { /// * The `outer_drop` of the provided `custom` must be safe to call exactly once. #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] - pub unsafe fn from_raw(custom: crate::ptr::NonNull) -> CustomOwner { + pub unsafe fn from_raw(custom: NonNull) -> CustomOwner { CustomOwner(custom) } #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] - pub fn into_raw(self) -> crate::ptr::NonNull { + pub fn into_raw(self) -> NonNull { let ptr = self.0; core::mem::forget(self); ptr From 54a639147e9700f9b4f3d4b0d8502f6771db8102 Mon Sep 17 00:00:00 2001 From: Yukang Date: Thu, 13 Aug 2026 10:20:09 +0800 Subject: [PATCH 62/98] Fix invalid suggestion from try unlabled block --- compiler/rustc_hir_typeck/src/diagnostics.rs | 5 +++- compiler/rustc_hir_typeck/src/loops.rs | 29 ++++++++++++++----- ...nvalid-label-suggestion-issue-160987.fixed | 16 ++++++++++ .../invalid-label-suggestion-issue-160987.rs | 2 ++ ...valid-label-suggestion-issue-160987.stderr | 7 +++-- 5 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 tests/ui/try-block/invalid-label-suggestion-issue-160987.fixed diff --git a/compiler/rustc_hir_typeck/src/diagnostics.rs b/compiler/rustc_hir_typeck/src/diagnostics.rs index 722dfb0794ec1..fd74693e7f9fb 100644 --- a/compiler/rustc_hir_typeck/src/diagnostics.rs +++ b/compiler/rustc_hir_typeck/src/diagnostics.rs @@ -819,10 +819,13 @@ pub(crate) struct OutsideLoop<'a> { applicability = "maybe-incorrect" )] pub(crate) struct OutsideLoopSuggestion { - #[suggestion_part(code = "'block: ")] + #[suggestion_part(code = "{block_prefix}")] pub block_span: Span, #[suggestion_part(code = " 'block")] pub break_spans: Vec, + #[suggestion_part(code = " }}")] + pub wrap_end: Option, + pub block_prefix: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_typeck/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs index 21aad64f58d38..ea01744d5b64e 100644 --- a/compiler/rustc_hir_typeck/src/loops.rs +++ b/compiler/rustc_hir_typeck/src/loops.rs @@ -31,7 +31,10 @@ enum Context { kind: hir::CoroutineDesugaring, source: hir::CoroutineSource, }, - UnlabeledBlock(Span), + UnlabeledBlock { + label_span: Span, + wrap_end: Option, + }, UnlabeledIfBlock(Span), LabeledBlock, /// E.g. The labeled block inside `['_'; 'block: { break 'block 1 + 2; }]`. @@ -50,6 +53,7 @@ struct BlockInfo { name: String, spans: Vec, suggs: Vec, + wrap_end: Option, } #[derive(PartialEq)] @@ -118,7 +122,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { ck_loop.cx_stack.last(), Some(&Normal) | Some(&AnonConst) - | Some(&UnlabeledBlock(_)) + | Some(&UnlabeledBlock { .. }) | Some(&UnlabeledIfBlock(_)) ) { @@ -177,10 +181,16 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { None, ) if matches!( self.cx_stack.last(), - Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock(_)) + Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock { .. }) ) => { - self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b)); + // An unlabeled block targeted by `break` may comes from a `try` block. + // Since `try 'block: {}` is invalid, nest a labeled block inside its body. + let wrap_end = b.targeted_by_break.then(|| b.span.shrink_to_hi()); + self.with_context( + UnlabeledBlock { label_span: b.span.shrink_to_lo(), wrap_end }, + |v| v.visit_block(b), + ); } hir::ExprKind::Break(break_destination, ref opt_expr) => { if let Some(e) = opt_expr { @@ -365,13 +375,14 @@ impl<'hir> CheckLoopVisitor<'hir> { source, }); } - UnlabeledBlock(block_span) - if br_cx_kind == BreakContextKind::Break && block_span.eq_ctxt(break_span) => + UnlabeledBlock { label_span, wrap_end } + if br_cx_kind == BreakContextKind::Break && label_span.eq_ctxt(break_span) => { - let block = self.block_breaks.entry(block_span).or_insert_with(|| BlockInfo { + let block = self.block_breaks.entry(label_span).or_insert_with(|| BlockInfo { name: br_cx_kind.to_string(), spans: vec![], suggs: vec![], + wrap_end, }); block.spans.push(span); block.suggs.push(break_span); @@ -379,7 +390,7 @@ impl<'hir> CheckLoopVisitor<'hir> { UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => { self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1); } - Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => { + Normal | AnonConst | Fn | UnlabeledBlock { .. } | UnlabeledIfBlock(_) | ConstBlock => { self.tcx.dcx().emit_err(OutsideLoop { spans: vec![span], name: &br_cx_kind.to_string(), @@ -415,6 +426,8 @@ impl<'hir> CheckLoopVisitor<'hir> { suggestion: Some(OutsideLoopSuggestion { block_span: *s, break_spans: block.suggs.clone(), + block_prefix: if block.wrap_end.is_some() { "{ 'block: " } else { "'block: " }, + wrap_end: block.wrap_end, }), }); } diff --git a/tests/ui/try-block/invalid-label-suggestion-issue-160987.fixed b/tests/ui/try-block/invalid-label-suggestion-issue-160987.fixed new file mode 100644 index 0000000000000..c0b9eeb1189e9 --- /dev/null +++ b/tests/ui/try-block/invalid-label-suggestion-issue-160987.fixed @@ -0,0 +1,16 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/160987. +//! A label suggested for a try block must use valid syntax. + +//@ edition: 2024 +//@ run-rustfix + +#![feature(try_blocks)] +#![allow(unreachable_code)] + +fn main() { + try { 'block: { + break 'block; + //~^ ERROR `break` outside of a loop or labeled block + None?; + } }; +} diff --git a/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs b/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs index 01e03bc03e9e7..aab9c98313c91 100644 --- a/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs +++ b/tests/ui/try-block/invalid-label-suggestion-issue-160987.rs @@ -2,8 +2,10 @@ //! A label suggested for a try block must use valid syntax. //@ edition: 2024 +//@ run-rustfix #![feature(try_blocks)] +#![allow(unreachable_code)] fn main() { try { diff --git a/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr b/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr index 4d539e176a453..55e57242ac686 100644 --- a/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr +++ b/tests/ui/try-block/invalid-label-suggestion-issue-160987.stderr @@ -1,13 +1,16 @@ error[E0268]: `break` outside of a loop or labeled block - --> $DIR/invalid-label-suggestion-issue-160987.rs:10:9 + --> $DIR/invalid-label-suggestion-issue-160987.rs:12:9 | LL | break; | ^^^^^ cannot `break` outside of a loop or labeled block | help: consider labeling this block to be able to break within it | -LL ~ try 'block: { +LL ~ try { 'block: { LL ~ break 'block; +LL | +LL | None?; +LL ~ } }; | error: aborting due to 1 previous error From 57b5019a3d3ebc8ba768173538bf43d70fd10649 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 12 Aug 2026 13:57:16 -0400 Subject: [PATCH 63/98] io: Improve internal documentation for `Custom` error Add comments about what fields do and turn cross-method safety into easier to follow invariants. --- library/core/src/io/error.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/library/core/src/io/error.rs b/library/core/src/io/error.rs index 567461f22960e..8491a42537092 100644 --- a/library/core/src/io/error.rs +++ b/library/core/src/io/error.rs @@ -30,7 +30,7 @@ mod os_functions; use self::os_functions::{decode_error_kind, format_os_error, is_interrupted, set_functions}; use self::repr::Repr; use crate::ptr::NonNull; -use crate::{error, fmt, result}; +use crate::{error, fmt, mem, result}; /// A specialized [`Result`] type for I/O operations. /// @@ -576,6 +576,7 @@ impl OsFunctions { }; } +/// A user-created allocated error. // As with `SimpleMessage`: `#[repr(align(4))]` here is just because // repr_bitpacked's encoding requires it. In practice it almost certainly be // already be this high or higher. @@ -584,8 +585,13 @@ impl OsFunctions { #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub struct Custom { kind: ErrorKind, + /// `Box` without `alloc`. + // INVARIANT: `error` must be a valid pointer and it must be safe to call `error_drop` + // with it once. error: NonNull, error_drop: unsafe fn(NonNull), + /// Call to drop a pointer to `Custom`. + // INVARIANT: must be safe to call once with a pointer to `Self` in `CustomOwner`. outer_drop: unsafe fn(NonNull), } @@ -607,7 +613,7 @@ impl fmt::Debug for Custom { #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] impl Drop for Custom { fn drop(&mut self) { - // SAFETY: `Custom::from_raw` ensures this call is safe. + // SAFETY: by `Custom` invariants, this is a drop call on a valid pointer. unsafe { (self.error_drop)(self.error); } @@ -620,7 +626,7 @@ impl Custom { /// * `error` must be valid for up to a static lifetime, and own its pointee. /// * `error_drop` must be safe to call for the pointer `error` exactly once. /// * `outer_drop` must be safe to call on a pointer to this instance of `Custom` - /// if it were stored within a [`CustomOwner`]. + /// (the pointer is likely stored within a [`CustomOwner`]). #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub unsafe fn from_raw( kind: ErrorKind, @@ -628,13 +634,15 @@ impl Custom { error_drop: unsafe fn(NonNull), outer_drop: unsafe fn(NonNull), ) -> Custom { + // INVARIANT: function preconditions match type invariants. Custom { kind, error, error_drop, outer_drop } } #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub fn into_raw(self) -> NonNull { let ptr = self.error; - core::mem::forget(self); + // Avoid `Custom::drop` which would free the error pointer. + mem::forget(self); ptr } @@ -653,6 +661,8 @@ impl Custom { } } +/// Effectively a `Box` without `alloc`. The `Custom` holds the call to free this pointer. +// INVARIANT: `self.0.outer_drop` must be safe to call once with `self.0`. #[derive(Debug)] #[repr(transparent)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] @@ -670,7 +680,7 @@ unsafe impl Sync for CustomOwner {} #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] impl Drop for CustomOwner { fn drop(&mut self) { - // SAFETY: `CustomOwner::from_raw` ensures this call is safe. + // SAFETY: by `CustomOwner` invariants, this is a drop call on a valid pointer. unsafe { (self.0.as_ref().outer_drop)(self.0); } @@ -680,17 +690,20 @@ impl Drop for CustomOwner { impl CustomOwner { /// # Safety /// - /// * The `outer_drop` of the provided `custom` must be safe to call exactly once. + /// * `custom` must point to valid `Custom`. + /// * The `outer_drop` of the provided `custom` must be the drop function for this pointer. #[doc(hidden)] #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub unsafe fn from_raw(custom: NonNull) -> CustomOwner { + // INVARIANT: by the preconditions, `custom.outer_drop` is the drop for `custom`. CustomOwner(custom) } #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] pub fn into_raw(self) -> NonNull { let ptr = self.0; - core::mem::forget(self); + // Avoid `CustomOwner::drop`, which would free the pointer. + mem::forget(self); ptr } From adc30eb1ccf74a92d0460d48a7f46de2ffda4739 Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez Date: Thu, 23 Jul 2026 21:19:24 +0200 Subject: [PATCH 64/98] Add `feedable` query modifier --- .../src/queries/incremental-compilation-in-detail.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md index b6bac0fea3ef3..823090c24ade3 100644 --- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md @@ -485,6 +485,12 @@ respect to incremental compilation: be cached to disk for "local" keys, because values for external crates should be loadable from crate metadata instead. + - `feedable` - The query is not actually a function, but its own arena type. This + is done to declare an arena, "feed" the information + to store at a later point in the compilation (for example, when we actually have a + `Crate` object available), and then retrieve it as any other crate. Thus, function + definitions for these queries do not exist. + [mod]: ../query.html#adding-a-new-kind-of-query @@ -553,4 +559,4 @@ See for more information. [query-model]: ./query-evaluation-model-in-detail.html -[try_mark_green]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/dep_graph/graph.rs.html +[try_mark_green]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/dep_graph/graph.rs.html \ No newline at end of file From 6a823d31d29994a994ee54124730d44610cd2dfe Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:34:51 +0200 Subject: [PATCH 65/98] sembr src/queries/incremental-compilation-in-detail.md --- .../src/queries/incremental-compilation-in-detail.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md index 823090c24ade3..71a48c3e377fc 100644 --- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md @@ -485,11 +485,11 @@ respect to incremental compilation: be cached to disk for "local" keys, because values for external crates should be loadable from crate metadata instead. - - `feedable` - The query is not actually a function, but its own arena type. This - is done to declare an arena, "feed" the information + - `feedable` - The query is not actually a function, but its own arena type. + This is done to declare an arena, "feed" the information to store at a later point in the compilation (for example, when we actually have a - `Crate` object available), and then retrieve it as any other crate. Thus, function - definitions for these queries do not exist. + `Crate` object available), and then retrieve it as any other crate. + Thus, function definitions for these queries do not exist. [mod]: ../query.html#adding-a-new-kind-of-query @@ -559,4 +559,4 @@ See for more information. [query-model]: ./query-evaluation-model-in-detail.html -[try_mark_green]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/dep_graph/graph.rs.html \ No newline at end of file +[try_mark_green]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/dep_graph/graph.rs.html From fa6c1ba66dc4de0da7eb006d837065d085a26919 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:35:19 +0200 Subject: [PATCH 66/98] align --- .../src/queries/incremental-compilation-in-detail.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md index 71a48c3e377fc..28618cbb082a0 100644 --- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md @@ -487,10 +487,10 @@ respect to incremental compilation: - `feedable` - The query is not actually a function, but its own arena type. This is done to declare an arena, "feed" the information - to store at a later point in the compilation (for example, when we actually have a - `Crate` object available), and then retrieve it as any other crate. - Thus, function definitions for these queries do not exist. - + to store at a later point in the compilation (for example, when we actually have a + `Crate` object available), and then retrieve it as any other crate. + Thus, function definitions for these queries do not exist. + [mod]: ../query.html#adding-a-new-kind-of-query From 66cf60318a721a4afdf1d8364bbc98874e847bbe Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:42:21 +0200 Subject: [PATCH 67/98] sembr src/llm-guidance/reviewing.md --- .../rustc-dev-guide/src/llm-guidance/reviewing.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md index d78bdf60db1e3..439b1d809e706 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md @@ -9,8 +9,8 @@ For example, if you have a codebase-specific wrapper around command spawning, rather than getting an LLM to look for places where you should use the wrapper, [configure clippy to disallow `Command::new`][disallowed-methods]. -- LLMs sometimes prefer LLM-generated output, particularly output from the same - model. Treat LLM review as advisory, and do not rely on the model that +- LLMs sometimes prefer LLM-generated output, particularly output from the same model. + Treat LLM review as advisory, and do not rely on the model that produced a change as its only reviewer. [disallowed-methods]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-methods @@ -26,9 +26,12 @@ That means it is **your responsibility** to check whether an `llm-assisted` PR t You may request that the author redo it without LLM-generated code, in which case this section doesn't apply. The following areas are currently banned: -- Code that affects soundness. If the author is not an org member who is experienced in the domain, you are required to close the PR. -- Diagnostics. All user-facing diagnostics must be human-written. -- Docs. All public doc-comments, and all `// SAFETY` comments, must be human-written. +- Code that affects soundness. + If the author is not an org member who is experienced in the domain, you are required to close the PR. +- Diagnostics. + All user-facing diagnostics must be human-written. +- Docs. + All public doc-comments, and all `// SAFETY` comments, must be human-written. "Code that affects soundness" is both broader and narrower than it sounds. It's broader because almost all of the compiler is relevant to soundness; From 3aba612b6b1ab8bd34b076e2dbbd62f9e3436d47 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:43:54 +0200 Subject: [PATCH 68/98] sembr src/llm-guidance/writing.md --- .../src/llm-guidance/writing.md | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md index 6af83fd4246cb..3cbdf3d2b849c 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/writing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md @@ -107,8 +107,9 @@ Commit messages must be authored by you, not your LLM. ### Before opening a PR -Review your own PR before opening it: -Does it make sense? Can you tell what the goal of the PR is? Does it achieve that goal? +Review your own PR before opening it: Does it make sense? +Can you tell what the goal of the PR is? +Does it achieve that goal? Remove outdated or prototyping code and debugging. @@ -135,12 +136,19 @@ Asking the LLM can be a starting point but it's not the same as explaining it yo Try explaining your change to yourself before opening the PR. For example, ask yourself: -- What is the original bug? When does it happen? How severe is it? What causes it? -- Why is this the right fix? Are there other fixes possible? What are their advantages or disadvantages? -- Are there any edge cases? Does your code handle them? +- What is the original bug? + When does it happen? + How severe is it? + What causes it? +- Why is this the right fix? + Are there other fixes possible? + What are their advantages or disadvantages? +- Are there any edge cases? + Does your code handle them? - Does the code have existing [invariants](https://brooker.co.za/blog/2023/07/28/ds-testing.html)? Did you preserve those invariants? -- What behavior is *unchanged*? What test establishes that? +- What behavior is *unchanged*? + What test establishes that? - Why does your test trigger the bug? - What are you still not certain about? From b011266b95d5dd5bce22b5114b7b1afe2a808799 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:44:45 +0200 Subject: [PATCH 69/98] sembr src/opaque-types-type-alias-impl-trait.md --- .../src/opaque-types-type-alias-impl-trait.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md b/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md index 9f20bfc708dce..239f30843ee67 100644 --- a/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md +++ b/src/doc/rustc-dev-guide/src/opaque-types-type-alias-impl-trait.md @@ -10,8 +10,8 @@ This is expressed by using `impl Trait` within type aliases, for example: type Foo = impl Bar; ``` -This declares an opaque type named `Foo`, of which the only information is that -it implements `Bar`. Therefore, any of `Bar`'s interface can be used on a `Foo`, +This declares an opaque type named `Foo`, of which the only information is that it implements `Bar`. +Therefore, any of `Bar`'s interface can be used on a `Foo`, but nothing else (regardless of whether the concrete type implements any other traits). Since there needs to be a concrete background type, @@ -53,12 +53,11 @@ fn foo() -> Foo { ## Defining use site(s) Currently only the return value of a function can be a defining use site -of an opaque type (and only if the return type of that function contains -the opaque type). +of an opaque type (and only if the return type of that function contains the opaque type). The defining use of an opaque type can be any code *within* the parent -of the opaque type definition. This includes any siblings of the -opaque type and all children of the siblings. +of the opaque type definition. +This includes any siblings of the opaque type and all children of the siblings. The initiative for *"not causing fatal brain damage to developers due to accidentally running infinite loops in their brain while trying to @@ -68,7 +67,8 @@ of opaque types to be defining use sites. ### Associated opaque types Associated opaque types can be defined by any other associated item -on the same trait `impl` or a child of these associated items. For instance: +on the same trait `impl` or a child of these associated items. +For instance: ```rust,ignore trait Baz { From c47f10a86512a281ff785d00c8111c5358ed2731 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:45:30 +0200 Subject: [PATCH 70/98] sembr src/hir/attribute-parsing.md --- src/doc/rustc-dev-guide/src/hir/attribute-parsing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/hir/attribute-parsing.md b/src/doc/rustc-dev-guide/src/hir/attribute-parsing.md index bc0240faec661..fb544a680fa8f 100644 --- a/src/doc/rustc-dev-guide/src/hir/attribute-parsing.md +++ b/src/doc/rustc-dev-guide/src/hir/attribute-parsing.md @@ -81,4 +81,4 @@ In other words, we expect attributes parsed with `parse_limited` to be reparsed [template!]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/macro.template.html [find_attr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_ir/macro.find_attr.html [parse_limited]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/interface/struct.AttributeParser.html#method.parse_limited -[`AttributeKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_ir/enum.AttributeKind.html \ No newline at end of file +[`AttributeKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_ir/enum.AttributeKind.html From e8d39b87aeff31b0845ce83055e7c077d837e9fa Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:46:14 +0200 Subject: [PATCH 71/98] sembr src/diagnostics/error-guaranteed.md --- .../src/diagnostics/error-guaranteed.md | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics/error-guaranteed.md b/src/doc/rustc-dev-guide/src/diagnostics/error-guaranteed.md index d0ff775da80e6..950e36ef33178 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/error-guaranteed.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/error-guaranteed.md @@ -1,32 +1,31 @@ # `ErrorGuaranteed` -The previous sections have been about the error message that a user of the -compiler sees. But emitting an error can also have a second important side -effect within the compiler source code: it generates an -[`ErrorGuaranteed`][errorguar]. +The previous sections have been about the error message that a user of the compiler sees. +But emitting an error can also have a second important side +effect within the compiler source code: it generates an [`ErrorGuaranteed`][errorguar]. `ErrorGuaranteed` is a zero-sized type that is unconstructable outside of the -[`rustc_errors`][rerrors] crate. It is generated whenever an error is reported +[`rustc_errors`][rerrors] crate. +It is generated whenever an error is reported to the user, so that if your compiler code ever encounters a value of type -`ErrorGuaranteed`, the compilation is _statically guaranteed to fail_. This is -useful for avoiding unsoundness bugs because you can statically check that an +`ErrorGuaranteed`, the compilation is _statically guaranteed to fail_. +This is useful for avoiding unsoundness bugs because you can statically check that an error code path leads to a failure. There are some important considerations about the usage of `ErrorGuaranteed`: -* It does _not_ convey information about the _kind_ of error. For example, the - error may be due (indirectly) to a delayed bug or other compiler error. +* It does _not_ convey information about the _kind_ of error. + For example, the error may be due (indirectly) to a delayed bug or other compiler error. Thus, you should not rely on - `ErrorGuaranteed` when deciding whether to emit an error, or what kind of error - to emit. + `ErrorGuaranteed` when deciding whether to emit an error, or what kind of error to emit. * `ErrorGuaranteed` should not be used to indicate that a compilation _will - emit_ an error in the future. It should be used to indicate that an error - _has already been_ emitted -- that is, the [`emit()`][emit] function has - already been called. For example, if we detect that a future part of the + emit_ an error in the future. + It should be used to indicate that an error + _has already been_ emitted -- that is, the [`emit()`][emit] function has already been called. + For example, if we detect that a future part of the compiler will error, we _cannot_ use `ErrorGuaranteed` unless we first emit an error or delayed bug ourselves. -Thankfully, in most cases, it should be statically impossible to abuse -`ErrorGuaranteed`. +Thankfully, in most cases, it should be statically impossible to abuse `ErrorGuaranteed`. [errorguar]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.ErrorGuaranteed.html [rerrors]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html From 8b93983071028fa8f3cd387e9653e91eb11fffa5 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:49:46 +0200 Subject: [PATCH 72/98] improve src/stability.md --- .../src/diagnostics/error-guaranteed.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics/error-guaranteed.md b/src/doc/rustc-dev-guide/src/diagnostics/error-guaranteed.md index 950e36ef33178..0e9fa1ca057ac 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/error-guaranteed.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/error-guaranteed.md @@ -1,10 +1,11 @@ # `ErrorGuaranteed` + The previous sections have been about the error message that a user of the compiler sees. But emitting an error can also have a second important side -effect within the compiler source code: it generates an [`ErrorGuaranteed`][errorguar]. +effect within the compiler source code: it generates an [`ErrorGuaranteed`]. `ErrorGuaranteed` is a zero-sized type that is unconstructable outside of the -[`rustc_errors`][rerrors] crate. +[`rustc_errors`] crate. It is generated whenever an error is reported to the user, so that if your compiler code ever encounters a value of type `ErrorGuaranteed`, the compilation is _statically guaranteed to fail_. @@ -21,12 +22,12 @@ There are some important considerations about the usage of `ErrorGuaranteed`: emit_ an error in the future. It should be used to indicate that an error _has already been_ emitted -- that is, the [`emit()`][emit] function has already been called. - For example, if we detect that a future part of the + For example, if we detect that a future part of the compiler will error, we _cannot_ use `ErrorGuaranteed` unless we first emit an error or delayed bug ourselves. Thankfully, in most cases, it should be statically impossible to abuse `ErrorGuaranteed`. -[errorguar]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.ErrorGuaranteed.html -[rerrors]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html +[`ErrorGuaranteed`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.ErrorGuaranteed.html +[`rustc_errors`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html [emit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/diagnostic/struct.Diag.html#method.emit From 6bf26fb840dd9fc6ec5543c77ee58a903bbc09d3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:50:29 +0200 Subject: [PATCH 73/98] sembr src/debuginfo/testing.md --- src/doc/rustc-dev-guide/src/debuginfo/testing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/debuginfo/testing.md b/src/doc/rustc-dev-guide/src/debuginfo/testing.md index 7aec83aa97ac6..293a5d2a5cfbc 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/testing.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/testing.md @@ -1,7 +1,7 @@ # Testing -The debug info test suite is undergoing a substantial rewrite. This section will be filled out as -the rewrite makes progress. +The debug info test suite is undergoing a substantial rewrite. +This section will be filled out as the rewrite makes progress. Please see [this tracking issue][148483] for more information. From 24b66a7f94a34655ee1b792a8cda39c1b4ff71c4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:50:58 +0200 Subject: [PATCH 74/98] sembr src/tests/stdlib-semver-check.md --- .../src/tests/stdlib-semver-check.md | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md b/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md index 60923d57cceef..7fbd531bf9b44 100644 --- a/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md +++ b/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md @@ -1,21 +1,32 @@ # Standard library semantic versioning breakage check -The `x86_64-gnu-stdlib-semver-check` job runs the [`cargo-semver-checks`][csc] (c-s-c) tool on the standard library (`core`, `alloc` and `std`) in order to find potential unintended semantic versioning (semver) breakages. It does so by analyzing the rustdoc JSON output (from the `rust-docs-json` component) of the parent merge commit, and the current commit being merged. When it runs, one of five things can happen: +The `x86_64-gnu-stdlib-semver-check` job runs the [`cargo-semver-checks`][csc] (c-s-c) tool on the standard library (`core`, `alloc` and `std`) in order to find potential unintended semantic versioning (semver) breakages. +It does so by analyzing the rustdoc JSON output (from the `rust-docs-json` component) of the parent merge commit, and the current commit being merged. +When it runs, one of five things can happen: 1. Everything proceeds correctly, c-s-c does not find any breakage. -2. The rustdoc JSON version was bumped recently, and c-s-c cannot handle it yet. This case will result in the test ending with a success, and printing a warning that c-s-c needs to be updated. Once c-s-c releases a version that supports the new JSON format, it should go to 1. again. +2. The rustdoc JSON version was bumped recently, and c-s-c cannot handle it yet. + This case will result in the test ending with a success, and printing a warning that c-s-c needs to be updated. + Once c-s-c releases a version that supports the new JSON format, it should go to 1. again. - We currently install the latest released version of c-s-c in this job, so its version does not need to be updated manually in the `rust-lang/rust` repository. -3. c-s-c detects a breakage, but it is a false positive. In this case, please report the false positive to [this][semver-topic] Zulip channel, and [bump the stamp file](#bumping-the-stdlib-semver-stamp-file). -4. c-s-c detects a real breakage, and it helped you find unintended beakage. Yay! In this case, please consider reporting the success to [this][semver-topic] Zulip channel. -5. c-s-c detects a real breakage, but you want to land it anyway (maybe it is an edge case that was FCPed). In that case, [bump the stamp file](#bumping-the-stdlib-semver-stamp-file). +3. c-s-c detects a breakage, but it is a false positive. + In this case, please report the false positive to [this][semver-topic] Zulip channel, and [bump the stamp file](#bumping-the-stdlib-semver-stamp-file). +4. c-s-c detects a real breakage, and it helped you find unintended beakage. + Yay! + In this case, please consider reporting the success to [this][semver-topic] Zulip channel. +5. c-s-c detects a real breakage, but you want to land it anyway (maybe it is an edge case that was FCPed). + In that case, [bump the stamp file](#bumping-the-stdlib-semver-stamp-file). ## Bumping the stdlib semver stamp file -If you want to let CI pass on a PR where c-s-c detects breakage (whether it is real or not), you have to modify the `src/bootstrap/stdlib-semver-check-stamp` file. Please update the PR number in which you modify this file at the bottom of the file. This will ensure that the test will stay green, regardless of what c-s-c detects. +If you want to let CI pass on a PR where c-s-c detects breakage (whether it is real or not), you have to modify the `src/bootstrap/stdlib-semver-check-stamp` file. +Please update the PR number in which you modify this file at the bottom of the file. +This will ensure that the test will stay green, regardless of what c-s-c detects. ## Running the check manually -You can manually run the semver check locally using `./x test std-semver-check --set rust.stdlib-semver-baseline=${PARENT}`, where `PARENT` is a commit SHA against which you want to compare the in-tree stdlib. If you do not specify it, bootstrap will select the latest upstream commit that it finds in your local git history. +You can manually run the semver check locally using `./x test std-semver-check --set rust.stdlib-semver-baseline=${PARENT}`, where `PARENT` is a commit SHA against which you want to compare the in-tree stdlib. +If you do not specify it, bootstrap will select the latest upstream commit that it finds in your local git history. [semver-topic]: https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/Breakages.20detected.20by.20cargo-semver-checks/with/615570111 [csc]: https://github.com/obi1kenobi/cargo-semver-checks From fd1d77ffeccfe3314905fc5293b7c2b66c293d01 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:56:04 +0200 Subject: [PATCH 75/98] improve tests/stdlib-semver-check.md --- src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md b/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md index 7fbd531bf9b44..b560568811d48 100644 --- a/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md +++ b/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md @@ -10,10 +10,10 @@ When it runs, one of five things can happen: Once c-s-c releases a version that supports the new JSON format, it should go to 1. again. - We currently install the latest released version of c-s-c in this job, so its version does not need to be updated manually in the `rust-lang/rust` repository. 3. c-s-c detects a breakage, but it is a false positive. - In this case, please report the false positive to [this][semver-topic] Zulip channel, and [bump the stamp file](#bumping-the-stdlib-semver-stamp-file). + In this case, please report the false positive to [this Zulip topic][semver-topic], and [bump the stamp file](#bumping-the-stdlib-semver-stamp-file). 4. c-s-c detects a real breakage, and it helped you find unintended beakage. Yay! - In this case, please consider reporting the success to [this][semver-topic] Zulip channel. + In this case, please consider reporting the success to [this Zulip topic][semver-topic]. 5. c-s-c detects a real breakage, but you want to land it anyway (maybe it is an edge case that was FCPed). In that case, [bump the stamp file](#bumping-the-stdlib-semver-stamp-file). From 5f4b0918279294fd08129ab994b9e59050793a11 Mon Sep 17 00:00:00 2001 From: SomeFlyingThing <306498559+SomeFlyingThing@users.noreply.github.com> Date: Thu, 13 Aug 2026 02:56:27 -0700 Subject: [PATCH 76/98] Optimize CStr backing slice bounds checks --- library/core/src/ffi/c_str.rs | 7 +++++- .../cstr-nonempty-no-bounds-check.rs | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tests/codegen-llvm/cstr-nonempty-no-bounds-check.rs diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index d3318b0863e6e..10fab83eda348 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -582,7 +582,12 @@ impl CStr { pub const fn to_bytes_with_nul(&self) -> &[u8] { // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s // is safe on all supported targets. - unsafe { &*((&raw const self.inner) as *const [u8]) } + let bytes = unsafe { &*((&raw const self.inner) as *const [u8]) }; + + // SAFETY: A valid `CStr` always contains at least its trailing nul byte. + unsafe { crate::hint::assert_unchecked(!bytes.is_empty()) }; + + bytes } /// Iterates over the bytes in this C string. diff --git a/tests/codegen-llvm/cstr-nonempty-no-bounds-check.rs b/tests/codegen-llvm/cstr-nonempty-no-bounds-check.rs new file mode 100644 index 0000000000000..252735883aa5e --- /dev/null +++ b/tests/codegen-llvm/cstr-nonempty-no-bounds-check.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -Copt-level=3 -Cpanic=abort + +#![crate_type = "lib"] + +use std::ffi::CStr; + +// A `CStr` always contains at least its trailing nul byte. + +// CHECK-LABEL: @cstr_with_nul_is_nonempty +#[no_mangle] +pub fn cstr_with_nul_is_nonempty(s: &CStr) -> bool { + // CHECK: ret i1 true + !s.to_bytes_with_nul().is_empty() +} + +// CHECK-LABEL: @cstr_first_with_nul +#[no_mangle] +pub fn cstr_first_with_nul(s: &CStr) -> u8 { + // CHECK-NOT: panic_bounds_check + // CHECK: ret i8 + s.to_bytes_with_nul()[0] +} From c490377e3c13bcfb2eaf4034be04fb1f480ecac0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:57:19 +0200 Subject: [PATCH 77/98] reflow --- .../src/tests/stdlib-semver-check.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md b/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md index b560568811d48..af1116f69e75b 100644 --- a/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md +++ b/src/doc/rustc-dev-guide/src/tests/stdlib-semver-check.md @@ -6,11 +6,14 @@ When it runs, one of five things can happen: 1. Everything proceeds correctly, c-s-c does not find any breakage. 2. The rustdoc JSON version was bumped recently, and c-s-c cannot handle it yet. - This case will result in the test ending with a success, and printing a warning that c-s-c needs to be updated. + This case will result in the test ending with a success, + and printing a warning that c-s-c needs to be updated. Once c-s-c releases a version that supports the new JSON format, it should go to 1. again. - - We currently install the latest released version of c-s-c in this job, so its version does not need to be updated manually in the `rust-lang/rust` repository. + - We currently install the latest released version of c-s-c in this job,r + so its version does not need to be updated manually in the `rust-lang/rust` repository. 3. c-s-c detects a breakage, but it is a false positive. - In this case, please report the false positive to [this Zulip topic][semver-topic], and [bump the stamp file](#bumping-the-stdlib-semver-stamp-file). + In this case, please report the false positive to [this Zulip topic][semver-topic], +and [bump the stamp file](#bumping-the-stdlib-semver-stamp-file). 4. c-s-c detects a real breakage, and it helped you find unintended beakage. Yay! In this case, please consider reporting the success to [this Zulip topic][semver-topic]. @@ -19,14 +22,17 @@ When it runs, one of five things can happen: ## Bumping the stdlib semver stamp file -If you want to let CI pass on a PR where c-s-c detects breakage (whether it is real or not), you have to modify the `src/bootstrap/stdlib-semver-check-stamp` file. +If you want to let CI pass on a PR where c-s-c detects breakage (whether it is real or not), +you have to modify the `src/bootstrap/stdlib-semver-check-stamp` file. Please update the PR number in which you modify this file at the bottom of the file. This will ensure that the test will stay green, regardless of what c-s-c detects. ## Running the check manually -You can manually run the semver check locally using `./x test std-semver-check --set rust.stdlib-semver-baseline=${PARENT}`, where `PARENT` is a commit SHA against which you want to compare the in-tree stdlib. -If you do not specify it, bootstrap will select the latest upstream commit that it finds in your local git history. +You can manually run the semver check locally using `./x test std-semver-check --set rust.stdlib-semver-baseline=${PARENT}`, +where `PARENT` is a commit SHA against which you want to compare the in-tree stdlib. +If you do not specify it, +bootstrap will select the latest upstream commit that it finds in your local git history. [semver-topic]: https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/Breakages.20detected.20by.20cargo-semver-checks/with/615570111 [csc]: https://github.com/obi1kenobi/cargo-semver-checks From cda814cbcb341e1ade7c68e0bc2dbdded27fb5d2 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 11:58:11 +0200 Subject: [PATCH 78/98] sembr src/profile-guided-optimization.md --- .../src/profile-guided-optimization.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/profile-guided-optimization.md b/src/doc/rustc-dev-guide/src/profile-guided-optimization.md index f8a07813a10eb..191d612b45a60 100644 --- a/src/doc/rustc-dev-guide/src/profile-guided-optimization.md +++ b/src/doc/rustc-dev-guide/src/profile-guided-optimization.md @@ -1,8 +1,7 @@ # Profile-guided optimization `rustc` supports doing profile-guided optimization (PGO). -This chapter describes what PGO is and how the support for it is -implemented in `rustc`. +This chapter describes what PGO is and how the support for it is implemented in `rustc`. ## What is profiled-guided optimization? @@ -35,13 +34,13 @@ LLVM actually [supports multiple forms][clang-pgo] of PGO: itself during optimization passes. `rustc` supports only the last approach, IR-level instrumentation, mainly -because it is almost exclusively implemented in LLVM and needs little -maintenance on the Rust side. Fortunately, it is also the most modern approach, +because it is almost exclusively implemented in LLVM and needs little maintenance on the Rust side. +Fortunately, it is also the most modern approach, yielding the best results. So, we are dealing with an instrumentation-based approach, i.e. profiling data -is generated by a specially instrumented version of the program that's being -optimized. Instrumentation-based PGO has two components: a compile-time +is generated by a specially instrumented version of the program that's being optimized. +Instrumentation-based PGO has two components: a compile-time component and run-time component, and one needs to understand the overall workflow to see how they interact. @@ -89,8 +88,8 @@ runtime are not removed [by marking the with the right export level][pgo-gen-sym #### Compile binaries where optimizations make use of profiling data In the final step of the workflow described above, the program is compiled -again, with the compiler using the gathered profiling data in order to drive -optimization decisions. `rustc` again leaves most of the work to LLVM here, +again, with the compiler using the gathered profiling data in order to drive optimization decisions. +`rustc` again leaves most of the work to LLVM here, basically [just telling][pgo-use-passmanager] the LLVM `PassManagerBuilder` where the profiling data can be found: @@ -112,8 +111,7 @@ to generate profiling data, and collecting and persisting this profiling data needs some infrastructure in place. In the case of LLVM, these runtime components are implemented in -[compiler-rt][compiler-rt-profile] and statically linked into any instrumented -binaries. +[compiler-rt][compiler-rt-profile] and statically linked into any instrumented binaries. The `rustc` version of this can be found in `library/profiler_builtins` which basically packs the C code from `compiler-rt` into a Rust crate. From ca1b03488b8ff7cf1b48492cd8bed3a20ada3c20 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 12 Aug 2026 20:16:24 +0200 Subject: [PATCH 79/98] disallow `#[cold]` on `extern "custom"` functions --- .../rustc_ast_passes/src/ast_validation.rs | 41 +++++- compiler/rustc_ast_passes/src/diagnostics.rs | 34 +++++ .../rustc_hir_analysis/src/check/check.rs | 14 +- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../rustc_hir_analysis/src/diagnostics.rs | 16 --- compiler/rustc_hir_typeck/src/lib.rs | 5 +- tests/ui/abi/bad-custom.rs | 19 ++- tests/ui/abi/bad-custom.stderr | 127 ++++++++++-------- 8 files changed, 160 insertions(+), 98 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index f64d499d1bde0..3270fb940bab3 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -38,7 +38,7 @@ use rustc_session::lint::builtin::{ use rustc_span::{Ident, Span, Symbol, kw, sym}; use rustc_target::spec::{AbiMap, AbiMapping}; -use crate::diagnostics::{self, TildeConstReason}; +use crate::diagnostics::{self, AbiCustomCannotBeCold, AbiCustomMustBeNaked, TildeConstReason}; /// Is `self` allowed semantically as the first parameter in an `FnDecl`? enum SelfSemantic { @@ -899,6 +899,44 @@ impl<'a> AstValidator<'a> { } } + /// Check the attributes on an `extern "custom"` function: + /// + /// - require `#[naked]` + /// - reject `#[cold]` (these functions cannot be called so `#[cold]` is meaningless) + fn check_extern_custom(&self, fk: FnKind<'_>, attrs: &AttrVec) { + let FnKind::Fn(fn_ctxt, _, Fn { sig, body: Some(_), .. }) = fk else { + return; + }; + + match fn_ctxt { + FnCtxt::Foreign => return, + FnCtxt::Free | FnCtxt::Assoc(_) => { /* fall through */ } + } + + let Extern::Explicit(StrLit { symbol_unescaped, .. }, ext_span) = sig.header.ext else { + return; + }; + + let Ok(ExternAbi::Custom) = ExternAbi::from_str(symbol_unescaped.as_str()) else { + return; + }; + + if !attr::contains_name(attrs, sym::naked) { + self.dcx().emit_err(AbiCustomMustBeNaked { + span: sig.span, + naked_span: sig.span.shrink_to_lo(), + }); + } + + if let Some(cold) = attr::find_by_name(attrs, sym::cold) { + self.dcx().emit_err(AbiCustomCannotBeCold { + span: sig.span, + abi_span: ext_span, + cold_span: cold.span, + }); + } + } + /// Reject invalid C-variadic types. /// /// C-variadics must be: @@ -1937,6 +1975,7 @@ impl Visitor<'_> for AstValidator<'_> { } } + self.check_extern_custom(fk, attrs); self.check_c_variadic_type(fk, attrs); // Functions cannot both be `const async` or `const gen` diff --git a/compiler/rustc_ast_passes/src/diagnostics.rs b/compiler/rustc_ast_passes/src/diagnostics.rs index 0814c79d339bd..93711b40e0884 100644 --- a/compiler/rustc_ast_passes/src/diagnostics.rs +++ b/compiler/rustc_ast_passes/src/diagnostics.rs @@ -1264,3 +1264,37 @@ pub(crate) struct VarargsWithoutPattern { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag( + "an `extern \"custom\"` function can only be declared externally or defined via naked functions" +)] +pub(crate) struct AbiCustomMustBeNaked { + #[primary_span] + pub span: Span, + #[suggestion( + "convert this to an `#[unsafe(naked)]` function", + applicability = "maybe-incorrect", + code = "#[unsafe(naked)]\n", + style = "short" + )] + pub naked_span: Span, +} + +#[derive(Diagnostic)] +#[diag("an `extern \"custom\"` function cannot be marked `#[cold]`")] +pub(crate) struct AbiCustomCannotBeCold { + #[primary_span] + pub span: Span, + + #[suggestion( + "remove the `#[cold]` attribute", + applicability = "maybe-incorrect", + code = "", + style = "short" + )] + pub cold_span: Span, + + #[label("`extern \"custom\"` because of this")] + pub abi_span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index d98125f7cd9f9..32960bd370172 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::util::Discr; use rustc_middle::ty::{ - AdtDef, BottomUpFolder, FnSig, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable, + AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, Unnormalized, fold_regions, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; @@ -93,18 +93,6 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi } } -pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) { - if fn_sig.abi() == ExternAbi::Custom { - // Function definitions that use `extern "custom"` must be naked functions. - if !find_attr!(tcx, def_id, Naked(_)) { - tcx.dcx().emit_err(crate::diagnostics::AbiCustomClothedFunction { - span: fn_sig_span, - naked_span: tcx.def_span(def_id).shrink_to_lo(), - }); - } - } -} - fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index e9bc2a2d281d4..eac3762ef9af8 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -74,7 +74,7 @@ pub mod wfcheck; use std::borrow::Cow; use std::num::NonZero; -pub use check::{check_abi, check_custom_abi}; +pub use check::check_abi; use rustc_abi::VariantIdx; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{ErrorGuaranteed, pluralize, struct_span_code_err}; diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index 9b629e17942c4..890d25f14b264 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -1947,22 +1947,6 @@ pub(crate) struct DynTraitAssocItemBindingMentionsSelf { pub binding: Span, } -#[derive(Diagnostic)] -#[diag( - "items with the \"custom\" ABI can only be declared externally or defined via naked functions" -)] -pub(crate) struct AbiCustomClothedFunction { - #[primary_span] - pub span: Span, - #[suggestion( - "convert this to an `#[unsafe(naked)]` function", - applicability = "maybe-incorrect", - code = "#[unsafe(naked)]\n", - style = "short" - )] - pub naked_span: Span, -} - #[derive(Diagnostic)] #[diag("`AsyncDrop` impl without `Drop` impl")] #[help( diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d20d8375fc228..7a2670f3b1b78 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -47,7 +47,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, HirIdMap, Node}; -use rustc_hir_analysis::check::{check_abi, check_custom_abi}; +use rustc_hir_analysis::check::check_abi; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, TraitEngine, WellFormedLoc}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -138,7 +138,7 @@ fn typeck_with_inspect<'tcx>( // for visit the asm expr of the body. let ty = fcx.check_expr(body.value); fcx.write_ty(id, ty); - } else if let Some(hir::FnSig { header, decl, span: fn_sig_span }) = node.fn_sig() { + } else if let Some(hir::FnSig { header, decl, span: _ }) = node.fn_sig() { let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() { // In the case that we're recovering `fn() -> W<_>` or some other return // type that has an infer in it, lower the type directly so that it'll @@ -150,7 +150,6 @@ fn typeck_with_inspect<'tcx>( }; check_abi(tcx, id, span, fn_sig.abi()); - check_custom_abi(tcx, def_id, fn_sig.skip_binder(), *fn_sig_span); loops::check(tcx, def_id, body); diff --git a/tests/ui/abi/bad-custom.rs b/tests/ui/abi/bad-custom.rs index 82a27ac4af375..6811520df44cb 100644 --- a/tests/ui/abi/bad-custom.rs +++ b/tests/ui/abi/bad-custom.rs @@ -8,7 +8,7 @@ unsafe extern "custom" fn return_explicit_unit() -> () { std::arch::naked_asm!("") } -// Rejecting an alias is the status quo, this may change in the future. +// The unit must be syntactic, an alias is rejected. type UnitAlias = (); #[unsafe(naked)] unsafe extern "custom" fn return_alias_unit() -> UnitAlias { @@ -55,7 +55,7 @@ type NoNeverReturnType = unsafe extern "custom" fn() -> !; //~^ ERROR invalid signature for `extern "custom"` function unsafe extern "custom" fn not_both(a: i64) -> i64 { - //~^ ERROR items with the "custom" ABI can only be declared externally or defined via naked functions + //~^ ERROR an `extern "custom"` function can only be declared externally or defined via naked functions //~| ERROR invalid signature for `extern "custom"` function unimplemented!() } @@ -67,7 +67,7 @@ struct Thing(i64); impl Thing { extern "custom" fn is_even(self) -> bool { - //~^ ERROR items with the "custom" ABI can only be declared externally or defined via naked functions + //~^ ERROR an `extern "custom"` function can only be declared externally or defined via naked functions //~| ERROR invalid signature for `extern "custom"` function //~| ERROR functions with the "custom" ABI must be unsafe unimplemented!() @@ -76,7 +76,7 @@ impl Thing { trait BitwiseNot { extern "custom" fn bitwise_not(a: i64) -> i64 { - //~^ ERROR items with the "custom" ABI can only be declared externally or defined via naked functions + //~^ ERROR an `extern "custom"` function can only be declared externally or defined via naked functions //~| ERROR invalid signature for `extern "custom"` function //~| ERROR functions with the "custom" ABI must be unsafe unimplemented!() @@ -93,7 +93,7 @@ trait Negate { impl Negate for Thing { extern "custom" fn negate(a: i64) -> i64 { - //~^ ERROR items with the "custom" ABI can only be declared externally or defined via naked functions + //~^ ERROR an `extern "custom"` function can only be declared externally or defined via naked functions //~| ERROR functions with the "custom" ABI must be unsafe //~| ERROR invalid signature for `extern "custom"` function -a @@ -138,7 +138,7 @@ const unsafe extern "custom" fn no_const_fn() { } async unsafe extern "custom" fn no_async_fn() { - //~^ ERROR items with the "custom" ABI can only be declared externally or defined via naked functions + //~^ ERROR an `extern "custom"` function can only be declared externally or defined via naked functions //~| ERROR functions with the "custom" ABI cannot be `async` } @@ -147,6 +147,13 @@ fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() { f } +#[cold] +#[unsafe(naked)] +unsafe extern "custom" fn no_cold_attribute() { + //~^ ERROR an `extern "custom"` function cannot be marked `#[cold]` + std::arch::naked_asm!("") +} + pub fn main() { unsafe { assert_eq!(not_both(21), 42); diff --git a/tests/ui/abi/bad-custom.stderr b/tests/ui/abi/bad-custom.stderr index 773026ba8b76f..4801b294d818f 100644 --- a/tests/ui/abi/bad-custom.stderr +++ b/tests/ui/abi/bad-custom.stderr @@ -150,6 +150,18 @@ LL - unsafe extern "custom" fn not_both(a: i64) -> i64 { LL + unsafe extern "custom" fn not_both() { | +error: an `extern "custom"` function can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:57:1 + | +LL | unsafe extern "custom" fn not_both(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | unsafe extern "custom" fn not_both(a: i64) -> i64 { + | + error: invalid signature for `extern "custom"` function --> $DIR/bad-custom.rs:63:42 | @@ -187,6 +199,18 @@ LL - extern "custom" fn is_even(self) -> bool { LL + extern "custom" fn is_even() { | +error: an `extern "custom"` function can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:69:5 + | +LL | extern "custom" fn is_even(self) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | extern "custom" fn is_even(self) -> bool { + | + error: functions with the "custom" ABI must be unsafe --> $DIR/bad-custom.rs:78:5 | @@ -211,6 +235,18 @@ LL - extern "custom" fn bitwise_not(a: i64) -> i64 { LL + extern "custom" fn bitwise_not() { | +error: an `extern "custom"` function can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:78:5 + | +LL | extern "custom" fn bitwise_not(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | extern "custom" fn bitwise_not(a: i64) -> i64 { + | + error: functions with the "custom" ABI must be unsafe --> $DIR/bad-custom.rs:89:5 | @@ -259,6 +295,18 @@ LL - extern "custom" fn negate(a: i64) -> i64 { LL + extern "custom" fn negate() { | +error: an `extern "custom"` function can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:95:5 + | +LL | extern "custom" fn negate(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | extern "custom" fn negate(a: i64) -> i64 { + | + error: invalid signature for `extern "custom"` function --> $DIR/bad-custom.rs:104:18 | @@ -347,7 +395,7 @@ LL - async unsafe extern "custom" fn no_async_fn() { LL + unsafe extern "custom" fn no_async_fn() { | -error: items with the "custom" ABI can only be declared externally or defined via naked functions +error: an `extern "custom"` function can only be declared externally or defined via naked functions --> $DIR/bad-custom.rs:140:1 | LL | async unsafe extern "custom" fn no_async_fn() { @@ -359,6 +407,17 @@ LL + #[unsafe(naked)] LL | async unsafe extern "custom" fn no_async_fn() { | +error: an `extern "custom"` function cannot be marked `#[cold]` + --> $DIR/bad-custom.rs:152:1 + | +LL | #[cold] + | ------- help: remove the `#[cold]` attribute +LL | #[unsafe(naked)] +LL | unsafe extern "custom" fn no_cold_attribute() { + | ^^^^^^^---------------^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `extern "custom"` because of this + error[E0277]: expected an `Fn()` closure, found `unsafe extern "custom" fn()` --> $DIR/bad-custom.rs:145:64 | @@ -372,54 +431,6 @@ LL | f = note: wrap the `unsafe extern "custom" fn()` in a closure with no arguments: `|| { /* code */ }` = note: unsafe function cannot be called generically without an unsafe block -error: items with the "custom" ABI can only be declared externally or defined via naked functions - --> $DIR/bad-custom.rs:57:1 - | -LL | unsafe extern "custom" fn not_both(a: i64) -> i64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: convert this to an `#[unsafe(naked)]` function - | -LL + #[unsafe(naked)] -LL | unsafe extern "custom" fn not_both(a: i64) -> i64 { - | - -error: items with the "custom" ABI can only be declared externally or defined via naked functions - --> $DIR/bad-custom.rs:69:5 - | -LL | extern "custom" fn is_even(self) -> bool { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: convert this to an `#[unsafe(naked)]` function - | -LL + #[unsafe(naked)] -LL | extern "custom" fn is_even(self) -> bool { - | - -error: items with the "custom" ABI can only be declared externally or defined via naked functions - --> $DIR/bad-custom.rs:78:5 - | -LL | extern "custom" fn bitwise_not(a: i64) -> i64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: convert this to an `#[unsafe(naked)]` function - | -LL + #[unsafe(naked)] -LL | extern "custom" fn bitwise_not(a: i64) -> i64 { - | - -error: items with the "custom" ABI can only be declared externally or defined via naked functions - --> $DIR/bad-custom.rs:95:5 - | -LL | extern "custom" fn negate(a: i64) -> i64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: convert this to an `#[unsafe(naked)]` function - | -LL + #[unsafe(naked)] -LL | extern "custom" fn negate(a: i64) -> i64 { - | - error: functions with the "custom" ABI cannot be called --> $DIR/bad-custom.rs:116:14 | @@ -457,49 +468,49 @@ LL | unsafe { f(x) } | ^^^^ error: functions with the "custom" ABI cannot be called - --> $DIR/bad-custom.rs:152:20 + --> $DIR/bad-custom.rs:159:20 | LL | assert_eq!(not_both(21), 42); | ^^^^^^^^^^^^ | note: an `extern "custom"` function can only be called using inline assembly - --> $DIR/bad-custom.rs:152:20 + --> $DIR/bad-custom.rs:159:20 | LL | assert_eq!(not_both(21), 42); | ^^^^^^^^^^^^ error: functions with the "custom" ABI cannot be called - --> $DIR/bad-custom.rs:155:29 + --> $DIR/bad-custom.rs:162:29 | LL | assert_eq!(unsafe { increment(41) }, 42); | ^^^^^^^^^^^^^ | note: an `extern "custom"` function can only be called using inline assembly - --> $DIR/bad-custom.rs:155:29 + --> $DIR/bad-custom.rs:162:29 | LL | assert_eq!(unsafe { increment(41) }, 42); | ^^^^^^^^^^^^^ error: functions with the "custom" ABI cannot be called - --> $DIR/bad-custom.rs:158:17 + --> $DIR/bad-custom.rs:165:17 | LL | assert!(Thing(41).is_even()); | ^^^^^^^^^^^^^^^^^^^ | note: an `extern "custom"` function can only be called using inline assembly - --> $DIR/bad-custom.rs:158:17 + --> $DIR/bad-custom.rs:165:17 | LL | assert!(Thing(41).is_even()); | ^^^^^^^^^^^^^^^^^^^ error: functions with the "custom" ABI cannot be called - --> $DIR/bad-custom.rs:161:20 + --> $DIR/bad-custom.rs:168:20 | LL | assert_eq!(Thing::bitwise_not(42), !42); | ^^^^^^^^^^^^^^^^^^^^^^ | note: an `extern "custom"` function can only be called using inline assembly - --> $DIR/bad-custom.rs:161:20 + --> $DIR/bad-custom.rs:168:20 | LL | assert_eq!(Thing::bitwise_not(42), !42); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -510,7 +521,7 @@ error[E0015]: inline assembly is not allowed in constant functions LL | std::arch::naked_asm!("") | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 42 previous errors +error: aborting due to 43 previous errors Some errors have detailed explanations: E0015, E0277. For more information about an error, try `rustc --explain E0015`. From 03b98be071b3b3a2c1323cd29b1c1d342ea7f593 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 13 Aug 2026 12:44:27 +0200 Subject: [PATCH 80/98] Prepare for merging from rust-lang/rust This updates the rust-version file to 1e5ee356374211706221b71b6106d297a646ee57. --- library/stdarch/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/stdarch/rust-version b/library/stdarch/rust-version index 7b240b9797241..61a4b2d8c095f 100644 --- a/library/stdarch/rust-version +++ b/library/stdarch/rust-version @@ -1 +1 @@ -fcbe7917ba18120d9eda136f1c7c5a60c78e554e +1e5ee356374211706221b71b6106d297a646ee57 From 28ff895a8ae84949f03c9f5cc758b03c6b9d9a54 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 12:11:33 +0200 Subject: [PATCH 81/98] improve profile-guided-optimization.md --- .../src/profile-guided-optimization.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/profile-guided-optimization.md b/src/doc/rustc-dev-guide/src/profile-guided-optimization.md index 191d612b45a60..52c197162993f 100644 --- a/src/doc/rustc-dev-guide/src/profile-guided-optimization.md +++ b/src/doc/rustc-dev-guide/src/profile-guided-optimization.md @@ -111,24 +111,24 @@ to generate profiling data, and collecting and persisting this profiling data needs some infrastructure in place. In the case of LLVM, these runtime components are implemented in -[compiler-rt][compiler-rt-profile] and statically linked into any instrumented binaries. +[compiler-rt] and statically linked into any instrumented binaries. The `rustc` version of this can be found in `library/profiler_builtins` which basically packs the C code from `compiler-rt` into a Rust crate. In order for `profiler_builtins` to be built, `profiler = true` must be set in `rustc`'s `bootstrap.toml`. -[compiler-rt-profile]: https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/profile +[compiler-rt]: https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/profile ## Testing PGO Since the PGO workflow spans multiple compiler invocations most testing happens -in [run-make tests][rmake-tests] (the relevant tests have `pgo` in their name). -There is also a [codegen test][codegen-test] that checks that some expected +in [run-make tests] (the relevant tests have `pgo` in their name). +There is also a [codegen test] that checks that some expected instrumentation artifacts show up in LLVM IR. -[rmake-tests]: https://github.com/rust-lang/rust/tree/HEAD/tests/run-make -[codegen-test]: https://github.com/rust-lang/rust/blob/HEAD/tests/codegen-llvm/pgo-instrumentation.rs +[run-make tests]: https://github.com/rust-lang/rust/tree/HEAD/tests/run-make +[codegen test]: https://github.com/rust-lang/rust/blob/HEAD/tests/codegen-llvm/pgo-instrumentation.rs ## Additional information From eee684e6e05d0978054a8233f7fe24a37aa35d71 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 12:12:42 +0200 Subject: [PATCH 82/98] sembr src/guides/editions.md --- .../rustc-dev-guide/src/guides/editions.md | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/guides/editions.md b/src/doc/rustc-dev-guide/src/guides/editions.md index 535d82f8403b4..435aa12339b99 100644 --- a/src/doc/rustc-dev-guide/src/guides/editions.md +++ b/src/doc/rustc-dev-guide/src/guides/editions.md @@ -23,8 +23,8 @@ supports comparisons for doing range checks, such as `span.edition() >= Edition: ### Adding a new edition Adding a new edition mainly involves adding a variant to the [`Edition`] enum and then fixing -everything that is broken. See [#94461](https://github.com/rust-lang/rust/pull/94461) for an -example. +everything that is broken. +See [#94461](https://github.com/rust-lang/rust/pull/94461) for an example. ### Features and Edition stability @@ -35,7 +35,8 @@ When adding a new feature, there are two options you can choose for how to handl future edition: - Just check the edition of the span like `span.at_least_rust_20xx()` (see [Edition hygiene]) or the - [`Session::edition`]. This will implicitly depend on the stability of the edition itself to + [`Session::edition`]. + This will implicitly depend on the stability of the edition itself to indicate that your feature is available. - Place your new behavior behind a [feature gate]. @@ -71,7 +72,8 @@ There are a few different options for doing feature checks: or just remove the feature check altogether and just check `span.at_least_rust_20xx()`. If you need to do the feature gating in multiple places, consider placing the check in a single -function so that there will only be a single place to update. For example: +function so that there will only be a single place to update. +For example: ```rust,ignore // An example from Edition 2021 disjoint closure captures. @@ -93,7 +95,8 @@ Within [`Lexer`], tokens can be modified based on edition-specific behavior. For example, C-String literals like `c"foo"` are split into multiple tokens in editions before 2021. This is also where things like reserved prefixes are handled for the 2021 edition. -Edition-specific parsing is relatively rare. One example is `async fn` which checks the span of the +Edition-specific parsing is relatively rare. +One example is `async fn` which checks the span of the token to determine if it is the 2015 edition, and emits an error in that case. This can only be done if the syntax was already invalid. @@ -190,7 +193,9 @@ When a user runs `cargo fix --edition`, cargo will pass the `--force-warn rust-2 flag to force all of these lints to appear during the edition migration. Cargo also passes `--cap-lints=allow` so that no other lints interfere with the edition migration. -Make sure that the example code sets the correct edition. The example should illustrate the previous edition, and show what the migration warning would look like. For example, this lint for a 2024 migration shows an example in 2021: +Make sure that the example code sets the correct edition. +The example should illustrate the previous edition, and show what the migration warning would look like. +For example, this lint for a 2024 migration shows an example in 2021: ```rust,ignore declare_lint! { @@ -245,14 +250,16 @@ afterwards. This should generally be used sparingly, as there are other options: - Small impact stylistic changes unrelated to an edition can just make the lint `Warn` on all - editions. If you want people to adopt a different way to write things, then go ahead and commit to + editions. + If you want people to adopt a different way to write things, then go ahead and commit to having it show up for all projects. Beware that if a new warn-by-default lint hits many projects, it can be very disruptive and frustrating for users. - Change the new style to be a hard error in the new edition, and use a [migration lint] to - automatically convert projects to the new style. For example, + automatically convert projects to the new style. + For example, [`ellipsis_inclusive_range_patterns`] is a hard error in 2021, and warns in all previous editions. Beware that these cannot be added after the edition stabilizes. @@ -354,11 +361,22 @@ In general it is recommended to avoid these special cases except for very high v Updating the edition of the standard library itself roughly involves the following process: - Wait until the newly stabilized edition has reached beta and the bootstrap compiler has been updated. -- Apply migration lints. This can be an involved process since some code is in external submodules[^std-submodules], and the standard library makes heavy use of conditional compilation. Also, running `cargo fix --edition` can be impractical on the standard library itself. One approach is to individually add `#![warn(...)]` at the top of each crate for each lint, run `./x check library`, apply the migrations, remove the `#![warn(...)]` and commit each migration separately. You'll likely need to run `./x check` with `--target` for many different targets to get full coverage (otherwise you'll likely spend days or weeks getting CI to pass)[^ed-docker]. See also the [advanced migration guide] for more tips. - - Apply migrations to [`backtrace-rs`]. [Example for 2024](https://github.com/rust-lang/backtrace-rs/pull/700). Note that this doesn't update the edition of the crate itself because that is published independently on crates.io, and that would otherwise restrict the minimum Rust version. Consider adding some `#![deny()]` attributes to avoid regressions until its edition gets updated. - - Apply migrations to [`stdarch`], and update its edition, and formatting. [Example for 2024](https://github.com/rust-lang/stdarch/pull/1710). +- Apply migration lints. + This can be an involved process since some code is in external submodules[^std-submodules], and the standard library makes heavy use of conditional compilation. + Also, running `cargo fix --edition` can be impractical on the standard library itself. + One approach is to individually add `#![warn(...)]` at the top of each crate for each lint, run `./x check library`, apply the migrations, remove the `#![warn(...)]` and commit each migration separately. + You'll likely need to run `./x check` with `--target` for many different targets to get full coverage (otherwise you'll likely spend days or weeks getting CI to pass)[^ed-docker]. + See also the [advanced migration guide] for more tips. + - Apply migrations to [`backtrace-rs`]. + [Example for 2024](https://github.com/rust-lang/backtrace-rs/pull/700). + Note that this doesn't update the edition of the crate itself because that is published independently on crates.io, and that would otherwise restrict the minimum Rust version. + Consider adding some `#![deny()]` attributes to avoid regressions until its edition gets updated. + - Apply migrations to [`stdarch`], and update its edition, and formatting. + [Example for 2024](https://github.com/rust-lang/stdarch/pull/1710). - Post PRs to update the backtrace and stdarch submodules, and wait for those to land. - - Apply migration lints to the standard library crates, and update their edition. I recommend working one crate at a time starting with `core`. [Example for 2024](https://github.com/rust-lang/rust/pull/138162). + - Apply migration lints to the standard library crates, and update their edition. + I recommend working one crate at a time starting with `core`. + [Example for 2024](https://github.com/rust-lang/rust/pull/138162). [^std-submodules]: This will hopefully change in the future to pull these submodules into `rust-lang/rust`. [^ed-docker]: You'll also likely need to do a lot of testing for different targets, and this is where [docker testing](../tests/docker.md) comes in handy. @@ -376,7 +394,8 @@ After the edition team has given the go-ahead, the process for stabilizing an ed - Hunt and find any document that refers to edition by number, and update it: - [`--edition` flag](https://github.com/rust-lang/rust/blob/HEAD/src/doc/rustc/src/command-line-arguments.md#--edition-specify-the-edition-to-use) - [Rustdoc attributes](https://github.com/rust-lang/rust/blob/HEAD/src/doc/rustdoc/src/write-documentation/documentation-tests.md#attributes) -- Clean up any tests that use the `//@ edition` header to remove the `-Zunstable-options` flag to ensure they are indeed stable. Note: Ideally this should be automated, see [#133582]. +- Clean up any tests that use the `//@ edition` header to remove the `-Zunstable-options` flag to ensure they are indeed stable. + Note: Ideally this should be automated, see [#133582]. - Bless any tests that change. - Update `lint-docs` to default to the new edition. From e8fe604d3f364dfc4281e8278f2a114df42021a6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 12:19:09 +0200 Subject: [PATCH 83/98] not a blog post --- src/doc/rustc-dev-guide/src/guides/editions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/guides/editions.md b/src/doc/rustc-dev-guide/src/guides/editions.md index 435aa12339b99..e5f8d38912a09 100644 --- a/src/doc/rustc-dev-guide/src/guides/editions.md +++ b/src/doc/rustc-dev-guide/src/guides/editions.md @@ -375,7 +375,7 @@ Updating the edition of the standard library itself roughly involves the followi [Example for 2024](https://github.com/rust-lang/stdarch/pull/1710). - Post PRs to update the backtrace and stdarch submodules, and wait for those to land. - Apply migration lints to the standard library crates, and update their edition. - I recommend working one crate at a time starting with `core`. + It is recommended to work one crate at a time, starting with `core`. [Example for 2024](https://github.com/rust-lang/rust/pull/138162). [^std-submodules]: This will hopefully change in the future to pull these submodules into `rust-lang/rust`. From 5d82d7ec74655fe768a90569aa27a069d0eb2173 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 12:20:21 +0200 Subject: [PATCH 84/98] sembr src/incrcomp-debugging.md --- .../rustc-dev-guide/src/incrcomp-debugging.md | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md index 8207b81665aa7..35fb6d6846611 100644 --- a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md +++ b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md @@ -2,16 +2,16 @@ ## Testing the dependency graph -There are various ways to write tests against the dependency graph. The -simplest mechanisms are the `#[rustc_if_this_changed]` and -`#[rustc_then_this_would_need]` annotations. These are used in [ui] tests to test +There are various ways to write tests against the dependency graph. + The simplest mechanisms are the `#[rustc_if_this_changed]` and +`#[rustc_then_this_would_need]` annotations. +These are used in [ui] tests to test whether the expected set of paths exist in the dependency graph. [`tests/ui/dep-graph/dep-graph-caller-callee.rs`]: https://github.com/rust-lang/rust/blob/HEAD/tests/ui/dep-graph/dep-graph-caller-callee.rs [ui]: tests/ui.html -As an example, see [`tests/ui/dep-graph/dep-graph-caller-callee.rs`], or the -tests below. +As an example, see [`tests/ui/dep-graph/dep-graph-caller-callee.rs`], or the tests below. ```rust,ignore #[rustc_if_this_changed] @@ -45,15 +45,15 @@ code we test, but is meaningful from the point of view of the test itself. ### Dumping the graph -The compiler is also capable of dumping the dependency graph for your -debugging pleasure. To do so, pass the `-Z dump-dep-graph` flag. The -graph will be dumped to `dep_graph.{txt,dot}` in the current -directory. You can override the filename with the `RUST_DEP_GRAPH` -environment variable. +The compiler is also capable of dumping the dependency graph for your debugging pleasure. +To do so, pass the `-Z dump-dep-graph` flag. +The graph will be dumped to `dep_graph.{txt,dot}` in the current +directory. + You can override the filename with the `RUST_DEP_GRAPH` environment variable. -Frequently, though, the full dep graph is quite overwhelming and not -particularly helpful. Therefore, the compiler also allows you to filter -the graph. You can filter in three ways: +Frequently, though, the full dep graph is quite overwhelming and not particularly helpful. +Therefore, the compiler also allows you to filter the graph. +You can filter in three ways: 1. All edges originating in a particular set of nodes (usually a single node). 2. All edges reaching a particular set of nodes. @@ -69,15 +69,15 @@ source_filter -> target_filter // nodes in between source_filter and target_filt ``` `source_filter` and `target_filter` are a `&`-separated list of strings. -A node is considered to match a filter if all of those strings appear in its -label. So, for example: +A node is considered to match a filter if all of those strings appear in its label. +So, for example: ```text RUST_DEP_GRAPH_FILTER='-> TypeckTables' ``` -would select the predecessors of all `TypeckTables` nodes. Usually though you -want the `TypeckTables` node for some particular fn, so you might write: +would select the predecessors of all `TypeckTables` nodes. +Usually though you want the `TypeckTables` node for some particular fn, so you might write: ```text RUST_DEP_GRAPH_FILTER='-> TypeckTables & bar' @@ -87,36 +87,35 @@ This will select only the predecessors of `TypeckTables` nodes for functions with `bar` in their name. Perhaps you are finding that when you change `foo` you need to re-type-check -`bar`, but you don't think you should have to. In that case, you might do: +`bar`, but you don't think you should have to. +In that case, you might do: ```text RUST_DEP_GRAPH_FILTER='Hir & foo -> TypeckTables & bar' ``` This will dump out all the nodes that lead from `Hir(foo)` to -`TypeckTables(bar)`, from which you can (hopefully) see the source -of the erroneous edge. +`TypeckTables(bar)`, from which you can (hopefully) see the source of the erroneous edge. ### Tracking down incorrect edges Sometimes, after you dump the dependency graph, you will find some -path that should not exist, but you will not be quite sure how it came -to be. **When the compiler is built with debug assertions,** it can -help you track that down. Simply set the `RUST_FORBID_DEP_GRAPH_EDGE` -environment variable to a filter. Every edge created in the dep-graph +path that should not exist, but you will not be quite sure how it came to be. +**When the compiler is built with debug assertions,** it can help you track that down. +Simply set the `RUST_FORBID_DEP_GRAPH_EDGE` environment variable to a filter. +Every edge created in the dep-graph will be tested against that filter – if it matches, a `bug!` is reported, so you can easily see the backtrace (`RUST_BACKTRACE=1`). -The syntax for these filters is the same as described in the previous -section. However, note that this filter is applied to every **edge** -and doesn't handle longer paths in the graph, unlike the previous -section. +The syntax for these filters is the same as described in the previous section. +However, note that this filter is applied to every **edge** +and doesn't handle longer paths in the graph, unlike the previous section. Example: You find that there is a path from the `Hir` of `foo` to the type -check of `bar` and you don't think there should be. You dump the -dep-graph as described in the previous section and open `dep-graph.txt` +check of `bar` and you don't think there should be. +You dump the dep-graph as described in the previous section and open `dep-graph.txt` to see something like: ```text @@ -124,6 +123,7 @@ Hir(foo) -> Collect(bar) Collect(bar) -> TypeckTables(bar) ``` -That first edge looks suspicious to you. So you set -`RUST_FORBID_DEP_GRAPH_EDGE` to `Hir&foo -> Collect&bar`, re-run, and -then observe the backtrace. Voila, bug fixed! +That first edge looks suspicious to you. +So you set `RUST_FORBID_DEP_GRAPH_EDGE` to `Hir&foo -> Collect&bar`, re-run, and +then observe the backtrace. +Voila, bug fixed! From 5f249e400cd710607c1901e9c361be291f7e1a5a Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 12:23:52 +0200 Subject: [PATCH 85/98] whitespace --- src/doc/rustc-dev-guide/src/incrcomp-debugging.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md index 35fb6d6846611..8b5b889bc6af3 100644 --- a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md +++ b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md @@ -49,7 +49,7 @@ The compiler is also capable of dumping the dependency graph for your debugging To do so, pass the `-Z dump-dep-graph` flag. The graph will be dumped to `dep_graph.{txt,dot}` in the current directory. - You can override the filename with the `RUST_DEP_GRAPH` environment variable. +You can override the filename with the `RUST_DEP_GRAPH` environment variable. Frequently, though, the full dep graph is quite overwhelming and not particularly helpful. Therefore, the compiler also allows you to filter the graph. From 84fb23fa0c2f5eb2a6f776c23c82ece238ea1f3a Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 12:24:32 +0200 Subject: [PATCH 86/98] sembr src/memory.md --- src/doc/rustc-dev-guide/src/memory.md | 45 +++++++++++++++------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/memory.md b/src/doc/rustc-dev-guide/src/memory.md index 24e7205a3565b..ca79160064d3b 100644 --- a/src/doc/rustc-dev-guide/src/memory.md +++ b/src/doc/rustc-dev-guide/src/memory.md @@ -27,30 +27,33 @@ The [`CtxtInterners`] type contains a bunch of maps of interned types and the ar ### Example: `ty::TyKind` Taking the example of [`ty::TyKind`] which represents a type in the compiler (you -can read more [here](./ty.md)). Each time we want to construct a type, the -compiler doesn’t naively allocate from the buffer. Instead, we check if that -type was already constructed. If it was, we just get the same pointer we had -before, otherwise we make a fresh pointer. With this schema if we want to know -if two types are the same, all we need to do is compare the pointers which is -efficient. [`ty::TyKind`] should never be constructed on the stack, and it would be unusable -if done so. -You always allocate them from this arena and you always intern them so they are -unique. +can read more [here](./ty.md)). + Each time we want to construct a type, the compiler doesn’t naively allocate from the buffer. + Instead, we check if that type was already constructed. +If it was, we just get the same pointer we had before, otherwise we make a fresh pointer. +With this schema if we want to know +if two types are the same, all we need to do is compare the pointers which is efficient. +[`ty::TyKind`] should never be constructed on the stack, and it would be unusable if done so. +You always allocate them from this arena and you always intern them so they are unique. At the beginning of the compilation we make a buffer and each time we need to allocate a type we use -some of this memory buffer. If we run out of space we get another one. The lifetime of that buffer -is `'tcx`. Our types are tied to that lifetime, so when compilation finishes all the memory related +some of this memory buffer. +If we run out of space we get another one. +The lifetime of that buffer is `'tcx`. +Our types are tied to that lifetime, so when compilation finishes all the memory related to that buffer is freed and our `'tcx` references would be invalid. In addition to types, there are a number of other arena-allocated data structures that you can -allocate, and which are found in this module. Here are a few examples: +allocate, and which are found in this module. +Here are a few examples: - [`GenericArgs`], allocated with [`mk_args`] – this will intern a slice of types, often used to specify the values to be substituted for generics args (e.g. `HashMap` would be represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`). - [`TraitRef`], typically passed by value – a **trait reference** consists of a reference to a trait along with its various type parameters (including `Self`), like `i32: Display` (here, the def-id - would reference the `Display` trait, and the args would contain `i32`). Note that `def-id` is + would reference the `Display` trait, and the args would contain `i32`). + Note that `def-id` is defined and discussed in depth in the [`AdtDef and DefId`][adtdefid] section. - [`Predicate`] defines something the trait system has to prove (see [traits] module). @@ -69,9 +72,9 @@ represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`). ## The `tcx` and how it uses lifetimes -The typing context (`tcx`) is the central data structure in the compiler. It is the context that -you use to perform all manner of queries. The `struct` [`TyCtxt`] defines a reference to this shared -context: +The typing context (`tcx`) is the central data structure in the compiler. +It is the context that you use to perform all manner of queries. +The `struct` [`TyCtxt`] defines a reference to this shared context: ```rust,ignore tcx: TyCtxt<'tcx> @@ -80,7 +83,8 @@ tcx: TyCtxt<'tcx> // arena lifetime ``` -As you can see, the `TyCtxt` type takes a lifetime parameter. When you see a reference with a +As you can see, the `TyCtxt` type takes a lifetime parameter. +When you see a reference with a lifetime like `'tcx`, you know that it refers to arena-allocated data (or data that lives as long as the arenas, anyhow). @@ -91,14 +95,15 @@ the arenas, anyhow). The Rust compiler is a fairly large program containing lots of big data structures (e.g. the [Abstract Syntax Tree (AST)][ast], [High-Level Intermediate Representation (`HIR`)][hir], and the type system) and as such, arenas and -references are heavily relied upon to minimize unnecessary memory use. This +references are heavily relied upon to minimize unnecessary memory use. +This manifests itself in the way people can plug into the compiler (i.e. the [driver](./rustc-driver/intro.md)), preferring a "push"-style API (callbacks) instead of the more Rust-ic "pull" style (think the `Iterator` trait). Thread-local storage and interning are used a lot through the compiler to reduce -duplication while also preventing a lot of the ergonomic issues due to many -pervasive lifetimes. The [`rustc_middle::ty::tls`][tls] module is used to access these +duplication while also preventing a lot of the ergonomic issues due to many pervasive lifetimes. +The [`rustc_middle::ty::tls`][tls] module is used to access these thread-locals, although you should rarely need to touch it. [ast]: ./ast-validation.md From 0b6995a5fe7c5754a936957155880ecb054111cd Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 12:32:35 +0200 Subject: [PATCH 87/98] improve memory.md --- src/doc/rustc-dev-guide/src/memory.md | 31 ++++++++++++--------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/memory.md b/src/doc/rustc-dev-guide/src/memory.md index ca79160064d3b..6056f09ab2593 100644 --- a/src/doc/rustc-dev-guide/src/memory.md +++ b/src/doc/rustc-dev-guide/src/memory.md @@ -28,20 +28,20 @@ The [`CtxtInterners`] type contains a bunch of maps of interned types and the ar Taking the example of [`ty::TyKind`] which represents a type in the compiler (you can read more [here](./ty.md)). - Each time we want to construct a type, the compiler doesn’t naively allocate from the buffer. - Instead, we check if that type was already constructed. +Each time we want to construct a type, the compiler doesn’t naively allocate from the buffer. +Instead, we check if that type was already constructed. If it was, we just get the same pointer we had before, otherwise we make a fresh pointer. -With this schema if we want to know -if two types are the same, all we need to do is compare the pointers which is efficient. +With this schema, if we want to know if two types are the same, +all we need to do is compare the pointers, which is efficient. [`ty::TyKind`] should never be constructed on the stack, and it would be unusable if done so. You always allocate them from this arena and you always intern them so they are unique. At the beginning of the compilation we make a buffer and each time we need to allocate a type we use some of this memory buffer. -If we run out of space we get another one. +If we run out of space, we get another one. The lifetime of that buffer is `'tcx`. -Our types are tied to that lifetime, so when compilation finishes all the memory related -to that buffer is freed and our `'tcx` references would be invalid. +Our types are tied to that lifetime, so when compilation finishes, +all the memory related to that buffer is freed, and our `'tcx` references would be invalid. In addition to types, there are a number of other arena-allocated data structures that you can allocate, and which are found in this module. @@ -53,18 +53,16 @@ represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`). - [`TraitRef`], typically passed by value – a **trait reference** consists of a reference to a trait along with its various type parameters (including `Self`), like `i32: Display` (here, the def-id would reference the `Display` trait, and the args would contain `i32`). - Note that `def-id` is - defined and discussed in depth in the [`AdtDef and DefId`][adtdefid] section. + Note that `def-id` is defined and discussed in depth in the [`AdtDef and DefId`] section. - [`Predicate`] defines something the trait system has to prove (see [traits] module). [`GenericArgs`]: ./ty-module/generic-arguments.md#the-genericargs-type -[adtdefid]: ./ty-module/generic-arguments.md#adtdef-and-defid [`TraitRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.TraitRef.html [`AdtDef` and `DefId`]: ./ty.md#adts-representation [`def-id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html [`GenericArgs`]: ./generic_arguments.html#GenericArgs [`mk_args`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.mk_args -[adtdefid]: ./ty-module/generic-arguments.md#adtdef-and-defid +[`AdtDef and DefId`]: ./ty-module/generic-arguments.md#adtdef-and-defid [`Predicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Predicate.html [`TraitRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.TraitRef.html [`ty::TyKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/type.TyKind.html @@ -84,9 +82,8 @@ tcx: TyCtxt<'tcx> ``` As you can see, the `TyCtxt` type takes a lifetime parameter. -When you see a reference with a -lifetime like `'tcx`, you know that it refers to arena-allocated data (or data that lives as long as -the arenas, anyhow). +When you see a reference with a lifetime like `'tcx`, +you know that it refers to arena-allocated data (or data that lives as long as the arenas, anyhow). [`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html @@ -96,9 +93,9 @@ The Rust compiler is a fairly large program containing lots of big data structures (e.g. the [Abstract Syntax Tree (AST)][ast], [High-Level Intermediate Representation (`HIR`)][hir], and the type system) and as such, arenas and references are heavily relied upon to minimize unnecessary memory use. -This -manifests itself in the way people can plug into the compiler (i.e. the -[driver](./rustc-driver/intro.md)), preferring a "push"-style API (callbacks) instead +This manifests itself in the way people can plug into the compiler +(i.e. the [driver](./rustc-driver/intro.md)), +preferring a "push"-style API (callbacks) instead of the more Rust-ic "pull" style (think the `Iterator` trait). Thread-local storage and interning are used a lot through the compiler to reduce From ac129e99b031a04bf4e1cb4153ddfbf17de413b1 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 12:34:20 +0200 Subject: [PATCH 88/98] sembr src/return-position-impl-trait-in-trait.md --- .../return-position-impl-trait-in-trait.md | 141 +++++++++--------- 1 file changed, 67 insertions(+), 74 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md b/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md index d87b97a8612cb..605a70cac90c0 100644 --- a/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md +++ b/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md @@ -7,8 +7,8 @@ GAT either on the trait side or impl side. RPITIT was originally implemented in [#101224], which added support for async fn in trait (AFIT), since the implementation for RPITIT came for -free as a part of implementing AFIT which had been RFC'd previously. It -was then RFC'd independently in [RFC 3425], which was recently approved +free as a part of implementing AFIT which had been RFC'd previously. +It was then RFC'd independently in [RFC 3425], which was recently approved by T-lang. ## How does it work? @@ -21,12 +21,13 @@ This doc is ordered mostly via the compilation pipeline: ### AST lowering -AST lowering for RPITITs is almost the same as lowering RPITs. We -still lower them as +AST lowering for RPITITs is almost the same as lowering RPITs. +We still lower them as [`hir::ItemKind::OpaqueTy`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.OpaqueTy.html). The two differences are that: -We record `in_trait` for the opaque. This will signify that the opaque +We record `in_trait` for the opaque. +This will signify that the opaque is an RPITIT for HIR ty lowering, diagnostics that deal with HIR, etc. We record `lifetime_mapping`s for the opaque type, described below. @@ -34,11 +35,12 @@ We record `lifetime_mapping`s for the opaque type, described below. #### Aside: Opaque lifetime duplication *All opaques* (not just RPITITs) end up duplicating their captured -lifetimes into new lifetime parameters local to the opaque. The main -reason we do this is because RPITs need to be able to "reify"[^1] any -captured late-bound arguments, or make them into early-bound ones. This -is so they can be used as generic args for the opaque, and later to -instantiate hidden types. Since we don't know which lifetimes are early- +lifetimes into new lifetime parameters local to the opaque. +The main reason we do this is because RPITs need to be able to "reify"[^1] any +captured late-bound arguments, or make them into early-bound ones. +This is so they can be used as generic args for the opaque, and later to +instantiate hidden types. +Since we don't know which lifetimes are early- or late-bound during AST lowering, we just do this for all lifetimes. [^1]: This is compiler-errors terminology, I'm not claiming it's accurate :^) @@ -49,15 +51,13 @@ duplicated lifetimes in an additional field, [`OpaqueTy::lifetime_mapping`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.OpaqueTy.html#structfield.lifetime_mapping). We use this lifetime mapping later on in `clauses_of` to install bounds that enforce equality between these duplicated lifetimes and -their source lifetimes in order to properly typecheck these GATs, which -will be discussed below. +their source lifetimes in order to properly typecheck these GATs, which will be discussed below. ##### Note It may be better if we were able to lower without duplicates and for -that I think we would need to stop distinguishing between early and late -bound lifetimes. So we would need a solution like [Account for -late-bound lifetimes in generics +that I think we would need to stop distinguishing between early and late bound lifetimes. +So we would need a solution like [Account for late-bound lifetimes in generics #103448](https://github.com/rust-lang/rust/pull/103448) and then also a PR similar to [Inherit function lifetimes for impl-trait #103449](https://github.com/rust-lang/rust/pull/103449). @@ -66,12 +66,12 @@ PR similar to [Inherit function lifetimes for impl-trait The main change to HIR ty lowering is that we lower `hir::TyKind::OpaqueDef` for an RPITIT to a projection instead of an opaque, using a newly -synthesized def-id for a new associated type in the trait. We'll -describe how exactly we get this def-id in the next section. +synthesized def-id for a new associated type in the trait. +We'll describe how exactly we get this def-id in the next section. This means that any time we call `lower_ty` on the RPITIT, we end up -getting a projection back instead of an opaque. This projection can then -be normalized to the right value -- either the original opaque if we're +getting a projection back instead of an opaque. +This projection can then be normalized to the right value -- either the original opaque if we're in the trait, or the inferred type of the RPITIT if we're in an impl. #### Lowering to synthetic associated types @@ -84,18 +84,15 @@ trait side and impl side for RPITITs that show up in methods. When `tcx.associated_item_def_ids(trait_def_id)` is called on a trait to gather all of the trait's associated types, the query previously just returned the def-ids of the HIR items that are children of the trait. -After [#112988], additionally, for each method in the trait, we add the -def-ids returned by +After [#112988], additionally, for each method in the trait, we add the def-ids returned by `tcx.associated_types_for_impl_traits_in_associated_fn(trait_method_def_id)`, which walks through each trait method, gathers any RPITITs that show up -in the signature, and then calls -`associated_type_for_impl_trait_in_trait` for each RPITIT, which +in the signature, and then calls `associated_type_for_impl_trait_in_trait` for each RPITIT, which synthesizes a new associated type. ##### Lowering RPITITs in impls -Similarly, along with the impl's HIR items, for each impl method, we -additionally add all of the +Similarly, along with the impl's HIR items, for each impl method, we additionally add all of the `associated_types_for_impl_traits_in_associated_fn` for the impl method. This calls `associated_type_for_impl_trait_in_impl`, which will synthesize an associated type definition for each RPITIT that comes from @@ -107,11 +104,10 @@ We use query feeding ([`TyCtxtAt::create_def`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/plumbing/struct.TyCtxtAt.html#method.create_def)) to synthesize a new def-id for the synthetic GATs for each RPITIT. -Locally, most of rustc's queries match on the HIR of an item to compute -their values. Since the RPITIT doesn't really have HIR associated with +Locally, most of rustc's queries match on the HIR of an item to compute their values. +Since the RPITIT doesn't really have HIR associated with it, or at least not HIR that corresponds to an associated type, we must -compute many queries eagerly and -[feed](https://github.com/rust-lang/rust/pull/104940) them, like +compute many queries eagerly and [feed](https://github.com/rust-lang/rust/pull/104940) them, like `opt_def_kind`, `associated_item`, `visibility`, and`defaultness`. The values for most of these queries is obvious, since the RPITIT @@ -124,19 +120,18 @@ document the interesting ones of those below: ##### `generics_of` for the trait -The GAT for an RPITIT conceptually inherits the same generics as the -RPIT it comes from. However, instead of having the method as the -generics' parent, the trait is the parent. +The GAT for an RPITIT conceptually inherits the same generics as the RPIT it comes from. +However, instead of having the method as the generics' parent, the trait is the parent. Currently we get away with taking the RPIT's generics and method generics and flattening them both into a new generics list, preserving -the def-id of each of the parameters. (This may cause issues with -def-ids having the wrong parents, but in the worst case this will cause -diagnostics issues. If this ends up being an issue, we can synthesize +the def-id of each of the parameters. +(This may cause issues with def-ids having the wrong parents, but in the worst case this will cause +diagnostics issues. +If this ends up being an issue, we can synthesize new def-ids for generic params whose parent is the GAT.) -
- An illustrated example +
An illustrated example ```rust trait Foo { @@ -158,9 +153,10 @@ trait Foo { ##### `generics_of` for the impl -The generics for an impl's GAT are a bit more interesting. They are -composed of RPITIT's own generics (from the trait definition), appended -onto the impl's methods generics. This has the same issue as above, +The generics for an impl's GAT are a bit more interesting. +They are composed of RPITIT's own generics (from the trait definition), appended +onto the impl's methods generics. +This has the same issue as above, where the generics for the GAT have parameters whose def-ids have the wrong parent, but this should only cause issues in diagnostics. @@ -172,9 +168,8 @@ perhaps by a interested new contributor. Some queries rely on computing information that would result in cycles if we were to feed them eagerly, like `explicit_clauses_of`. -Therefore we defer to the `clauses_of` provider to return the right -value for our RPITIT's GAT. We do this by detecting early on in the -query if the associated type is synthetic by using +Therefore we defer to the `clauses_of` provider to return the right value for our RPITIT's GAT. +We do this by detecting early on in the query if the associated type is synthetic by using [`opt_rpitit_info`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.opt_rpitit_info), which returns `Some` if the associated type is synthetic. @@ -200,8 +195,8 @@ both on the trait and impl side. Additionally, we install "bidirectional outlives" predicates. Specifically, we add region-outlives clauses in both directions for each captured early-bound lifetime that constrains it to be equal to the -duplicated early-bound lifetime that results from lowering. This is best -illustrated in an example: +duplicated early-bound lifetime that results from lowering. +This is best illustrated in an example: ```rust trait Foo<'a> { @@ -226,8 +221,8 @@ trait Foo<'a> { ##### `assumed_wf_types` The GATs in both the trait and impl inherit the `assumed_wf_types` of -the trait method that defines the RPITIT. This is to make sure that the -following code is well formed when lowered. +the trait method that defines the RPITIT. +This is to make sure that the following code is well formed when lowered. ```rust trait Foo { @@ -247,8 +242,7 @@ trait FooDesugared { Because `assumed_wf_types` is only defined for local def ids, in order to properly implement `assumed_wf_types` for impls of foreign traits -with RPITs, we need to encode the assumed wf types of RPITITs in an -extern query +with RPITs, we need to encode the assumed wf types of RPITITs in an extern query [`assumed_wf_types_for_rpitit`](https://github.com/rust-lang/rust/blob/a17c7968b727d8413801961fc4e89869b6ab00d3/compiler/rustc_ty_utils/src/implied_bounds.rs#L14). ### Typechecking @@ -259,8 +253,8 @@ The RPITIT inference algorithm is implemented in [`collect_return_position_impl_trait_in_trait_tys`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.collect_return_position_impl_trait_in_trait_tys.html). **High-level:** Given a impl method and a trait method, we take the -trait method and instantiate each RPITIT in the signature with an infer -var. We then equate this trait method signature with the impl method +trait method and instantiate each RPITIT in the signature with an infer var. +We then equate this trait method signature with the impl method signature, and process all obligations that fall out in order to infer the type of all of the RPITITs in the method. @@ -268,8 +262,7 @@ The method is also responsible for making sure that the hidden types for each RPITIT actually satisfy the bounds of the `impl Trait`, i.e. that if we infer `impl Trait = Foo`, that `Foo: Trait` holds. -
- An example... +
An example... ```rust #![feature(return_position_impl_trait_in_trait)] @@ -287,16 +280,16 @@ impl Foo for () { ``` We end up with the trait signature that looks like `fn() -> ?0`, and -nested obligations `?0: Deref`, `?1: Sized`. The impl -signature is `fn() -> Box`. +nested obligations `?0: Deref`, `?1: Sized`. +The impl signature is `fn() -> Box`. Equating these signatures gives us `?0 = Box`, which then after processing the obligation `Box: Deref` gives us `?1 = String`, and the other obligation `String: Sized` evaluates to true. By the end of the algorithm, we end up with a mapping between associated -type def-ids to concrete types inferred from the signature. We can then -use this mapping to implement `type_of` for the synthetic associated +type def-ids to concrete types inferred from the signature. +We can then use this mapping to implement `type_of` for the synthetic associated types in the impl, since this mapping describes the type that should come after the `=` in `type Assoc = ...` for each RPITIT.
@@ -305,17 +298,17 @@ come after the `=` in `type Assoc = ...` for each RPITIT. Since `collect_return_position_impl_trait_in_trait_tys` does fulfillment and region resolution, we must provide it `assumed_wf_types` so that we can prove -region obligations with the same expected implied bounds as -`compare_method_clause_entailment` does. +region obligations with the same expected implied bounds as `compare_method_clause_entailment` does. Since the return type of a method is understood to be one of the assumed WF types, and we eagerly fold the return type with inference variables to do opaque type inference, after opaque type inference, the return type will -resolve to contain the hidden types of the RPITITs. this would mean that the +resolve to contain the hidden types of the RPITITs. +this would mean that the hidden types of the RPITITs would be assumed to be well-formed without having -independently proven that they are. This resulted in a -[subtle unsoundness bug](https://github.com/rust-lang/rust/pull/116072). In -order to prevent this cyclic reasoning, we instead replace the hidden types of +independently proven that they are. +This resulted in a [subtle unsoundness bug](https://github.com/rust-lang/rust/pull/116072). +In order to prevent this cyclic reasoning, we instead replace the hidden types of the RPITITs in the return type of the method with *placeholders*, which lead to no implied well-formedness bounds. @@ -331,12 +324,13 @@ trait Foo { } ``` -requires one interesting hack. We need to install a projection predicate +requires one interesting hack. +We need to install a projection predicate into the param-env of `Foo::bar` allowing us to assume that the RPITIT's -GAT normalizes to the RPITIT's opaque type. This relies on the -observation that a trait method and RPITIT's GAT will always be "in -sync". That is, one will only ever be overridden if the other one is as -well. +GAT normalizes to the RPITIT's opaque type. +This relies on the observation that a trait method and RPITIT's GAT will always be "in +sync". +That is, one will only ever be overridden if the other one is as well. Compare this to a similar desugaring of the code above, which would fail because we cannot rely on this same assumption: @@ -355,8 +349,7 @@ trait Foo { ``` Failing because a down-stream impl could theoretically provide an -implementation for `RPITIT` without providing an implementation of -`bar`: +implementation for `RPITIT` without providing an implementation of `bar`: ```text error[E0308]: mismatched types @@ -390,8 +383,8 @@ WF-checking the GAT as if it were a regular GAT. The "default trait methods" described above does not interact well with specialization, because we only install those projection bounds in trait -default methods, and not in impl methods. Given that specialization is -already pretty busted, I won't go into detail, but it's currently a bug +default methods, and not in impl methods. +Given that specialization is already pretty busted, I won't go into detail, but it's currently a bug tracked in: * `tests/ui/impl-trait/in-trait/specialization-broken.rs` @@ -414,8 +407,8 @@ fn test<'a, 'b, T: Foo>() -> bool { ``` This is because we can't relate `::Rpitit<'a>` and `::Rpitit<'b>`, even if they don't capture their lifetime. If we were -using regular opaque types, this would work, because they would be +Foo>::Rpitit<'b>`, even if they don't capture their lifetime. +If we were using regular opaque types, this would work, because they would be bivariant in that lifetime parameter: ```rust #![feature(return_position_impl_trait_in_trait)] From b4f722c6c7853d84c61a347e40116bce89c1aa3a Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 12:49:30 +0200 Subject: [PATCH 89/98] was 3 years ago --- .../rustc-dev-guide/src/return-position-impl-trait-in-trait.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md b/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md index 605a70cac90c0..a256dbcd49eeb 100644 --- a/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md +++ b/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md @@ -8,7 +8,7 @@ GAT either on the trait side or impl side. RPITIT was originally implemented in [#101224], which added support for async fn in trait (AFIT), since the implementation for RPITIT came for free as a part of implementing AFIT which had been RFC'd previously. -It was then RFC'd independently in [RFC 3425], which was recently approved +It was then RFC'd independently in [RFC 3425], which was then approved by T-lang. ## How does it work? From 8f7fc506b5e2a1b9030e4e00045175a45614a86e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 13:11:14 +0200 Subject: [PATCH 90/98] reflow --- .../return-position-impl-trait-in-trait.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md b/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md index a256dbcd49eeb..39453d1358647 100644 --- a/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md +++ b/src/doc/rustc-dev-guide/src/return-position-impl-trait-in-trait.md @@ -27,8 +27,8 @@ We still lower them as The two differences are that: We record `in_trait` for the opaque. -This will signify that the opaque -is an RPITIT for HIR ty lowering, diagnostics that deal with HIR, etc. +This will signify that the opaque is an RPITIT for HIR ty lowering, +diagnostics that deal with HIR, etc. We record `lifetime_mapping`s for the opaque type, described below. @@ -40,8 +40,8 @@ The main reason we do this is because RPITs need to be able to "reify"[^1] any captured late-bound arguments, or make them into early-bound ones. This is so they can be used as generic args for the opaque, and later to instantiate hidden types. -Since we don't know which lifetimes are early- -or late-bound during AST lowering, we just do this for all lifetimes. +Since we don't know which lifetimes are early- or late-bound during AST lowering, +we just do this for all lifetimes. [^1]: This is compiler-errors terminology, I'm not claiming it's accurate :^) @@ -304,9 +304,8 @@ Since the return type of a method is understood to be one of the assumed WF types, and we eagerly fold the return type with inference variables to do opaque type inference, after opaque type inference, the return type will resolve to contain the hidden types of the RPITITs. -this would mean that the -hidden types of the RPITITs would be assumed to be well-formed without having -independently proven that they are. +This would mean that the hidden types of the RPITITs would be assumed to be well-formed +without having independently proven that they are. This resulted in a [subtle unsoundness bug](https://github.com/rust-lang/rust/pull/116072). In order to prevent this cyclic reasoning, we instead replace the hidden types of the RPITITs in the return type of the method with *placeholders*, which lead @@ -314,7 +313,7 @@ to no implied well-formedness bounds. #### Default trait body -Type-checking a default trait body, like: +Type-checking a default trait body like the following requires one interesting hack. ```rust trait Foo { @@ -324,12 +323,10 @@ trait Foo { } ``` -requires one interesting hack. We need to install a projection predicate into the param-env of `Foo::bar` allowing us to assume that the RPITIT's GAT normalizes to the RPITIT's opaque type. -This relies on the observation that a trait method and RPITIT's GAT will always be "in -sync". +This relies on the observation that a trait method and RPITIT's GAT will always be "in sync". That is, one will only ever be overridden if the other one is as well. Compare this to a similar desugaring of the code above, which would fail From 499d68c4d4034df2f8687d4479bb90b726d79151 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 13:11:52 +0200 Subject: [PATCH 91/98] sembr src/traits/implied-bounds.md --- .../src/traits/implied-bounds.md | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md index 732f6e81465b2..4fa64fdb99199 100644 --- a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md +++ b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md @@ -3,13 +3,15 @@ We currently add implied region bounds to avoid explicit annotations. e.g. `fn foo<'a, T>(x: &'a T)` can freely assume that `T: 'a` holds without specifying it. -There are two kinds of implied bounds: explicit and implicit. Explicit implied bounds +There are two kinds of implied bounds: explicit and implicit. +Explicit implied bounds get added to the `fn clauses_of` of the relevant item while implicit ones are handled... well... implicitly. ## explicit implied bounds -The explicit implied bounds are computed in [`fn inferred_outlives_of`]. Only ADTs and +The explicit implied bounds are computed in [`fn inferred_outlives_of`]. +Only ADTs and lazy type aliases have explicit implied bounds which are computed via a fixpoint algorithm in the [`fn inferred_outlives_crate`] query. @@ -18,12 +20,14 @@ This function computes the outlives bounds for each component of the field using separate implementation. For ADTs, trait objects, and associated types the initially required clauses are -computed in [`fn check_explicit_clauses`]. This simply uses `fn explicit_clauses_of` -without elaborating them. +computed in [`fn check_explicit_clauses`]. +This simply uses `fn explicit_clauses_of` without elaborating them. -Region clauses are added via [`fn insert_outlives_clause`]. This function takes +Region clauses are added via [`fn insert_outlives_clause`]. +This function takes an outlives clause, decomposes it and adds the components as explicit clauses only -if the outlived region is a region parameter. [It does not add `'static` requirements][nostatic]. +if the outlived region is a region parameter. +[It does not add `'static` requirements][nostatic]. [`fn inferred_outlives_of`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/mod.rs#L20 @@ -40,7 +44,8 @@ requirements of impls and functions as explicit predicates. ### using implicit implied bounds as assumptions -These bounds are not added to the `ParamEnv` of the affected item itself. For lexical +These bounds are not added to the `ParamEnv` of the affected item itself. +For lexical region resolution they are added using [`fn OutlivesEnvironment::from_normalized_bounds`]. Similarly, during MIR borrowck we add them using [`fn UniversalRegionRelationsBuilder::add_implied_bounds`]. @@ -50,8 +55,8 @@ Outside of MIR borrowck we add the outlives requirements for the types returned [`fn assumed_wf_types`] query. The assumed outlives constraints for implicit bounds are computed using the -[`fn implied_outlives_bounds`] query. This directly -[extracts the required outlives bounds from `fn wf::obligations`][boundsfromty]. +[`fn implied_outlives_bounds`] query. +This directly [extracts the required outlives bounds from `fn wf::obligations`][boundsfromty]. MIR borrowck adds the outlives constraints for both the normalized and unnormalized types, lexical region resolution [only uses the unnormalized types][notnorm]. @@ -67,11 +72,13 @@ lexical region resolution [only uses the unnormalized types][notnorm]. ### proving implicit implied bounds As the implicit implied bounds are not included in `fn clauses_of` we have to -separately make sure they actually hold. We generally handle this by checking that +separately make sure they actually hold. +We generally handle this by checking that all used types are well formed by emitting `WellFormed` predicates. We cannot emit `WellFormed` predicates when instantiating impls, as this would result -in - currently often inductive - trait solver cycles. We also do not emit constraints +in - currently often inductive - trait solver cycles. +We also do not emit constraints involving higher ranked regions as we're lacking the implied bounds from their binder. This results in multiple unsoundnesses: From 9ac8fe6cf9efd51241bdd58b80ed0b80e37eea64 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 13 Aug 2026 13:15:19 +0200 Subject: [PATCH 92/98] improve traits/implied-bounds.md --- .../src/traits/implied-bounds.md | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md index 4fa64fdb99199..3b4072394e787 100644 --- a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md +++ b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md @@ -4,16 +4,14 @@ We currently add implied region bounds to avoid explicit annotations. e.g. `fn foo<'a, T>(x: &'a T)` can freely assume that `T: 'a` holds without specifying it. There are two kinds of implied bounds: explicit and implicit. -Explicit implied bounds -get added to the `fn clauses_of` of the relevant item while implicit ones are -handled... well... implicitly. +Explicit implied bounds get added to the `fn clauses_of` of the relevant item, +while implicit ones are handled, well... implicitly. ## explicit implied bounds The explicit implied bounds are computed in [`fn inferred_outlives_of`]. -Only ADTs and -lazy type aliases have explicit implied bounds which are computed via a fixpoint algorithm -in the [`fn inferred_outlives_crate`] query. +Only ADTs and lazy type aliases have explicit implied bounds +which are computed via a fixpoint algorithm in the [`fn inferred_outlives_crate`] query. We use [`fn insert_required_clauses_to_be_wf`] on all fields of all ADTs in the crate. This function computes the outlives bounds for each component of the field using a @@ -24,8 +22,8 @@ computed in [`fn check_explicit_clauses`]. This simply uses `fn explicit_clauses_of` without elaborating them. Region clauses are added via [`fn insert_outlives_clause`]. -This function takes -an outlives clause, decomposes it and adds the components as explicit clauses only +This function takes an outlives clause, +decomposes it, and adds the components as explicit clauses only if the outlived region is a region parameter. [It does not add `'static` requirements][nostatic]. @@ -45,8 +43,8 @@ requirements of impls and functions as explicit predicates. ### using implicit implied bounds as assumptions These bounds are not added to the `ParamEnv` of the affected item itself. -For lexical -region resolution they are added using [`fn OutlivesEnvironment::from_normalized_bounds`]. +For lexical region resolution, +they are added using [`fn OutlivesEnvironment::from_normalized_bounds`]. Similarly, during MIR borrowck we add them using [`fn UniversalRegionRelationsBuilder::add_implied_bounds`]. @@ -74,12 +72,12 @@ lexical region resolution [only uses the unnormalized types][notnorm]. As the implicit implied bounds are not included in `fn clauses_of` we have to separately make sure they actually hold. We generally handle this by checking that -all used types are well formed by emitting `WellFormed` predicates. +all used types are well-formed by emitting `WellFormed` predicates. We cannot emit `WellFormed` predicates when instantiating impls, as this would result in - currently often inductive - trait solver cycles. -We also do not emit constraints -involving higher ranked regions as we're lacking the implied bounds from their binder. +We also do not emit constraints involving higher ranked regions +as we're lacking the implied bounds from their binder. This results in multiple unsoundnesses: - by using subtyping: [#25860] From 948b5ab98333d04abde8b69bf55a36f26688b5ca Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 13 Aug 2026 13:27:47 +0200 Subject: [PATCH 93/98] tidy: Update Python version requirements to 3.11 --- src/ci/docker/host-x86_64/tidy/Dockerfile | 15 ++++----------- src/tools/tidy/config/requirements.in | 2 +- src/tools/tidy/config/requirements.txt | 2 +- src/tools/tidy/src/extra_checks/mod.rs | 8 ++++---- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/ci/docker/host-x86_64/tidy/Dockerfile b/src/ci/docker/host-x86_64/tidy/Dockerfile index 5ea9941e863c8..c7a083d149815 100644 --- a/src/ci/docker/host-x86_64/tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/tidy/Dockerfile @@ -1,6 +1,6 @@ # We use the ghcr base image because ghcr doesn't have a rate limit # and the tidy job doesn't cache docker images in CI. -FROM ghcr.io/rust-lang/ubuntu:22.04 +FROM ghcr.io/rust-lang/ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -10,10 +10,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ file \ curl \ ca-certificates \ - python2.7 \ python3 \ - python3-pip \ - python3-pkg-resources \ + python3-venv \ git \ cmake \ sudo \ @@ -33,12 +31,7 @@ ENV PATH="/node/bin:${PATH}" COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -COPY host-x86_64/pr-check-1/reuse-requirements.txt /tmp/ -RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt \ - && pip3 install virtualenv - COPY host-x86_64/pr-check-1/validate-toolstate.sh /scripts/ -# NOTE: intentionally uses python2 for x.py so we can test it still works. -# validate-toolstate only runs in our CI, so it's ok for it to only support python3. -ENV SCRIPT="python2.7 ../x.py test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck" +# python3 resolves to python3.12 on Ubuntu 24.04 +ENV SCRIPT="python3 ../x.py test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck" diff --git a/src/tools/tidy/config/requirements.in b/src/tools/tidy/config/requirements.in index d6a13667dad2a..1367d76baa4ff 100644 --- a/src/tools/tidy/config/requirements.in +++ b/src/tools/tidy/config/requirements.in @@ -4,7 +4,7 @@ # --generate-hashes --strip-extras src/tools/tidy/config/requirements.in` # # Note: this generation step should be run with the oldest supported python -# version (currently 3.10) to ensure backward compatibility +# version (currently 3.11) to ensure backward compatibility ruff==0.4.9 clang-format==18.1.7 diff --git a/src/tools/tidy/config/requirements.txt b/src/tools/tidy/config/requirements.txt index ec487b61f9a20..4d3a10c5c07cd 100644 --- a/src/tools/tidy/config/requirements.txt +++ b/src/tools/tidy/config/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.10 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # pip-compile --generate-hashes --strip-extras src/tools/tidy/config/requirements.in diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 7aed70766dcba..7176f8cabc595 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -29,8 +29,8 @@ mod rustdoc_js; #[cfg(test)] mod tests; -const MIN_PY_REV: (u32, u32) = (3, 10); -const MIN_PY_REV_STR: &str = "≥3.10"; +const MIN_PY_REV: (u32, u32) = (3, 11); +const MIN_PY_REV_STR: &str = "≥3.11"; /// Path to find the python executable within a virtual environment #[cfg(target_os = "windows")] @@ -564,13 +564,13 @@ fn create_venv_at_path(path: &Path) -> Result<(), Error> { /// Preferred python versions in order. Newest to oldest then current /// development versions const TRY_PY: &[&str] = &[ + "python3.14", "python3.13", "python3.12", "python3.11", - "python3.10", "python3", "python", - "python3.14", + "python3.15", ]; let mut sys_py = None; From dfb5bab6fce452b3f519557e7d2084a8abb08f4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 13 Aug 2026 13:44:24 +0200 Subject: [PATCH 94/98] Enable unrolling feature of bors --- rust-bors.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust-bors.toml b/rust-bors.toml index 99842cc3e0188..94a1f7cf60816 100644 --- a/rust-bors.toml +++ b/rust-bors.toml @@ -77,6 +77,7 @@ auto_build_failed = [ "-S-waiting-on-team", ] +# Enable management of EC2 self-hosted runners [ec2_runners] runner_group_id = 8 label_prefix = "ec2" @@ -98,3 +99,6 @@ allowed_instances = [ "c8a.8xlarge", "c8a.12xlarge", ] + +# Enable unrolling of rollup member PRs after rollup merge +[unroll] From 6ef144dcb3794f99c998054be137269f4e2d789b Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 4 Aug 2026 21:43:05 +0200 Subject: [PATCH 95/98] rustdoc: use anonymous constant for primitives/keywords/attribute docs --- .../src/attributes/rustc_internal.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 19 ++--- compiler/rustc_passes/src/diagnostics.rs | 12 +-- library/core/src/attribute_docs.rs | 28 +++---- library/core/src/keyword_docs.rs | 80 +++++++++---------- library/core/src/primitive_docs.rs | 54 ++++++------- src/doc/rustdoc/src/unstable-features.md | 4 +- src/librustdoc/clean/types.rs | 18 +++-- .../rustdoc/search-load-itemtype/foo.rs | 9 +-- tests/rustdoc-gui/src/test_docs/lib.rs | 4 +- .../rustdoc-html/auto/auto-impl-primitive.rs | 2 +- tests/rustdoc-html/doc-attribute.rs | 6 +- tests/rustdoc-html/doc-on-keyword.rs | 2 +- .../intra-doc/auxiliary/my-core.rs | 2 +- .../intra-doc/prim-methods-local.rs | 2 +- tests/rustdoc-html/intra-doc/prim-self.rs | 2 +- tests/rustdoc-html/keyword.rs | 6 +- ...-notable_trait-mut_t_is_not_an_iterator.rs | 2 +- .../doc-notable_trait-mut_t_is_not_ref_t.rs | 2 +- .../primitive/auxiliary/issue-15318.rs | 2 +- .../primitive/auxiliary/primitive-doc.rs | 14 +++- .../primitive/cross-crate-primitive-doc.rs | 11 +-- .../primitive/primitive-generic-impl.rs | 2 +- .../primitive-raw-pointer-dox-15318-3.rs | 2 +- ...ive-raw-pointer-link-no-inlined-15318-2.rs | 2 - .../primitive/primitive-reference.rs | 2 +- .../primitive/primitive-slice-auto-trait.rs | 2 +- .../primitive/primitive-tuple-auto-trait.rs | 2 +- .../primitive/primitive-unit-auto-trait.rs | 2 +- tests/rustdoc-html/primitive/primitive.rs | 8 +- ...h-index-primitive-inherent-method-23511.rs | 13 ++- .../rustdoc-html/sidebar/sidebar-all-page.rs | 2 +- .../check-source-code-urls-to-def.rs | 2 +- tests/rustdoc-html/stability.rs | 4 +- tests/rustdoc-html/tab_title.rs | 4 +- tests/rustdoc-html/titles.rs | 2 +- .../type-alias/primitive-local-link-121106.rs | 2 +- tests/rustdoc-json/doc_attribute.rs | 7 +- .../impls/local_for_local_primitive.rs | 2 +- tests/rustdoc-json/keyword.rs | 15 ++-- tests/rustdoc-json/keyword_private.rs | 19 +++-- .../primitives/local_primitive.rs | 16 ++-- .../primitives/primitive_impls.rs | 2 +- .../primitives/primitive_overloading.rs | 3 +- .../rustdoc-json/primitives/use_primitive.rs | 3 +- tests/rustdoc-ui/coverage/exotic.rs | 4 +- tests/rustdoc-ui/doc-attribute-unsupported.rs | 2 +- tests/rustdoc-ui/invalid-attribute.rs | 4 +- tests/rustdoc-ui/invalid-keyword.rs | 2 +- .../feature-gate-rustdoc_internals.rs | 4 +- tests/ui/rustdoc/doc_keyword.rs | 10 +-- tests/ui/rustdoc/doc_keyword.stderr | 18 ++--- .../ui/rustdoc/feature-gate-doc_primitive.rs | 2 +- 53 files changed, 206 insertions(+), 241 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index fe90b51c221a1..94d7d70d07afc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -1132,7 +1132,7 @@ pub(crate) struct RustcDocPrimitiveParser; impl SingleAttributeParser for RustcDocPrimitiveParser { const PATH: &[Symbol] = &[sym::rustc_doc_primitive]; - const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Mod)]); + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Const)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name"); const STABILITY: AttributeStability = unstable!( rustc_attrs, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 44c34a2abddd1..e035e16cabb91 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -44,7 +44,7 @@ use rustc_session::lint::builtin::{ MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_span::edition::Edition; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::{ObligationCtxt, TraitErrors}; @@ -1024,18 +1024,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { hir::Node::Item(item) => Some(&item.kind), _ => None, }; - match item_kind { - Some(ItemKind::Mod(_, module)) => { - if !module.item_ids.is_empty() { - self.dcx() - .emit_err(diagnostics::DocKeywordAttributeEmptyMod { span, attr_name }); - return; - } - } - _ => { - self.dcx().emit_err(diagnostics::DocKeywordAttributeNotMod { span, attr_name }); - return; - } + if let Some(ItemKind::Const(ident, _gen, _ty, _rhs)) = item_kind + && ident.name == kw::Underscore + { + } else { + self.dcx().emit_err(diagnostics::DocKeywordAttributeNotAnonConst { span, attr_name }); } } diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 59b393fc8e68b..16a2cc4007318 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -73,16 +73,8 @@ pub(crate) struct DocAliasNotAnAlias { } #[derive(Diagnostic)] -#[diag("`#[doc({$attr_name} = \"...\")]` should be used on empty modules")] -pub(crate) struct DocKeywordAttributeEmptyMod { - #[primary_span] - pub span: Span, - pub attr_name: &'static str, -} - -#[derive(Diagnostic)] -#[diag("`#[doc({$attr_name} = \"...\")]` should be used on modules")] -pub(crate) struct DocKeywordAttributeNotMod { +#[diag("`#[doc({$attr_name} = \"...\")]` should be used on anonymous constants")] +pub(crate) struct DocKeywordAttributeNotAnonConst { #[primary_span] pub span: Span, pub attr_name: &'static str, diff --git a/library/core/src/attribute_docs.rs b/library/core/src/attribute_docs.rs index b30c449104ad5..584e1583c9bdb 100644 --- a/library/core/src/attribute_docs.rs +++ b/library/core/src/attribute_docs.rs @@ -82,7 +82,7 @@ /// /// [`unused_must_use`]: ../rustc/lints/listing/warn-by-default.html#unused-must-use /// [the `must_use` attribute]: ../reference/attributes/diagnostics.html#the-must_use-attribute -mod must_use_attribute {} +const _: () = (); #[doc(attribute = "allow")] // @@ -144,7 +144,7 @@ mod must_use_attribute {} /// [`forbid`]: ./attribute.forbid.html /// [`warn`]: ./attribute.warn.html /// [`deny`]: ./attribute.deny.html -mod allow_attribute {} +const _: () = (); #[doc(attribute = "cfg")] // @@ -192,7 +192,7 @@ mod allow_attribute {} /// [`cfg_attr`]: ../reference/conditional-compilation.html#the-cfg_attr-attribute /// [the `cfg` attribute]: ../reference/conditional-compilation.html#the-cfg-attribute /// [`if`]: ./keyword.if.html -mod cfg_attribute {} +const _: () = (); #[doc(attribute = "deny")] // @@ -240,7 +240,7 @@ mod cfg_attribute {} /// [`allow`]: ./attribute.allow.html /// [`warn`]: ./attribute.warn.html /// [`deny`]: ./attribute.deny.html -mod deny_attribute {} +const _: () = (); #[doc(attribute = "forbid")] // @@ -276,7 +276,7 @@ mod deny_attribute {} /// [the `forbid` attribute]: ../reference/attributes/diagnostics.html#lint-check-attributes /// [`allow`]: ./attribute.allow.html /// [`warn`]: ./attribute.warn.html -mod forbid_attribute {} +const _: () = (); #[doc(attribute = "deprecated")] // @@ -302,7 +302,7 @@ mod forbid_attribute {} /// For more information, see the Reference on [the `deprecated` attribute]. /// /// [the `deprecated` attribute]: ../reference/attributes/diagnostics.html#the-deprecated-attribute -mod deprecated_attribute {} +const _: () = (); #[doc(attribute = "warn")] // @@ -348,7 +348,7 @@ mod deprecated_attribute {} /// [`allow`]: ./attribute.allow.html /// [`deny`]: ./attribute.deny.html /// [`forbid`]: ./attribute.forbid.html -mod warn_attribute {} +const _: () = (); #[doc(attribute = "no_std")] // @@ -404,7 +404,7 @@ mod warn_attribute {} /// [`Option`]: option::Option /// [`Result`]: result::Result /// [the `no_std` attribute]: ../reference/names/preludes.html#the-no_std-attribute -mod no_std_attribute {} +const _: () = (); #[doc(attribute = "inline")] // @@ -444,7 +444,7 @@ mod no_std_attribute {} /// For more information, see the Reference on [the `inline` attribute]. /// /// [the `inline` attribute]: ../reference/attributes/codegen.html#the-inline-attribute -mod inline_attribute {} +const _: () = (); #[doc(attribute = "cold")] // @@ -474,7 +474,7 @@ mod inline_attribute {} /// For more information, see the Reference on [the `cold` attribute]. /// /// [the `cold` attribute]: ../reference/attributes/codegen.html#the-cold-attribute -mod cold_attribute {} +const _: () = (); #[doc(attribute = "track_caller")] // @@ -505,7 +505,7 @@ mod cold_attribute {} /// [`Location::caller`]: panic::Location::caller /// [`Option::unwrap`]: Option::unwrap /// [the `track_caller` attribute]: ../reference/attributes/codegen.html#the-track_caller-attribute -mod track_caller_attribute {} +const _: () = (); #[doc(attribute = "proc_macro")] // @@ -554,7 +554,7 @@ mod track_caller_attribute {} /// [`TokenStream`]: ../proc_macro/struct.TokenStream.html /// [function-like procedural macros]: ../reference/procedural-macros.html#the-proc_macro-attribute /// [`proc_macro`]: ../proc_macro/index.html -mod proc_macro_attribute {} +const _: () = (); #[doc(attribute = "link_section")] // @@ -580,7 +580,7 @@ mod proc_macro_attribute {} /// For more information, see the Reference on [the `link_section` attribute]. /// /// [the `link_section` attribute]: ../reference/abi.html#the-link_section-attribute -mod link_section_attribute {} +const _: () = (); #[doc(attribute = "non_exhaustive")] // @@ -632,4 +632,4 @@ mod link_section_attribute {} /// For more information, see the Reference on [the `non_exhaustive` attribute]. /// /// [the `non_exhaustive` attribute]: ../reference/attributes/type_system.html#the-non_exhaustive-attribute -mod non_exhaustive_attribute {} +const _: () = (); diff --git a/library/core/src/keyword_docs.rs b/library/core/src/keyword_docs.rs index 596765be5e2dd..3d914556fc65c 100644 --- a/library/core/src/keyword_docs.rs +++ b/library/core/src/keyword_docs.rs @@ -73,7 +73,7 @@ /// [`use`]: keyword.use.html /// [const-cast]: pointer::cast /// [mut-cast]: primitive.pointer.html#method.cast-1 -mod as_keyword {} +const _: () = (); #[doc(keyword = "break")] // @@ -171,7 +171,7 @@ mod as_keyword {} /// [Reference on "break expression"]: ../reference/expressions/loop-expr.html#break-expressions /// [Reference on "break and loop values"]: /// ../reference/expressions/loop-expr.html#break-and-loop-values -mod break_keyword {} +const _: () = (); #[doc(keyword = "const")] // @@ -248,7 +248,7 @@ mod break_keyword {} /// [Reference]: ../reference/items/constant-items.html /// [const-blocks]: ../reference/expressions/block-expr.html#const-blocks /// [const-eval]: ../reference/const_eval.html -mod const_keyword {} +const _: () = (); #[doc(keyword = "continue")] // @@ -288,7 +288,7 @@ mod const_keyword {} /// See [continue expressions] from the reference for more details. /// /// [continue expressions]: ../reference/expressions/loop-expr.html#continue-expressions -mod continue_keyword {} +const _: () = (); #[doc(keyword = "crate")] // @@ -325,7 +325,7 @@ mod continue_keyword {} /// module `foo`, from anywhere else in the same crate. /// /// [Reference]: ../reference/items/extern-crates.html -mod crate_keyword {} +const _: () = (); #[doc(keyword = "else")] // @@ -378,7 +378,7 @@ mod crate_keyword {} /// [`match`]: keyword.match.html /// [`false`]: keyword.false.html /// [`if`]: keyword.if.html -mod else_keyword {} +const _: () = (); #[doc(keyword = "enum")] // @@ -433,7 +433,7 @@ mod else_keyword {} /// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type /// [Rust Book]: ../book/ch06-01-defining-an-enum.html /// [Reference]: ../reference/items/enumerations.html -mod enum_keyword {} +const _: () = (); #[doc(keyword = "extern")] // @@ -480,7 +480,7 @@ mod enum_keyword {} /// ../book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code /// [Reference]: ../reference/items/external-blocks.html /// [`crate`]: keyword.crate.html -mod extern_keyword {} +const _: () = (); #[doc(keyword = "false")] // @@ -491,7 +491,7 @@ mod extern_keyword {} /// See the documentation for [`true`] for more information. /// /// [`true`]: keyword.true.html -mod false_keyword {} +const _: () = (); #[doc(keyword = "fn")] // @@ -558,7 +558,7 @@ mod false_keyword {} /// [`extern`]: keyword.extern.html /// [Rust book]: ../book/ch03-03-how-functions-work.html /// [Reference]: ../reference/items/functions.html -mod fn_keyword {} +const _: () = (); #[doc(keyword = "for")] // @@ -640,7 +640,7 @@ mod fn_keyword {} /// [Rust book]: /// ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for /// [Reference]: ../reference/expressions/loop-expr.html#iterator-loops -mod for_keyword {} +const _: () = (); #[doc(keyword = "if")] // @@ -714,7 +714,7 @@ mod for_keyword {} /// /// [Rust book]: ../book/ch03-05-control-flow.html#if-expressions /// [Reference]: ../reference/expressions/if-expr.html -mod if_keyword {} +const _: () = (); #[doc(keyword = "impl")] // @@ -804,7 +804,7 @@ mod if_keyword {} /// [book1]: ../book/ch05-03-method-syntax.html /// [Reference]: ../reference/items/implementations.html /// [book2]: ../book/ch10-02-traits.html#returning-types-that-implement-traits -mod impl_keyword {} +const _: () = (); #[doc(keyword = "in")] // @@ -836,7 +836,7 @@ mod impl_keyword {} /// For more information, see the [Reference]. /// /// [Reference]: ../reference/visibility-and-privacy.html#pubin-path-pubcrate-pubsuper-and-pubself -mod in_keyword {} +const _: () = (); #[doc(keyword = "let")] // @@ -899,7 +899,7 @@ mod in_keyword {} /// [`if`]: keyword.if.html /// [book2]: ../book/ch18-01-all-the-places-for-patterns.html#let-statements /// [Reference]: ../reference/statements.html#let-statements -mod let_keyword {} +const _: () = (); #[doc(keyword = "loop")] // @@ -949,7 +949,7 @@ mod let_keyword {} /// [`for`]: keyword.for.html /// [`while`]: keyword.while.html /// [Reference]: ../reference/expressions/loop-expr.html -mod loop_keyword {} +const _: () = (); #[doc(keyword = "match")] // @@ -999,7 +999,7 @@ mod loop_keyword {} /// For more information on `match` and matching in general, see the [Reference]. /// /// [Reference]: ../reference/expressions/match-expr.html -mod match_keyword {} +const _: () = (); #[doc(keyword = "mod")] // @@ -1027,7 +1027,7 @@ mod match_keyword {} /// [`pub`]: keyword.pub.html /// [`struct`]: keyword.struct.html /// [modules]: ../reference/items/modules.html -mod mod_keyword {} +const _: () = (); #[doc(keyword = "move")] // @@ -1085,7 +1085,7 @@ mod mod_keyword {} /// /// [closure]: ../book/ch13-01-closures.html /// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads -mod move_keyword {} +const _: () = (); #[doc(keyword = "mut")] // @@ -1143,7 +1143,7 @@ mod move_keyword {} /// More information on mutable references and pointers can be found in the [Reference]. /// /// [Reference]: ../reference/types/pointer.html#mutable-references-mut -mod mut_keyword {} +const _: () = (); #[doc(keyword = "pub")] // @@ -1158,7 +1158,7 @@ mod mut_keyword {} /// /// [reference]:../reference/visibility-and-privacy.html?highlight=pub#visibility-and-privacy /// [Rust by Example]:../rust-by-example/mod/visibility.html -mod pub_keyword {} +const _: () = (); #[doc(keyword = "ref")] // @@ -1208,7 +1208,7 @@ mod pub_keyword {} /// /// [`match`]: keyword.match.html /// [Reference]: ../reference/patterns.html#identifier-patterns -mod ref_keyword {} +const _: () = (); #[doc(keyword = "return")] // @@ -1272,7 +1272,7 @@ mod ref_keyword {} /// /// [closures]: ../book/ch13-01-closures.html /// [`async`]: ../std/keyword.async.html -mod return_keyword {} +const _: () = (); #[doc(keyword = "become")] // @@ -1376,7 +1376,7 @@ mod return_keyword {} /// let program = &[Inst::Inc, Inst::Inc, Inst::Dec, Inst::Inc]; /// assert_eq!(dispatch(program, 0), 2); /// ``` -mod become_keyword {} +const _: () = (); #[doc(keyword = "self")] // @@ -1469,7 +1469,7 @@ mod become_keyword {} /// /// [`use`]: keyword.use.html /// [Reference]: ../reference/items/associated-items.html#methods -mod self_keyword {} +const _: () = (); // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we can replace // these two lines with `#[doc(keyword = "Self")]` and update `is_doc_keyword` in @@ -1540,7 +1540,7 @@ mod self_keyword {} /// /// [`impl`]: keyword.impl.html /// [`trait`]: keyword.trait.html -mod self_upper_keyword {} +const _: () = (); #[doc(keyword = "static")] // @@ -1626,7 +1626,7 @@ mod self_upper_keyword {} /// [`RefCell`]: cell::RefCell /// [atomic]: sync::atomic /// [Reference]: ../reference/items/static-items.html -mod static_keyword {} +const _: () = (); #[doc(keyword = "struct")] // @@ -1734,7 +1734,7 @@ mod static_keyword {} /// [`PhantomData`]: marker::PhantomData /// [book]: ../book/ch05-01-defining-structs.html /// [reference]: ../reference/items/structs.html -mod struct_keyword {} +const _: () = (); #[doc(keyword = "super")] // @@ -1760,7 +1760,7 @@ mod struct_keyword {} /// /// [module]: ../reference/items/modules.html /// [Reference]: ../reference/paths.html#super -mod super_keyword {} +const _: () = (); #[doc(keyword = "trait")] // @@ -1945,7 +1945,7 @@ mod super_keyword {} /// [`unsafe`]: keyword.unsafe.html /// [Ref-Traits]: ../reference/items/traits.html /// [Ref-Trait-Objects]: ../reference/types/trait-object.html -mod trait_keyword {} +const _: () = (); #[doc(keyword = "true")] // @@ -1972,7 +1972,7 @@ mod trait_keyword {} /// [`while`]: keyword.while.html /// [`match`]: ../reference/expressions/match-expr.html#match-guards /// [`false`]: keyword.false.html -mod true_keyword {} +const _: () = (); #[doc(keyword = "type")] // @@ -2024,7 +2024,7 @@ mod true_keyword {} /// [`trait`]: keyword.trait.html /// [associated type]: ../reference/items/associated-items.html#associated-types /// [alias]: ../reference/items/type-aliases.html -mod type_keyword {} +const _: () = (); #[doc(keyword = "unsafe")] // @@ -2310,7 +2310,7 @@ mod type_keyword {} /// [soundness]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library /// [Reference]: ../reference/unsafety.html /// [discussion on Rust Internals]: https://internals.rust-lang.org/t/what-does-unsafe-mean/6696 -mod unsafe_keyword {} +const _: () = (); #[doc(keyword = "use")] // @@ -2408,7 +2408,7 @@ mod unsafe_keyword {} /// [`super`]: keyword.super.html /// [ref-use-decls]: ../reference/items/use-declarations.html /// [ref-impl-trait]: ../reference/types/impl-trait.html -mod use_keyword {} +const _: () = (); #[doc(keyword = "where")] // @@ -2508,7 +2508,7 @@ mod use_keyword {} /// ``` /// /// [RFC]: https://github.com/rust-lang/rfcs/blob/master/text/0135-where.md -mod where_keyword {} +const _: () = (); #[doc(keyword = "while")] // @@ -2566,7 +2566,7 @@ mod where_keyword {} /// [`for`]: keyword.for.html /// [`loop`]: keyword.loop.html /// [reference]: ../reference/expressions/loop-expr.html#predicate-loops -mod while_keyword {} +const _: () = (); // 2018 Edition keywords @@ -2628,7 +2628,7 @@ mod while_keyword {} /// [never type]: ../reference/types/never.html /// [`Result`]: result::Result /// [async book blocks]: https://rust-lang.github.io/async-book/part-guide/more-async-await.html#async-blocks -mod async_keyword {} +const _: () = (); #[doc(keyword = "await")] // @@ -2648,7 +2648,7 @@ mod async_keyword {} /// [`Future`]: future::Future /// [async book]: https://rust-lang.github.io/async-book/ /// [`async`]: ../std/keyword.async.html -mod await_keyword {} +const _: () = (); #[doc(keyword = "dyn")] // @@ -2684,7 +2684,7 @@ mod await_keyword {} /// [ref-dyn-compat]: ../reference/items/traits.html#dyn-compatibility /// [erased]: https://en.wikipedia.org/wiki/Type_erasure /// [^1]: Formerly known as *object safe*. -mod dyn_keyword {} +const _: () = (); #[doc(keyword = "union")] // @@ -2758,4 +2758,4 @@ mod dyn_keyword {} /// /// [`struct`]: keyword.struct.html /// [union]: ../reference/items/unions.html -mod union_keyword {} +const _: () = (); diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index d80c55538055b..3e1596689e9d1 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -58,7 +58,7 @@ /// assert_eq!(false as i32, 0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -mod prim_bool {} +const _: () = (); #[rustc_doc_primitive = "never"] #[doc(alias = "!")] @@ -312,7 +312,7 @@ mod prim_bool {} /// [2024 edition]: /// #[unstable(feature = "never_type", issue = "35121")] -mod prim_never {} +const _: () = (); // Required to make auto trait impls render. // See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls @@ -448,7 +448,7 @@ impl ! {} /// assert_eq!(32, size_of_val(&v[..])); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -mod prim_char {} +const _: () = (); #[rustc_doc_primitive = "unit"] #[doc(alias = "(")] @@ -489,7 +489,7 @@ mod prim_char {} /// ``` /// #[stable(feature = "rust1", since = "1.0.0")] -mod prim_unit {} +const _: () = (); // Required to make auto trait impls render. // See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls @@ -616,7 +616,7 @@ impl () {} /// [`write`]: ptr::write /// [valid]: ptr#safety #[stable(feature = "rust1", since = "1.0.0")] -mod prim_pointer {} +const _: () = (); #[rustc_doc_primitive = "array"] #[doc(alias = "[]")] @@ -828,7 +828,7 @@ mod prim_pointer {} /// [slice pattern]: ../reference/patterns.html#slice-patterns /// [`From`]: convert::From #[stable(feature = "rust1", since = "1.0.0")] -mod prim_array {} +const _: () = (); #[rustc_doc_primitive = "slice"] #[doc(alias = "[")] @@ -942,7 +942,7 @@ mod prim_array {} /// [`.chunks`]: slice::chunks /// [`.windows`]: slice::windows #[stable(feature = "rust1", since = "1.0.0")] -mod prim_slice {} +const _: () = (); #[rustc_doc_primitive = "str"] /// String slices. @@ -1015,7 +1015,7 @@ mod prim_slice {} /// called on a string slice may assume that it is valid UTF-8, which means that a non-UTF-8 string /// slice can lead to undefined behavior down the road. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_str {} +const _: () = (); #[rustc_doc_primitive = "tuple"] #[doc(alias = "(")] @@ -1142,7 +1142,7 @@ mod prim_str {} /// ``` /// #[stable(feature = "rust1", since = "1.0.0")] -mod prim_tuple {} +const _: () = (); // Required to make auto trait impls render. // See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls @@ -1167,7 +1167,7 @@ impl (T,) {} /// /// [wikipedia]: https://en.wikipedia.org/wiki/Half-precision_floating-point_format #[unstable(feature = "f16", issue = "116909")] -mod prim_f16 {} +const _: () = (); #[rustc_doc_primitive = "f32"] #[doc(alias = "single")] @@ -1380,7 +1380,7 @@ mod prim_f16 {} /// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -mod prim_f32 {} +const _: () = (); #[rustc_doc_primitive = "f64"] #[doc(alias = "double")] @@ -1394,7 +1394,7 @@ mod prim_f32 {} /// /// [wikipedia]: https://en.wikipedia.org/wiki/Double-precision_floating-point_format #[stable(feature = "rust1", since = "1.0.0")] -mod prim_f64 {} +const _: () = (); #[rustc_doc_primitive = "f128"] #[doc(alias = "quad")] @@ -1417,31 +1417,31 @@ mod prim_f64 {} /// /// [wikipedia]: https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format #[unstable(feature = "f128", issue = "116909")] -mod prim_f128 {} +const _: () = (); #[rustc_doc_primitive = "i8"] // /// The 8-bit signed integer type. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_i8 {} +const _: () = (); #[rustc_doc_primitive = "i16"] // /// The 16-bit signed integer type. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_i16 {} +const _: () = (); #[rustc_doc_primitive = "i32"] // /// The 32-bit signed integer type. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_i32 {} +const _: () = (); #[rustc_doc_primitive = "i64"] // /// The 64-bit signed integer type. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_i64 {} +const _: () = (); #[rustc_doc_primitive = "i128"] // @@ -1459,31 +1459,31 @@ mod prim_i64 {} /// do not use the same alignment. `i128` is intended to always match `__int128` and does not /// attempt to match `_BitInt(128)` on platforms without `__int128`. #[stable(feature = "i128", since = "1.26.0")] -mod prim_i128 {} +const _: () = (); #[rustc_doc_primitive = "u8"] // /// The 8-bit unsigned integer type. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_u8 {} +const _: () = (); #[rustc_doc_primitive = "u16"] // /// The 16-bit unsigned integer type. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_u16 {} +const _: () = (); #[rustc_doc_primitive = "u32"] // /// The 32-bit unsigned integer type. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_u32 {} +const _: () = (); #[rustc_doc_primitive = "u64"] // /// The 64-bit unsigned integer type. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_u64 {} +const _: () = (); #[rustc_doc_primitive = "u128"] // @@ -1491,7 +1491,7 @@ mod prim_u64 {} /// /// Please see [the documentation for `i128`](prim@i128) for information on ABI compatibility. #[stable(feature = "i128", since = "1.26.0")] -mod prim_u128 {} +const _: () = (); #[rustc_doc_primitive = "isize"] // @@ -1501,7 +1501,7 @@ mod prim_u128 {} /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_isize {} +const _: () = (); #[rustc_doc_primitive = "usize"] // @@ -1511,7 +1511,7 @@ mod prim_isize {} /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_usize {} +const _: () = (); #[rustc_doc_primitive = "reference"] #[doc(alias = "&")] @@ -1672,7 +1672,7 @@ mod prim_usize {} /// /// [allocation]: ptr#allocation #[stable(feature = "rust1", since = "1.0.0")] -mod prim_ref {} +const _: () = (); #[rustc_doc_primitive = "fn"] // @@ -1947,7 +1947,7 @@ mod prim_ref {} /// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because /// these traits are specially known to the compiler. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_fn {} +const _: () = (); // Required to make auto trait impls render. // See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index ec03dba854578..3b5bf4ae080dc 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -130,7 +130,7 @@ To do so, the `#[doc(keyword = "...")]` attribute is used. Example: /// Some documentation about the keyword. #[doc(keyword = "break")] -mod empty_mod {} +const _: () = (); ``` ### Document builtin attributes @@ -147,7 +147,7 @@ To do so, the `#[doc(attribute = "...")]` attribute is used. Example: /// Some documentation about the attribute. #[doc(attribute = "repr")] -mod empty_mod {} +const _: () = (); ``` ### Use the Rust logo as the crate logo diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5c8d6d619b647..47b701e3c42d7 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -236,7 +236,7 @@ impl ExternalCrate { .unwrap_or(Unknown) // Well, at least we tried. } - fn mapped_root_modules( + fn mapped_root_anon_consts( &self, tcx: TyCtxt<'_>, f: impl Fn(DefId, TyCtxt<'_>) -> Option<(DefId, T)>, @@ -248,7 +248,7 @@ impl ExternalCrate { tcx.hir_root_module() .item_ids .iter() - .filter(move |&&id| matches!(tcx.hir_item(id).kind, hir::ItemKind::Mod(..))) + .filter(move |&&id| matches!(tcx.hir_item(id).kind, hir::ItemKind::Const(..))) .filter_map(move |&id| f(id.owner_id.into(), tcx)), ) } else { @@ -256,7 +256,11 @@ impl ExternalCrate { tcx.module_children(root) .iter() .filter_map(|item| { - if let Res::Def(DefKind::Mod, did) = item.res { Some(did) } else { None } + if let Res::Def(DefKind::Const { is_type_const: false }, did) = item.res { + Some(did) + } else { + None + } }) .filter_map(move |did| f(did, tcx)), ) @@ -281,7 +285,7 @@ impl ExternalCrate { let as_target = move |did: DefId, tcx: TyCtxt<'_>| -> Option<(DefId, Symbol)> { find_attr!(tcx, did, Doc(d) => callback(d)).flatten().map(|value| (did, value)) }; - self.mapped_root_modules(tcx, as_target) + self.mapped_root_anon_consts(tcx, as_target) } pub(crate) fn primitives( @@ -316,7 +320,7 @@ impl ExternalCrate { Some((def_id, prim)) } - self.mapped_root_modules(tcx, as_primitive) + self.mapped_root_anon_consts(tcx, as_primitive) } } @@ -984,10 +988,10 @@ pub(crate) enum ItemKind { AssocTypeItem(Box, Vec), /// An item that has been stripped by a rustdoc pass StrippedItem(Box), - /// This item represents a module with a `#[doc(keyword = "...")]` attribute which is used + /// This item represents an anonymous constant with a `#[doc(keyword = "...")]` attribute which is used /// to generate documentation for Rust keywords. KeywordItem, - /// This item represents a module with a `#[doc(attribute = "...")]` attribute which is used + /// This item represents an anonymous constant with a `#[doc(attribute = "...")]` attribute which is used /// to generate documentation for Rust builtin attributes. AttributeItem, } diff --git a/tests/run-make/rustdoc/search-load-itemtype/foo.rs b/tests/run-make/rustdoc/search-load-itemtype/foo.rs index 93b372d10cbf9..ad580b2505cac 100644 --- a/tests/run-make/rustdoc/search-load-itemtype/foo.rs +++ b/tests/run-make/rustdoc/search-load-itemtype/foo.rs @@ -4,15 +4,13 @@ //@ has foo/keyword.while.html //@ hasraw search.index/name/*.js while -//@ !hasraw search.index/name/*.js w_keyword #[doc(keyword = "while")] -mod w_keyword {} +const _: () = (); //@ has foo/primitive.u32.html //@ hasraw search.index/name/*.js u32 -//@ !hasraw search.index/name/*.js u_primitive #[rustc_doc_primitive = "u32"] -mod u_primitive {} +const _: () = (); //@ has foo/x_mod/index.html //@ hasraw search.index/name/*.js x_mod @@ -114,6 +112,5 @@ pub trait ATraitAlias = ATrait; //@ has foo/attribute.doc.html //@ hasraw search.index/name/*.js doc -//@ !hasraw search.index/name/*.js aa_mod #[doc(attribute = "doc")] -mod aa_mod {} +const _: () = (); diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 2bba2ac101544..4f8b4a93865a5 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -179,11 +179,11 @@ pub enum AnEnum { #[doc(keyword = "for")] /// Some keyword. -pub mod keyword {} +const _: () = (); #[doc(attribute = "forbid")] /// Some attribute. -pub mod repr {} +const _: () = (); /// Just some type alias. pub type SomeType = u32; diff --git a/tests/rustdoc-html/auto/auto-impl-primitive.rs b/tests/rustdoc-html/auto/auto-impl-primitive.rs index 3dab02506ca61..b9c9edc0c6bbc 100644 --- a/tests/rustdoc-html/auto/auto-impl-primitive.rs +++ b/tests/rustdoc-html/auto/auto-impl-primitive.rs @@ -7,4 +7,4 @@ pub use std::fs::File; //@ has 'foo/primitive.i16.html' '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementation' #[rustc_doc_primitive = "i16"] /// I love poneys! -mod prim {} +const _: () = (); diff --git a/tests/rustdoc-html/doc-attribute.rs b/tests/rustdoc-html/doc-attribute.rs index 47f2a7fccf6fe..289395c220ffd 100644 --- a/tests/rustdoc-html/doc-attribute.rs +++ b/tests/rustdoc-html/doc-attribute.rs @@ -11,14 +11,12 @@ //@ has foo/attribute.no_mangle.html '//h1' 'Attribute no_mangle' //@ has foo/attribute.no_mangle.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' //@ has foo/index.html '//a/@href' '../foo/index.html' -//@ !has foo/foo/index.html -//@ !has-dir foo/foo //@ !has foo/index.html '//span' '🔒' #[doc(attribute = "no_mangle")] /// this is a test! -mod foo{} +const _: () = (); //@ has foo/attribute.repr.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' #[doc(attribute = "repr")] /// hello -mod bar {} +const _: () = (); diff --git a/tests/rustdoc-html/doc-on-keyword.rs b/tests/rustdoc-html/doc-on-keyword.rs index 0c62eda60a6b3..d622624cdaa21 100644 --- a/tests/rustdoc-html/doc-on-keyword.rs +++ b/tests/rustdoc-html/doc-on-keyword.rs @@ -10,4 +10,4 @@ #[doc(keyword = "trait")] // /// [`Send`] and [Sync] -mod bar {} +const _: () = (); diff --git a/tests/rustdoc-html/intra-doc/auxiliary/my-core.rs b/tests/rustdoc-html/intra-doc/auxiliary/my-core.rs index a33b0582b31a8..4e6686023ba9e 100644 --- a/tests/rustdoc-html/intra-doc/auxiliary/my-core.rs +++ b/tests/rustdoc-html/intra-doc/auxiliary/my-core.rs @@ -5,7 +5,7 @@ #[rustc_doc_primitive = "char"] /// Some char docs -mod char {} +const _: () = (); impl char { pub fn len_utf8(self) -> usize { diff --git a/tests/rustdoc-html/intra-doc/prim-methods-local.rs b/tests/rustdoc-html/intra-doc/prim-methods-local.rs index f6aa1ed215654..1a9ae0ed84bdf 100644 --- a/tests/rustdoc-html/intra-doc/prim-methods-local.rs +++ b/tests/rustdoc-html/intra-doc/prim-methods-local.rs @@ -11,7 +11,7 @@ //! A [prim@`char`] and its [`char::len_utf8`]. #[rustc_doc_primitive = "char"] -mod char {} +const _: () = (); impl char { pub fn len_utf8(self) -> usize { diff --git a/tests/rustdoc-html/intra-doc/prim-self.rs b/tests/rustdoc-html/intra-doc/prim-self.rs index 21368fab99358..7b5911abe3d1d 100644 --- a/tests/rustdoc-html/intra-doc/prim-self.rs +++ b/tests/rustdoc-html/intra-doc/prim-self.rs @@ -27,7 +27,7 @@ impl usize { #[rustc_doc_primitive = "usize"] /// This has some docs. -mod usize {} +const _: () = (); /// [S::f] /// [Self::f] diff --git a/tests/rustdoc-html/keyword.rs b/tests/rustdoc-html/keyword.rs index 8f86c8ffd380b..baa81725e6e58 100644 --- a/tests/rustdoc-html/keyword.rs +++ b/tests/rustdoc-html/keyword.rs @@ -9,14 +9,12 @@ //@ has foo/keyword.match.html '//h1' 'Keyword match' //@ has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' //@ has foo/index.html '//a/@href' '../foo/index.html' -//@ !has foo/foo/index.html -//@ !has-dir foo/foo //@ !has foo/index.html '//span' '🔒' #[doc(keyword = "match")] /// this is a test! -mod foo{} +const _: () = (); //@ has foo/keyword.break.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' #[doc(keyword = "break")] /// hello -mod bar {} +const _: () = (); diff --git a/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs index 043d787396d3d..c2935c10311cb 100644 --- a/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs +++ b/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs @@ -14,7 +14,7 @@ /// /// We need to put this in here, because notable traits /// that are implemented on foreign types don't show up. -mod reference {} +const _: () = (); //@ has doc_notable_trait_mut_t_is_not_an_iterator/fn.fn_no_matches.html //@ !has - '//code[@class="content"]' 'Iterator' diff --git a/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs index 6a9fbb9ac0bdd..50767e6a4da07 100644 --- a/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs +++ b/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs @@ -12,7 +12,7 @@ /// /// We need to put this in here, because notable traits /// that are implemented on foreign types don't show up. -mod reference {} +const _: () = (); //@ has doc_notable_trait_mut_t_is_not_ref_t/fn.fn_no_matches.html //@ !has - '//code[@class="content"]' "impl<'_, I> Iterator for &'_ mut I" diff --git a/tests/rustdoc-html/primitive/auxiliary/issue-15318.rs b/tests/rustdoc-html/primitive/auxiliary/issue-15318.rs index d3dc89113fc53..95a59a137b8c7 100644 --- a/tests/rustdoc-html/primitive/auxiliary/issue-15318.rs +++ b/tests/rustdoc-html/primitive/auxiliary/issue-15318.rs @@ -14,4 +14,4 @@ fn bar(_: &core::panic::PanicInfo) -> ! { loop {} } /// dox #[rustc_doc_primitive = "pointer"] -pub mod ptr {} +const _: () = (); diff --git a/tests/rustdoc-html/primitive/auxiliary/primitive-doc.rs b/tests/rustdoc-html/primitive/auxiliary/primitive-doc.rs index 859716c38e462..f985cee8c6366 100644 --- a/tests/rustdoc-html/primitive/auxiliary/primitive-doc.rs +++ b/tests/rustdoc-html/primitive/auxiliary/primitive-doc.rs @@ -2,10 +2,18 @@ //@ edition: 2018 #![feature(rustc_attrs)] -#![feature(no_core)] +#![feature(no_core, lang_items)] #![no_core] +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + #[rustc_doc_primitive = "usize"] /// This is the built-in type `usize`. -mod usize { -} +const _: () = (); diff --git a/tests/rustdoc-html/primitive/cross-crate-primitive-doc.rs b/tests/rustdoc-html/primitive/cross-crate-primitive-doc.rs index 3c159d57f13f1..ca33dedcbaec7 100644 --- a/tests/rustdoc-html/primitive/cross-crate-primitive-doc.rs +++ b/tests/rustdoc-html/primitive/cross-crate-primitive-doc.rs @@ -2,18 +2,9 @@ //@ compile-flags: --extern-html-root-url=primitive_doc=../ -Z unstable-options //@ only-linux -#![feature(no_core, lang_items)] +#![feature(no_core)] #![no_core] -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - extern crate primitive_doc; //@ has 'cross_crate_primitive_doc/fn.foo.html' '//a[@href="../primitive_doc/primitive.usize.html"]' 'usize' diff --git a/tests/rustdoc-html/primitive/primitive-generic-impl.rs b/tests/rustdoc-html/primitive/primitive-generic-impl.rs index b342e977cf077..3363d1c966ef5 100644 --- a/tests/rustdoc-html/primitive/primitive-generic-impl.rs +++ b/tests/rustdoc-html/primitive/primitive-generic-impl.rs @@ -5,4 +5,4 @@ #[rustc_doc_primitive = "i32"] /// Some useless docs, wouhou! -mod i32 {} +const _: () = (); diff --git a/tests/rustdoc-html/primitive/primitive-raw-pointer-dox-15318-3.rs b/tests/rustdoc-html/primitive/primitive-raw-pointer-dox-15318-3.rs index 5520abf29250c..4f8b186b92a9c 100644 --- a/tests/rustdoc-html/primitive/primitive-raw-pointer-dox-15318-3.rs +++ b/tests/rustdoc-html/primitive/primitive-raw-pointer-dox-15318-3.rs @@ -6,4 +6,4 @@ /// dox #[rustc_doc_primitive = "pointer"] -pub mod ptr {} +const _: () = (); diff --git a/tests/rustdoc-html/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs b/tests/rustdoc-html/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs index 16b007e8bbda5..0629e62e6ade3 100644 --- a/tests/rustdoc-html/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs +++ b/tests/rustdoc-html/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs @@ -7,8 +7,6 @@ extern crate issue_15318; -pub use issue_15318::ptr; - //@ !has issue_15318_2/fn.bar.html \ // '//*[@href="primitive.pointer.html"]' \ // '*mut T' diff --git a/tests/rustdoc-html/primitive/primitive-reference.rs b/tests/rustdoc-html/primitive/primitive-reference.rs index bd6b2a32f754f..699585f828366 100644 --- a/tests/rustdoc-html/primitive/primitive-reference.rs +++ b/tests/rustdoc-html/primitive/primitive-reference.rs @@ -17,7 +17,7 @@ // 'impl Foo<&A> for &B' #[rustc_doc_primitive = "reference"] /// this is a test! -mod reference {} +const _: () = (); pub struct Bar; diff --git a/tests/rustdoc-html/primitive/primitive-slice-auto-trait.rs b/tests/rustdoc-html/primitive/primitive-slice-auto-trait.rs index 647c1cca94810..ce5c2319b09d4 100644 --- a/tests/rustdoc-html/primitive/primitive-slice-auto-trait.rs +++ b/tests/rustdoc-html/primitive/primitive-slice-auto-trait.rs @@ -11,4 +11,4 @@ //@ has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Sync for [T]where T: Sync' #[rustc_doc_primitive = "slice"] /// this is a test! -mod slice_prim {} +const _: () = (); diff --git a/tests/rustdoc-html/primitive/primitive-tuple-auto-trait.rs b/tests/rustdoc-html/primitive/primitive-tuple-auto-trait.rs index 51300bd6b2fc6..74fe6d21eb41f 100644 --- a/tests/rustdoc-html/primitive/primitive-tuple-auto-trait.rs +++ b/tests/rustdoc-html/primitive/primitive-tuple-auto-trait.rs @@ -19,4 +19,4 @@ /// This header is hard-coded in the HTML format linking for `#[doc(fake_variadics)]`. /// To make sure it gets linked correctly, we need to make sure the hardcoded anchor /// in the code matches what rustdoc generates for the header. -mod tuple_prim {} +const _: () = (); diff --git a/tests/rustdoc-html/primitive/primitive-unit-auto-trait.rs b/tests/rustdoc-html/primitive/primitive-unit-auto-trait.rs index 7dada1f9832e6..8c80a450ae130 100644 --- a/tests/rustdoc-html/primitive/primitive-unit-auto-trait.rs +++ b/tests/rustdoc-html/primitive/primitive-unit-auto-trait.rs @@ -11,4 +11,4 @@ //@ has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Sync for ()' #[rustc_doc_primitive = "unit"] /// this is a test! -mod unit_prim {} +const _: () = (); diff --git a/tests/rustdoc-html/primitive/primitive.rs b/tests/rustdoc-html/primitive/primitive.rs index b54c3dd1cd613..aef0dc15cd401 100644 --- a/tests/rustdoc-html/primitive/primitive.rs +++ b/tests/rustdoc-html/primitive/primitive.rs @@ -15,19 +15,19 @@ //@ !has foo/index.html '//span' '🔒' #[rustc_doc_primitive = "i32"] /// this is a test! -mod i32 {} +const _: () = (); //@ has foo/primitive.bool.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' #[rustc_doc_primitive = "bool"] /// hello -mod bool {} +const _: () = (); //@ has foo/primitive.f16.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' #[rustc_doc_primitive = "f16"] /// hello -mod f16 {} +const _: () = (); //@ has foo/primitive.f128.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' #[rustc_doc_primitive = "f128"] /// hello -mod f128 {} +const _: () = (); diff --git a/tests/rustdoc-html/primitive/search-index-primitive-inherent-method-23511.rs b/tests/rustdoc-html/primitive/search-index-primitive-inherent-method-23511.rs index ea828e08d82cc..b5022f1b5cf81 100644 --- a/tests/rustdoc-html/primitive/search-index-primitive-inherent-method-23511.rs +++ b/tests/rustdoc-html/primitive/search-index-primitive-inherent-method-23511.rs @@ -5,12 +5,11 @@ // https://github.com/rust-lang/rust/issues/23511 #![crate_name="issue_23511"] -pub mod str { - #![rustc_doc_primitive = "str"] +#[rustc_doc_primitive = "str"] +const _: () = (); - impl str { - //@ hasraw search.index/name/*.js foo - #[rustc_allow_incoherent_impl] - pub fn foo(&self) {} - } +impl str { + //@ hasraw search.index/name/*.js foo + #[rustc_allow_incoherent_impl] + pub fn foo(&self) {} } diff --git a/tests/rustdoc-html/sidebar/sidebar-all-page.rs b/tests/rustdoc-html/sidebar/sidebar-all-page.rs index 1f97a41404867..609fb525e649c 100644 --- a/tests/rustdoc-html/sidebar/sidebar-all-page.rs +++ b/tests/rustdoc-html/sidebar/sidebar-all-page.rs @@ -31,4 +31,4 @@ pub type Type = u8; pub const FOO: u8 = 0; pub static BAR: u8 = 0; #[rustc_doc_primitive = "u8"] -mod u8 {} +const _: () = (); diff --git a/tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def.rs b/tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def.rs index a7b944fa2f6fc..9036961358787 100644 --- a/tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def.rs +++ b/tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def.rs @@ -68,4 +68,4 @@ pub fn foo4() { //@ has - '//pre[@class="rust"]//a[@href="../../foo/primitive.bool.html"]' 'bool' #[rustc_doc_primitive = "bool"] -mod whatever {} +const _: () = (); diff --git a/tests/rustdoc-html/stability.rs b/tests/rustdoc-html/stability.rs index 22cd4b9cd5952..4870c68dfe5e6 100644 --- a/tests/rustdoc-html/stability.rs +++ b/tests/rustdoc-html/stability.rs @@ -160,7 +160,7 @@ pub trait UnstableTraitWithStableMethod { // /// `i32` is always stable in 1.0, even if you look at it from core. #[stable(feature = "rust1", since = "1.0.0")] -mod prim_i32 {} +const _: () = (); //@ has stability/keyword.if.html \ // '//div[@class="main-heading"]//span[@class="since"]' '1.0.0' @@ -168,4 +168,4 @@ mod prim_i32 {} // /// We currently don't document stability for keywords, but let's test it anyway. #[stable(feature = "rust1", since = "1.0.0")] -mod if_keyword {} +const _: () = (); diff --git a/tests/rustdoc-html/tab_title.rs b/tests/rustdoc-html/tab_title.rs index 59914065c9121..4056da412d4ae 100644 --- a/tests/rustdoc-html/tab_title.rs +++ b/tests/rustdoc-html/tab_title.rs @@ -36,10 +36,10 @@ pub mod blah { //@ has foo/keyword.continue.html '//head/title' 'continue - Rust' #[doc(keyword = "continue")] -mod continue_keyword {} +const _: () = (); //@ has foo/primitive.u8.html '//head/title' 'u8 - Rust' //@ !has - '//head/title' 'foo' #[rustc_doc_primitive = "u8"] /// `u8` docs -mod u8 {} +const _: () = (); diff --git a/tests/rustdoc-html/titles.rs b/tests/rustdoc-html/titles.rs index 922068adc5927..23915b05c2709 100644 --- a/tests/rustdoc-html/titles.rs +++ b/tests/rustdoc-html/titles.rs @@ -52,7 +52,7 @@ macro_rules! foo_macro { //@ matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool' //@ count - '//*[@class="rustdoc-breadcrumbs"]' 0 #[rustc_doc_primitive = "bool"] -mod bool {} +const _: () = (); //@ matches 'foo/static.FOO_STATIC.html' '//h1' 'Static FOO_STATIC' //@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo' diff --git a/tests/rustdoc-html/type-alias/primitive-local-link-121106.rs b/tests/rustdoc-html/type-alias/primitive-local-link-121106.rs index 3bdce3846c812..d4877e49a4125 100644 --- a/tests/rustdoc-html/type-alias/primitive-local-link-121106.rs +++ b/tests/rustdoc-html/type-alias/primitive-local-link-121106.rs @@ -5,7 +5,7 @@ //@ has foo/primitive.i32.html '//h1' 'Primitive Type i32' //@ has foo/index.html '//a/@href' '../foo/index.html' #[rustc_doc_primitive = "i32"] -mod i32 {} +const _: () = (); //@ has foo/struct.Node.html '//a/@href' 'primitive.i32.html' pub struct Node; diff --git a/tests/rustdoc-json/doc_attribute.rs b/tests/rustdoc-json/doc_attribute.rs index 9e1a711f0b7b5..1cb07e7a6debc 100644 --- a/tests/rustdoc-json/doc_attribute.rs +++ b/tests/rustdoc-json/doc_attribute.rs @@ -5,14 +5,11 @@ #![no_std] //@ !has "$.index[?(@.name=='repr')]" -//@ has "$.index[?(@.name=='foo')]" - #[doc(attribute = "repr")] /// this is a test! -pub mod foo {} +const _: () = (); //@ !has "$.index[?(@.name=='forbid')]" -//@ !has "$.index[?(@.name=='bar')]" #[doc(attribute = "forbid")] /// hello -mod bar {} +const _: () = (); diff --git a/tests/rustdoc-json/impls/local_for_local_primitive.rs b/tests/rustdoc-json/impls/local_for_local_primitive.rs index 859c0cb8ec82d..97ada2cf131bc 100644 --- a/tests/rustdoc-json/impls/local_for_local_primitive.rs +++ b/tests/rustdoc-json/impls/local_for_local_primitive.rs @@ -15,4 +15,4 @@ impl Local for bool {} //@ has "$.index[?(@.name=='bool')]" #[rustc_doc_primitive = "bool"] /// Boolean docs -mod prim_bool {} +const _: () = (); diff --git a/tests/rustdoc-json/keyword.rs b/tests/rustdoc-json/keyword.rs index 566b2c68bd5df..4f592745cf2b3 100644 --- a/tests/rustdoc-json/keyword.rs +++ b/tests/rustdoc-json/keyword.rs @@ -1,20 +1,17 @@ -// Regression test for . - -// Keywords should not be generated in rustdoc JSON output and this test -// ensures it. +//! Regression test for . +//! +//! Keywords should not be generated in rustdoc JSON output and this test +//! ensures it. #![feature(rustdoc_internals)] #![no_std] //@ !has "$.index[?(@.name=='match')]" -//@ has "$.index[?(@.name=='foo')]" - #[doc(keyword = "match")] /// this is a test! -pub mod foo {} +const _: () = (); //@ !has "$.index[?(@.name=='break')]" -//@ !has "$.index[?(@.name=='bar')]" #[doc(keyword = "break")] /// hello -mod bar {} +const _: () = (); diff --git a/tests/rustdoc-json/keyword_private.rs b/tests/rustdoc-json/keyword_private.rs index 3198fc2529ef8..d8da694f91465 100644 --- a/tests/rustdoc-json/keyword_private.rs +++ b/tests/rustdoc-json/keyword_private.rs @@ -1,20 +1,19 @@ -// Ensure keyword docs are present with --document-private-items +//! Regression test for . +//! +//! Keywords should not be generated in rustdoc JSON output and this test +//! ensures it. + +//@compile-flags: --document-private-items -//@ compile-flags: --document-private-items #![feature(rustdoc_internals)] +#![no_std] //@ !has "$.index[?(@.name=='match')]" -//@ has "$.index[?(@.name=='foo')]" -//@ is "$.index[?(@.name=='foo')].attrs[*].other" '"#[doc(keyword = \"match\")]"' -//@ is "$.index[?(@.name=='foo')].docs" '"this is a test!"' #[doc(keyword = "match")] /// this is a test! -pub mod foo {} +const _: () = (); //@ !has "$.index[?(@.name=='break')]" -//@ has "$.index[?(@.name=='bar')]" -//@ is "$.index[?(@.name=='bar')].attrs[*].other" '"#[doc(keyword = \"break\")]"' -//@ is "$.index[?(@.name=='bar')].docs" '"hello"' #[doc(keyword = "break")] /// hello -mod bar {} +const _: () = (); diff --git a/tests/rustdoc-json/primitives/local_primitive.rs b/tests/rustdoc-json/primitives/local_primitive.rs index b58120bae052f..e635cf12a6fb3 100644 --- a/tests/rustdoc-json/primitives/local_primitive.rs +++ b/tests/rustdoc-json/primitives/local_primitive.rs @@ -3,19 +3,25 @@ #![feature(no_core)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] +#![feature(lang_items)] #![no_core] #![rustc_coherence_is_core] //! Link to [i32][prim@i32] [i64][prim@i64] +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +pub trait Sized: MetaSized {} + #[rustc_doc_primitive = "i32"] -mod prim_i32 {} +const _: () = (); //@ set local_i32 = "$.index[?(@.name=='i32')].id" //@ has "$.index[?(@.name=='local_primitive')]" -//@ ismany "$.index[?(@.name=='local_primitive')].inner.module.items[*]" $local_i32 //@ is "$.index[?(@.name=='local_primitive')].links['prim@i32']" $local_i32 - -// Let's ensure the `prim_i32` module isn't present in the output JSON: -//@ !has "$.index[?(@.name=='prim_i32')]" diff --git a/tests/rustdoc-json/primitives/primitive_impls.rs b/tests/rustdoc-json/primitives/primitive_impls.rs index 2bdbb86862686..bb6f85a507696 100644 --- a/tests/rustdoc-json/primitives/primitive_impls.rs +++ b/tests/rustdoc-json/primitives/primitive_impls.rs @@ -35,7 +35,7 @@ impl Trait for i32 {} /// i32 #[rustc_doc_primitive = "i32"] -mod prim_i32 {} +const _: () = (); //@ set i32 = "$.index[?(@.docs=='i32')].id" //@ is "$.index[?(@.docs=='i32')].name" '"i32"' diff --git a/tests/rustdoc-json/primitives/primitive_overloading.rs b/tests/rustdoc-json/primitives/primitive_overloading.rs index ae0306843c56d..322411bcf4726 100644 --- a/tests/rustdoc-json/primitives/primitive_overloading.rs +++ b/tests/rustdoc-json/primitives/primitive_overloading.rs @@ -5,8 +5,7 @@ #![feature(rustc_attrs)] //@ has "$.index[?(@.name=='usize')]" -//@ has "$.index[?(@.name=='prim')]" #[rustc_doc_primitive = "usize"] /// This is the built-in type `usize`. -mod prim {} +const _: () = (); diff --git a/tests/rustdoc-json/primitives/use_primitive.rs b/tests/rustdoc-json/primitives/use_primitive.rs index 2991cc1e47c21..c3e3137bd0b2b 100644 --- a/tests/rustdoc-json/primitives/use_primitive.rs +++ b/tests/rustdoc-json/primitives/use_primitive.rs @@ -3,8 +3,7 @@ #![feature(rustc_attrs)] #[rustc_doc_primitive = "usize"] -mod usize {} - +const _: () = (); //@ set local_crate_id = "$.index[?(@.name=='use_primitive')].crate_id" //@ has "$.index[?(@.name=='ilog10')]" diff --git a/tests/rustdoc-ui/coverage/exotic.rs b/tests/rustdoc-ui/coverage/exotic.rs index 2beb890b21926..947ff43713b44 100644 --- a/tests/rustdoc-ui/coverage/exotic.rs +++ b/tests/rustdoc-ui/coverage/exotic.rs @@ -9,8 +9,8 @@ /// woo, check it out, we can write our own primitive docs lol #[rustc_doc_primitive = "unit"] -mod prim_unit {} +const _: () = (); /// keywords? sure, pile them on #[doc(keyword="where")] -mod where_keyword {} +const _: () = (); diff --git a/tests/rustdoc-ui/doc-attribute-unsupported.rs b/tests/rustdoc-ui/doc-attribute-unsupported.rs index 3bd153117a918..b709710644934 100644 --- a/tests/rustdoc-ui/doc-attribute-unsupported.rs +++ b/tests/rustdoc-ui/doc-attribute-unsupported.rs @@ -4,4 +4,4 @@ #[doc(attribute = "diagnostic::do_not_recommend")] //~ ERROR /// bla -mod yup {} +const _: () = (); diff --git a/tests/rustdoc-ui/invalid-attribute.rs b/tests/rustdoc-ui/invalid-attribute.rs index 2fc7be2cf341d..c229b067de6ef 100644 --- a/tests/rustdoc-ui/invalid-attribute.rs +++ b/tests/rustdoc-ui/invalid-attribute.rs @@ -4,7 +4,7 @@ #![feature(rustdoc_internals)] #[doc(attribute = "foo df")] //~ ERROR -mod foo {} +const _: () = (); #[doc(attribute = "fooyi")] //~ ERROR -mod foo2 {} +const _: () = (); diff --git a/tests/rustdoc-ui/invalid-keyword.rs b/tests/rustdoc-ui/invalid-keyword.rs index 2d70471c85e11..a9ff7d51ed2c2 100644 --- a/tests/rustdoc-ui/invalid-keyword.rs +++ b/tests/rustdoc-ui/invalid-keyword.rs @@ -1,4 +1,4 @@ #![feature(rustdoc_internals)] #[doc(keyword = "foo df")] //~ ERROR -mod foo {} +const _: () = (); diff --git a/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs b/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs index 0ad3b2aead481..7aa6dcbd5daac 100644 --- a/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs +++ b/tests/ui/feature-gates/feature-gate-rustdoc_internals.rs @@ -1,10 +1,10 @@ #[doc(keyword = "match")] //~ ERROR: `#[doc(keyword)]` is meant for internal use only /// wonderful -mod foo {} +const _: () = (); #[doc(attribute = "repr")] //~ ERROR: `#[doc(attribute)]` is meant for internal use only /// wonderful -mod foo2 {} +const _: () = (); trait Mine {} diff --git a/tests/ui/rustdoc/doc_keyword.rs b/tests/ui/rustdoc/doc_keyword.rs index abf06d7a78663..003f90f8d0afb 100644 --- a/tests/ui/rustdoc/doc_keyword.rs +++ b/tests/ui/rustdoc/doc_keyword.rs @@ -3,21 +3,17 @@ #![doc(keyword = "match")] //~^ ERROR `#![doc(keyword = "...")]` isn't allowed as a crate-level attribute -#[doc(keyword = "match")] //~ ERROR `#[doc(keyword = "...")]` should be used on empty modules -mod foo { - fn hell() {} -} -#[doc(keyword = "match")] //~ ERROR `#[doc(keyword = "...")]` should be used on modules +#[doc(keyword = "match")] //~ ERROR `#[doc(keyword = "...")]` should be used on anonymous constants fn foo() {} // Regression test for the ICE described in #83512. trait Foo { #[doc(keyword = "match")] - //~^ ERROR: `#[doc(keyword = "...")]` should be used on modules + //~^ ERROR: `#[doc(keyword = "...")]` should be used on anonymous constants fn quux() {} } #[doc(keyword = "tadam")] //~ ERROR nonexistent keyword `tadam` -mod tadam {} +const _: () = (); diff --git a/tests/ui/rustdoc/doc_keyword.stderr b/tests/ui/rustdoc/doc_keyword.stderr index c8038cbf01969..016ec61924e8a 100644 --- a/tests/ui/rustdoc/doc_keyword.stderr +++ b/tests/ui/rustdoc/doc_keyword.stderr @@ -5,30 +5,24 @@ LL | #![doc(keyword = "match")] | ^^^^^^^ error: nonexistent keyword `tadam` used in `#[doc(keyword = "...")]` - --> $DIR/doc_keyword.rs:22:17 + --> $DIR/doc_keyword.rs:18:17 | LL | #[doc(keyword = "tadam")] | ^^^^^^^ | = help: only existing keywords are allowed in core/std -error: `#[doc(keyword = "...")]` should be used on empty modules - --> $DIR/doc_keyword.rs:6:7 +error: `#[doc(keyword = "...")]` should be used on anonymous constants + --> $DIR/doc_keyword.rs:7:7 | LL | #[doc(keyword = "match")] | ^^^^^^^ -error: `#[doc(keyword = "...")]` should be used on modules - --> $DIR/doc_keyword.rs:11:7 - | -LL | #[doc(keyword = "match")] - | ^^^^^^^ - -error: `#[doc(keyword = "...")]` should be used on modules - --> $DIR/doc_keyword.rs:17:11 +error: `#[doc(keyword = "...")]` should be used on anonymous constants + --> $DIR/doc_keyword.rs:13:11 | LL | #[doc(keyword = "match")] | ^^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/rustdoc/feature-gate-doc_primitive.rs b/tests/ui/rustdoc/feature-gate-doc_primitive.rs index 0ff8ce8c24bca..62f2c535edc17 100644 --- a/tests/ui/rustdoc/feature-gate-doc_primitive.rs +++ b/tests/ui/rustdoc/feature-gate-doc_primitive.rs @@ -3,6 +3,6 @@ //~| NOTE the `rustc_doc_primitive` attribute is an internal implementation detail that will never be stable //~| NOTE the `rustc_doc_primitive` attribute is used by the standard library to provide a way to generate documentation for primitive types /// Some docs -mod usize {} +const _: () = (); fn main() {} From 4449de3ac5f07a9b202391263e7c7f673de25276 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 11 Aug 2026 13:50:40 +0200 Subject: [PATCH 96/98] ensure anon consts themselves are not documented --- .../fake-items-doc-private-items.rs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/rustdoc-html/fake-items-doc-private-items.rs diff --git a/tests/rustdoc-html/fake-items-doc-private-items.rs b/tests/rustdoc-html/fake-items-doc-private-items.rs new file mode 100644 index 0000000000000..4d948fc606630 --- /dev/null +++ b/tests/rustdoc-html/fake-items-doc-private-items.rs @@ -0,0 +1,37 @@ +//! Test checking that these `_` constants don't show up +//@ compile-flags: --document-private-items + +//@ !has foo/constant._.html + +// both PUB_CONST and PRIV_CONST should show up, but not the anon consts +//@ count foo/index.html '//*[@class="constant"]' 2 +#![crate_name = "foo"] + +#![feature(rustdoc_internals)] +#![feature(rustc_attrs)] + +//@ has foo/attribute.no_mangle.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello attr' +#[doc(attribute = "no_mangle")] +/// hello attr +const _: () = (); + +//@ has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello kw' +#[doc(keyword = "match")] +/// hello kw +const _: () = (); + +//@ has foo/primitive.i128.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello prim' +#[rustc_doc_primitive = "i128"] +/// hello prim +const _: () = (); + +/// regular anon const +const _: () = (); + +//@ has foo/constant.PUB_CONST.html +/// woop +pub const PUB_CONST: i32 = 42; + +//@ has foo/constant.PRIV_CONST.html +/// woop2 +const PRIV_CONST: i32 = 42; From 00a552fa8af1aeede7cb792f9e68ab0a9b1c1c7f Mon Sep 17 00:00:00 2001 From: im-lunex Date: Thu, 13 Aug 2026 13:41:55 +0000 Subject: [PATCH 97/98] check `mut`-restriction when tuple constructor is used as a value * check mut restriction when tuple ctor is used as a value * add missing stderr file for mut-restriction ctor value test * simplify def_kind matching in tuple ctor mut restriction check Match the DefKind::Ctor directly on the result of tcx.def_kind instead of binding it to a local first. Extend the ctor-value ui test with additional enum variants covering plain and crate-restricted fields. * test: exercise new ctor variants * address review: drop shell.nix, add tests --- .../src/check_mut_restriction.rs | 35 ++++++++++++++++ .../mut-restriction-ctor-value.rs | 40 +++++++++++++++++++ .../mut-restriction-ctor-value.stderr | 38 ++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 tests/ui/mut-restriction/mut-restriction-ctor-value.rs create mode 100644 tests/ui/mut-restriction/mut-restriction-ctor-value.stderr diff --git a/compiler/rustc_mir_transform/src/check_mut_restriction.rs b/compiler/rustc_mir_transform/src/check_mut_restriction.rs index 9d6809ea837cf..96f367952bd2b 100644 --- a/compiler/rustc_mir_transform/src/check_mut_restriction.rs +++ b/compiler/rustc_mir_transform/src/check_mut_restriction.rs @@ -1,3 +1,4 @@ +use rustc_hir::def::{CtorOf, DefKind}; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; @@ -34,6 +35,40 @@ impl<'tcx> Visitor<'tcx> for MutRestrictionChecker<'_, 'tcx> { self.super_statement(statement, location); } + // Tuple constructors used as values can bypass field mut restrictions if not checked here. + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Location) { + if let ty::FnDef(def_id, _) = *constant.const_.ty().kind() + && let DefKind::Ctor(ctor_of, _) = self.tcx.def_kind(def_id) + { + let body_did = self.body.source.instance.def_id(); + let adt_did = match ctor_of { + CtorOf::Struct => self.tcx.parent(def_id), + CtorOf::Variant => self.tcx.parent(self.tcx.parent(def_id)), + }; + let adt = self.tcx.adt_def(adt_did); + let variant = match ctor_of { + CtorOf::Struct => adt.non_enum_variant(), + CtorOf::Variant => adt.variant_with_ctor_id(def_id), + }; + + let mut_restriction = + variant.fields.iter().fold(ty::RestrictionKind::Unrestricted, |acc, field| { + acc.stricter_of(field.mut_restriction, self.tcx) + }); + if !mut_restriction.is_allowed_in(body_did, self.tcx) { + self.tcx.dcx().emit_err(diagnostics::ConstructionOfTyWithMutRestrictedField { + construction_span: constant.span, + restriction_span: mut_restriction.expect_span(), + name: variant.name, + descr: adt.variant_descr(), + restriction_path: mut_restriction.restriction_path(self.tcx), + }); + } + } + + self.super_const_operand(constant, location); + } + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { if context.is_mutating_use() { let body_did = self.body.source.instance.def_id(); diff --git a/tests/ui/mut-restriction/mut-restriction-ctor-value.rs b/tests/ui/mut-restriction/mut-restriction-ctor-value.rs new file mode 100644 index 0000000000000..7ca33ff4bdd22 --- /dev/null +++ b/tests/ui/mut-restriction/mut-restriction-ctor-value.rs @@ -0,0 +1,40 @@ +//@ edition: 2018.. +#![feature(mut_restriction)] + +pub mod inner { + #[derive(Default)] + pub struct Wrapper(pub mut(self) u8); + + pub enum EnumTup { + Tup(mut(self) u8), + Foo(u8), + Bar(u8, mut(crate) u8), + } + + pub fn construct_inner() { + let _ = Wrapper; + let _ = EnumTup::Tup; + let _ = EnumTup::Foo; + let _ = EnumTup::Bar; + } +} + +fn param_is_fn(_: fn(u8) -> inner::Wrapper) {} +fn param_impl_fn(_: impl Fn(u8) -> inner::Wrapper) {} + +fn main() { + let _ = inner::Wrapper; + //~^ ERROR `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + + param_is_fn(inner::Wrapper); + //~^ ERROR `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + + param_impl_fn(inner::Wrapper); + //~^ ERROR `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + + let _ = inner::EnumTup::Tup; + //~^ ERROR `Tup` cannot be constructed using a `variant` expression outside `crate::inner` + + let _ = inner::EnumTup::Foo; + let _ = inner::EnumTup::Bar; +} diff --git a/tests/ui/mut-restriction/mut-restriction-ctor-value.stderr b/tests/ui/mut-restriction/mut-restriction-ctor-value.stderr new file mode 100644 index 0000000000000..b10a3c15592c3 --- /dev/null +++ b/tests/ui/mut-restriction/mut-restriction-ctor-value.stderr @@ -0,0 +1,38 @@ +error: `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + --> $DIR/mut-restriction-ctor-value.rs:26:13 + | +LL | pub struct Wrapper(pub mut(self) u8); + | --------- field restricted here +... +LL | let _ = inner::Wrapper; + | ^^^^^^^^^^^^^^ + +error: `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + --> $DIR/mut-restriction-ctor-value.rs:29:17 + | +LL | pub struct Wrapper(pub mut(self) u8); + | --------- field restricted here +... +LL | param_is_fn(inner::Wrapper); + | ^^^^^^^^^^^^^^ + +error: `Wrapper` cannot be constructed using a `struct` expression outside `crate::inner` + --> $DIR/mut-restriction-ctor-value.rs:32:19 + | +LL | pub struct Wrapper(pub mut(self) u8); + | --------- field restricted here +... +LL | param_impl_fn(inner::Wrapper); + | ^^^^^^^^^^^^^^ + +error: `Tup` cannot be constructed using a `variant` expression outside `crate::inner` + --> $DIR/mut-restriction-ctor-value.rs:35:13 + | +LL | Tup(mut(self) u8), + | --------- field restricted here +... +LL | let _ = inner::EnumTup::Tup; + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + From a89abc82257eb3b4f76a13dd6d38161dfd5ed4df Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Aug 2026 16:54:57 +0200 Subject: [PATCH 98/98] Fix link title attribute value when field of enum variants --- src/librustdoc/html/format.rs | 8 ++++++-- .../intra-doc/enum-variant-field-title.rs | 13 +++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/rustdoc-html/intra-doc/enum-variant-field-title.rs diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 4b9bf8bbd3a07..b3b5779fbaca9 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -674,11 +674,15 @@ pub(crate) fn link_tooltip( fqp }; if let &Some(UrlFragment::Item(id)) = fragment { - write!(f, "{} ", cx.tcx().def_descr(id))?; + let tcx = cx.tcx(); + write!(f, "{} ", tcx.def_descr(id))?; for component in fqp { write!(f, "{component}::")?; } - write!(f, "{}", cx.tcx().item_name(id))?; + if *shortty == ItemType::Enum && tcx.def_kind(id) == DefKind::Field { + write!(f, "{}::", tcx.item_name(tcx.parent(id)))?; + } + write!(f, "{}", tcx.item_name(id))?; } else if !fqp.is_empty() { write!(f, "{shortty} ")?; write!(f, "{}", join_path_syms(fqp))?; diff --git a/tests/rustdoc-html/intra-doc/enum-variant-field-title.rs b/tests/rustdoc-html/intra-doc/enum-variant-field-title.rs new file mode 100644 index 0000000000000..8fdfef11e4ff0 --- /dev/null +++ b/tests/rustdoc-html/intra-doc/enum-variant-field-title.rs @@ -0,0 +1,13 @@ +// This test ensures that the generated "title" attribute for field of enum variant +// is correctly generated and includes the variant's name. +// Regression test for . + +#![crate_name = "foo"] + +//@ has 'foo/enum.Enum.html' +//@ has - '//*[@class="docblock"]//a[@title="field foo::Enum::Variant::field"]' 'Enum::Variant::field' + +/// [Enum::Variant::field] +pub enum Enum { + Variant { field: i32 } +}