diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 1a74dff9d23d8..6a21f4bf92e28 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -da86f4d0726be475afbbffe40cb2f65741c51ad3 +e64c8a664d9da54fc239cd4404cbf67f0d624326 diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 3e46caa1e28d6..1dd08cff81a00 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -53,6 +53,9 @@ - [About the compiler team](./compiler-team.md) - [Using Git](./git.md) - [Mastering @rustbot](./rustbot.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) - [Implementing new language features](./implementing-new-features.md) - [Stability guarantees](./stability-guarantees.md) 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 6282a66e13b07..efa354ecd6b3c 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -74,6 +74,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. @@ -95,7 +96,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 @@ -115,3 +116,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/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md index 527da87b7b7e1..0ddb65a2e2b20 100644 --- a/src/doc/rustc-dev-guide/src/appendix/glossary.md +++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md @@ -3,6 +3,7 @@ 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). 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/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 5cbffb1a49eee..ef6c98cb6d978 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -520,6 +520,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/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index 0440fb0c5e736..023db80481e78 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -141,6 +141,35 @@ 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. + +### [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. + +### 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/). + +### 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. + +### 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 @@ -159,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/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. 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 = "...")]` 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..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,33 +1,33 @@ # `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`]. `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`] 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 +[`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 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`; diff --git a/src/doc/rustc-dev-guide/src/guides/editions.md b/src/doc/rustc-dev-guide/src/guides/editions.md index 535d82f8403b4..e5f8d38912a09 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. + 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`. [^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. 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..fb544a680fa8f 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 diff --git a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md index 8207b81665aa7..8b5b889bc6af3 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! 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..c1b34362d2f47 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/llm-guidance.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](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 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..439b1d809e706 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md @@ -0,0 +1,110 @@ +# 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 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 `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 `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: +- 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; +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 + +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: + +```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. +- 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: + +```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 + +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/writing.md b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md new file mode 100644 index 0000000000000..3cbdf3d2b849c --- /dev/null +++ b/src/doc/rustc-dev-guide/src/llm-guidance/writing.md @@ -0,0 +1,178 @@ +# 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, +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: + +> 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 +[#llm-mentoring]: https://rust-lang.zulipchat.com/join/rlfvpemsaacs3pfi6kwqnqjb/ + +## 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: + +- 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 + +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. +LLM-created Github comments are banned. + +## Guidelines + +### 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. +Go slow. + +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: + +- 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][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. +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. + +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. + +### Write maintainable code + +Treat generated code as a *draft*, not a final product. +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: 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. +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); +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 + +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. + +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? +- 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? + +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 + +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 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. + +**Bad** examples: + +> 🤖 Generated with Claude Code + +> `Co-Authored-By: Claude Opus 4.6 (1M context) ` diff --git a/src/doc/rustc-dev-guide/src/memory.md b/src/doc/rustc-dev-guide/src/memory.md index 24e7205a3565b..6056f09ab2593 100644 --- a/src/doc/rustc-dev-guide/src/memory.md +++ b/src/doc/rustc-dev-guide/src/memory.md @@ -27,41 +27,42 @@ 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 -to that buffer is freed and our `'tcx` references would be invalid. +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 - defined and discussed in depth in the [`AdtDef and DefId`][adtdefid] section. + 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`] 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 @@ -69,9 +70,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,9 +81,9 @@ tcx: TyCtxt<'tcx> // arena lifetime ``` -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). +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). [`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html @@ -91,14 +92,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 -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 +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 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 { 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..52c197162993f 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,25 +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 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. 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..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 @@ -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 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..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 @@ -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 then approved by T-lang. ## How does it work? @@ -21,25 +21,27 @@ 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 -is an RPITIT for HIR ty lowering, diagnostics that deal with HIR, etc. +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. #### 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- -or late-bound during AST lowering, we just do this for all lifetimes. +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,23 +298,22 @@ 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 -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 +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 the RPITITs in the return type of the method with *placeholders*, which lead 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 { @@ -331,12 +323,11 @@ trait Foo { } ``` -requires one interesting hack. We need to install a projection predicate +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 +346,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 +380,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 +404,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)] diff --git a/src/doc/rustc-dev-guide/src/stability.md b/src/doc/rustc-dev-guide/src/stability.md index 52eb872a7e92e..cef8ce63f3b59 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. 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 d1378a849a9d4..41de1df9d02b0 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. 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..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 @@ -1,21 +1,38 @@ # 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. - - 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). +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,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). +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]. +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 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..3b4072394e787 100644 --- a/src/doc/rustc-dev-guide/src/traits/implied-bounds.md +++ b/src/doc/rustc-dev-guide/src/traits/implied-bounds.md @@ -3,27 +3,29 @@ 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. +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 -lazy type aliases have explicit implied bounds which are computed via a fixpoint algorithm -in the [`fn inferred_outlives_crate`] query. +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. 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 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 -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]. +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]. [`fn inferred_outlives_of`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/mod.rs#L20 @@ -40,8 +42,9 @@ 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`]. +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 +53,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,12 +70,14 @@ 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 -all used types are well formed by emitting `WellFormed` predicates. +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 -involving higher ranked regions as we're lacking the implied bounds from their binder. +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: - by using subtyping: [#25860]