mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
Merge pull request #2846 from rust-lang/tshepang/sembr
sembr some files
This commit is contained in:
@@ -8,13 +8,14 @@ Coherence checking is what detects both of trait impls and inherent impls overla
|
||||
Overlapping trait impls always produce an error,
|
||||
while overlapping inherent impls result in an error only if they have methods with the same name.
|
||||
|
||||
Checking for overlaps is split in two parts. First there's the [overlap check(s)](#overlap-checks),
|
||||
Checking for overlaps is split in two parts.
|
||||
First there's the [overlap check(s)](#overlap-checks),
|
||||
which finds overlaps between traits and inherent implementations that the compiler currently knows about.
|
||||
|
||||
However, Coherence also results in an error if any other impls **could** exist,
|
||||
even if they are currently unknown.
|
||||
even if they are currently unknown.
|
||||
This affects impls which may get added to upstream crates in a backwards compatible way,
|
||||
and impls from downstream crates.
|
||||
and impls from downstream crates.
|
||||
This is called the Orphan check.
|
||||
|
||||
## Overlap checks
|
||||
@@ -25,7 +26,7 @@ Overlap checks always consider pairs of implementations, comparing them to each
|
||||
|
||||
Overlap checking for inherent impl blocks is done through `fn check_item` (in coherence/inherent_impls_overlap.rs),
|
||||
where you can very clearly see that (at least for small `n`), the check really performs `n^2`
|
||||
comparisons between impls.
|
||||
comparisons between impls.
|
||||
|
||||
In the case of traits, this check is currently done as part of building the [specialization graph](traits/specialization.md),
|
||||
to handle specializing impls overlapping with their parent, but this may change in the future.
|
||||
@@ -37,7 +38,7 @@ Overlapping is sometimes partially allowed:
|
||||
1. for marker traits
|
||||
2. under [specialization](traits/specialization.md)
|
||||
|
||||
but normally isn't.
|
||||
It normally isn't.
|
||||
|
||||
The overlap check has various modes (see [`OverlapMode`]).
|
||||
Importantly, there's the explicit negative impl check, and the implicit negative impl check.
|
||||
@@ -47,9 +48,9 @@ Both try to prove that an overlap is definitely impossible.
|
||||
|
||||
### The explicit negative impl check
|
||||
|
||||
This check is done in [`impl_intersection_has_negative_obligation`].
|
||||
This check is done in [`impl_intersection_has_negative_obligation`].
|
||||
|
||||
This check tries to find a negative trait implementation.
|
||||
This check tries to find a negative trait implementation.
|
||||
For example:
|
||||
|
||||
```rust
|
||||
@@ -64,7 +65,7 @@ In this example, we'd get:
|
||||
`MyCustomErrorType: From<&str>` and `MyCustomErrorType: From<?E>`, giving `?E = &str`.
|
||||
|
||||
And thus, these two implementations would overlap.
|
||||
However, libstd provides `&str: !Error`, and therefore guarantees that there
|
||||
However, libstd provides `&str: !Error`, and therefore guarantees that there
|
||||
will never be a positive implementation of `&str: Error`, and thus there is no overlap.
|
||||
|
||||
Note that for this kind of negative impl check, we must have explicit negative implementations provided.
|
||||
@@ -77,13 +78,13 @@ This is not currently stable.
|
||||
This check is done in [`impl_intersection_has_impossible_obligation`],
|
||||
and does not rely on negative trait implementations and is stable.
|
||||
|
||||
Let's say there's a
|
||||
Let's say there's a
|
||||
```rust
|
||||
impl From<MyLocalType> for Box<dyn Error> {} // in your own crate
|
||||
impl<E> From<E> for Box<dyn Error> where E: Error {} // in std
|
||||
```
|
||||
|
||||
This would give: `Box<dyn Error>: From<MyLocalType>`, and `Box<dyn Error>: From<?E>`,
|
||||
This would give: `Box<dyn Error>: From<MyLocalType>`, and `Box<dyn Error>: From<?E>`,
|
||||
giving `?E = MyLocalType`.
|
||||
|
||||
In your crate there's no `MyLocalType: Error`, downstream crates cannot implement `Error` (a remote trait) for `MyLocalType` (a remote type).
|
||||
@@ -91,4 +92,3 @@ Therefore, these two impls do not overlap.
|
||||
Importantly, this works even if there isn't a `impl !Error for MyLocalType`.
|
||||
|
||||
[`impl_intersection_has_impossible_obligation`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_trait_selection/traits/coherence/fn.impl_intersection_has_impossible_obligation.html
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
The AST lowering step converts AST to [HIR](../hir.md).
|
||||
This means many structures are removed if they are irrelevant
|
||||
for type analysis or similar syntax agnostic analyses. Examples
|
||||
of such structures include but are not limited to
|
||||
for type analysis or similar syntax-agnostic analyses.
|
||||
Examples of such structures include but are not limited to
|
||||
|
||||
* Parenthesis
|
||||
* Removed without replacement, the tree structure makes order explicit
|
||||
@@ -19,16 +19,19 @@ The implementation of AST lowering is in the [`rustc_ast_lowering`] crate.
|
||||
The entry point is [`lower_to_hir`], which retrieves the post-expansion AST
|
||||
and resolver data from [`TyCtxt`] and builds the [`hir::Crate`] for the whole crate.
|
||||
|
||||
Lowering is organized around HIR owners. [`lower_to_hir`] first indexes the
|
||||
Lowering is organized around HIR owners.
|
||||
[`lower_to_hir`] first indexes the
|
||||
crate and then [`ItemLowerer::lower_node`] lowers each crate, item, associated
|
||||
item, and foreign item.
|
||||
|
||||
Most of the lowering logic lives on [`LoweringContext`]. The implementation is
|
||||
Most of the lowering logic lives on [`LoweringContext`].
|
||||
The implementation is
|
||||
split across multiple files in the [`rustc_ast_lowering`] crate such as `item.rs`,
|
||||
`expr.rs`, `pat.rs`, `path.rs`, and others, but they all share the same [`LoweringContext`]
|
||||
state and ID‑lowering machinery.
|
||||
|
||||
Each owner is lowered in its own [`with_hir_id_owner`] scope. This is why the
|
||||
Each owner is lowered in its own [`with_hir_id_owner`] scope.
|
||||
This is why the
|
||||
`HirId` invariants below matter: `lower_node_id` maps AST `NodeId`s into the
|
||||
current owner, while `next_id` creates fresh HIR-only nodes introduced during
|
||||
desugaring.
|
||||
@@ -36,20 +39,22 @@ desugaring.
|
||||
Lowering needs to uphold several invariants in order to not trigger the
|
||||
sanity checks in [`compiler/rustc_passes/src/hir_id_validator.rs`][hir_id_validator]:
|
||||
|
||||
1. A `HirId` must be used if created. So if you use the `lower_node_id`,
|
||||
you *must* use the resulting `NodeId` or `HirId` (either is fine, since
|
||||
any `NodeId`s in the `HIR` are checked for existing `HirId`s)
|
||||
1. A `HirId` must be used if created.
|
||||
So, if you use the `lower_node_id`,
|
||||
you *must* use the resulting `NodeId` or `HirId` (either is fine, since
|
||||
any `NodeId`s in the `HIR` are checked for existing `HirId`s).
|
||||
2. Lowering a `HirId` must be done in the scope of the *owning* item.
|
||||
This means you need to use `with_hir_id_owner` if you are creating parts
|
||||
of an item other than the one being currently lowered. This happens for
|
||||
example during the lowering of existential `impl Trait`
|
||||
This means you need to use `with_hir_id_owner` if you are creating parts
|
||||
of an item other than the one being currently lowered.
|
||||
This happens, for example, during the lowering of existential `impl Trait`.
|
||||
3. A `NodeId` that will be placed into a HIR structure must be lowered,
|
||||
even if its `HirId` is unused. Calling
|
||||
`let _ = self.lower_node_id(node_id);` is perfectly legitimate.
|
||||
even if its `HirId` is unused.
|
||||
Calling `let _ = self.lower_node_id(node_id);` is perfectly legitimate.
|
||||
4. If you are creating new nodes that didn't exist in the `AST`, you *must*
|
||||
create new ids for them. This is done by calling the `next_id` method,
|
||||
which produces both a new `NodeId` as well as automatically lowering it
|
||||
for you so you also get the `HirId`.
|
||||
create new ids for them.
|
||||
This is done by calling the `next_id` method,
|
||||
which produces both a new `NodeId` as well as automatically lowering it
|
||||
for you so you also get the `HirId`.
|
||||
|
||||
[`rustc_ast_lowering`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/index.html
|
||||
[`lower_to_hir`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/fn.lower_to_hir.html
|
||||
@@ -62,12 +67,16 @@ sanity checks in [`compiler/rustc_passes/src/hir_id_validator.rs`][hir_id_valida
|
||||
|
||||
If you are creating new `DefId`s, since each `DefId` needs to have a
|
||||
corresponding `NodeId`, it is advisable to add these `NodeId`s to the
|
||||
`AST` so you don't have to generate new ones during lowering. This has
|
||||
`AST` so you don't have to generate new ones during lowering.
|
||||
This has
|
||||
the advantage of creating a way to find the `DefId` of something via its
|
||||
`NodeId`. If lowering needs this `DefId` in multiple places, you can't
|
||||
`NodeId`.
|
||||
If lowering needs this `DefId` in multiple places, you can't
|
||||
generate a new `NodeId` in all those places because you'd also get a new
|
||||
`DefId` then. With a `NodeId` from the `AST` this is not an issue.
|
||||
`DefId` then.
|
||||
With a `NodeId` from the `AST`, this is not an issue.
|
||||
|
||||
Having the `NodeId` also allows the `DefCollector` to generate the `DefId`s
|
||||
instead of lowering having to do it on the fly. Centralizing the `DefId`
|
||||
instead of lowering having to do it on the fly.
|
||||
Centralizing the `DefId`
|
||||
generation in one place makes it easier to refactor and reason about.
|
||||
|
||||
@@ -1,36 +1,42 @@
|
||||
# Name resolution
|
||||
|
||||
In the previous chapters, we saw how the [*Abstract Syntax Tree* (`AST`)][ast]
|
||||
is built with all macros expanded. We saw how doing that requires doing some
|
||||
name resolution to resolve imports and macro names. In this chapter, we show
|
||||
how this is actually done and more.
|
||||
is built with all macros expanded.
|
||||
We saw how doing that requires doing some
|
||||
name resolution to resolve imports and macro names.
|
||||
In this chapter, we show how this is actually done and more.
|
||||
|
||||
[ast]: ./ast-validation.md
|
||||
|
||||
In fact, we don't do full name resolution during macro expansion -- we only
|
||||
resolve imports and macros at that time. This is required to know what to even
|
||||
expand. Later, after we have the whole AST, we do full name resolution to
|
||||
resolve all names in the crate. This happens in [`rustc_resolve::late`][late].
|
||||
resolve imports and macros at that time.
|
||||
This is required to know what to even expand.
|
||||
Later, after we have the whole AST, we do full name resolution to
|
||||
resolve all names in the crate.
|
||||
This happens in [`rustc_resolve::late`][late].
|
||||
Unlike during macro expansion, in this late expansion, we only need to try to
|
||||
resolve a name once, since no new names can be added. If we fail to resolve a
|
||||
name, then it is a compiler error.
|
||||
resolve a name once, since no new names can be added.
|
||||
If we fail to resolve a name, then it is a compiler error.
|
||||
|
||||
Name resolution is complex. There are different namespaces (e.g.
|
||||
macros, values, types, lifetimes), and names may be valid at different (nested)
|
||||
scopes. Also, different types of names can fail resolution differently, and
|
||||
failures can happen differently at different scopes. For example, in a module
|
||||
scope, failure means no unexpanded macros and no unresolved glob imports in
|
||||
that module. On the other hand, in a function body scope, failure requires that a
|
||||
name be absent from the block we are in, all outer scopes, and the global
|
||||
scope.
|
||||
scopes.
|
||||
Also, different types of names can fail resolution differently, and
|
||||
failures can happen differently at different scopes.
|
||||
For example, in a module scope,
|
||||
failure means no unexpanded macros and no unresolved glob imports in
|
||||
that module.
|
||||
On the other hand, in a function body scope, failure requires that a
|
||||
name be absent from the block we are in, all outer scopes, and the global scope.
|
||||
|
||||
[late]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/index.html
|
||||
|
||||
## Basics
|
||||
|
||||
In our programs we refer to variables, types, functions, etc, by giving them
|
||||
a name. These names are not always unique. For example, take this valid Rust
|
||||
program:
|
||||
a name.
|
||||
These names are not always unique.
|
||||
For example, take this valid Rust program:
|
||||
|
||||
```rust
|
||||
type x = u32;
|
||||
@@ -38,20 +44,25 @@ let x: x = 1;
|
||||
let y: x = 2;
|
||||
```
|
||||
|
||||
How do we know on line 3 whether `x` is a type (`u32`) or a value (1)? These
|
||||
conflicts are resolved during name resolution. In this specific case, name
|
||||
resolution defines that type names and variable names live in separate
|
||||
How do we know on line 3 whether `x` is a type (`u32`) or a value (1)?
|
||||
These conflicts are resolved during name resolution.
|
||||
In this specific case,
|
||||
name resolution defines that type names and variable names live in separate
|
||||
namespaces and therefore can co-exist.
|
||||
|
||||
The name resolution in Rust is a two-phase process. In the first phase, which runs
|
||||
during `macro` expansion, we build a tree of modules and resolve imports. Macro
|
||||
expansion and name resolution communicate with each other via the
|
||||
The name resolution in Rust is a two-phase process.
|
||||
In the first phase,
|
||||
which runs during `macro` expansion,
|
||||
we build a tree of modules and resolve imports.
|
||||
Macro expansion and name resolution communicate with each other via the
|
||||
[`ResolverAstLoweringExt`] trait.
|
||||
|
||||
The input to the second phase is the syntax tree, produced by parsing input
|
||||
files and expanding `macros`. This phase produces links from all the names in the
|
||||
source to relevant places where the name was introduced. It also generates
|
||||
helpful error messages, like typo suggestions, traits to import or lints about
|
||||
files and expanding `macros`.
|
||||
This phase produces links from all the names in the
|
||||
source to relevant places where the name was introduced.
|
||||
It also generates helpful error messages,
|
||||
like typo suggestions, traits to import or lints about
|
||||
unused items.
|
||||
|
||||
A successful run of the second phase ([`Resolver::resolve_crate`]) creates kind
|
||||
@@ -68,9 +79,11 @@ The name resolution lives in the [`rustc_resolve`] crate, with the bulk in
|
||||
## Namespaces
|
||||
|
||||
Different kind of symbols live in different namespaces ‒ e.g. types don't
|
||||
clash with variables. This usually doesn't happen, because variables start with
|
||||
clash with variables.
|
||||
This usually doesn't happen, because variables start with
|
||||
lower-case letter while types with upper-case one, but this is only a
|
||||
convention. This is legal Rust code that will compile (with warnings):
|
||||
convention.
|
||||
This is legal Rust code that will compile (with warnings):
|
||||
|
||||
```rust
|
||||
type x = u32;
|
||||
@@ -83,19 +96,21 @@ namespaces, the resolver keeps them separated and builds separate structures for
|
||||
them.
|
||||
|
||||
In other words, when the code talks about namespaces, it doesn't mean the module
|
||||
hierarchy, it's types vs. values vs. macros.
|
||||
hierarchy, it's types versus values versus macros.
|
||||
|
||||
## Scopes and ribs
|
||||
|
||||
A name is visible only in certain area in the source code. This forms a
|
||||
hierarchical structure, but not necessarily a simple one ‒ if one scope is
|
||||
A name is visible only in certain area in the source code.
|
||||
This forms a hierarchical structure,
|
||||
but not necessarily a simple one ‒ if one scope is
|
||||
part of another, it doesn't mean a name visible in the outer scope is also
|
||||
visible in the inner scope, or that it refers to the same thing.
|
||||
|
||||
To cope with that, the compiler introduces the concept of [`Rib`]s. This is
|
||||
an abstraction of a scope. Every time the set of visible names potentially changes,
|
||||
a new [`Rib`] is pushed onto a stack. The places where this can happen include for
|
||||
example:
|
||||
To cope with that, the compiler introduces the concept of [`Rib`]s.
|
||||
This is an abstraction of a scope.
|
||||
Every time the set of visible names potentially changes,
|
||||
a new [`Rib`] is pushed onto a stack.
|
||||
The places where this can happen include for example:
|
||||
|
||||
[`Rib`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.Rib.html
|
||||
|
||||
@@ -106,11 +121,14 @@ example:
|
||||
* Macro expansion border ‒ to cope with macro hygiene.
|
||||
|
||||
When searching for a name, the stack of [`ribs`] is traversed from the innermost
|
||||
outwards. This helps to find the closest meaning of the name (the one not
|
||||
shadowed by anything else). The transition to outer [`Rib`] may also affect
|
||||
outwards.
|
||||
This helps to find the closest meaning of the name (the one not
|
||||
shadowed by anything else).
|
||||
The transition to outer [`Rib`] may also affect
|
||||
what names are usable ‒ if there are nested functions (not closures),
|
||||
the inner one can't access parameters and local bindings of the outer one,
|
||||
even though they should be visible by ordinary scoping rules. An example:
|
||||
even though they should be visible by ordinary scoping rules.
|
||||
An example:
|
||||
|
||||
[`ribs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.LateResolutionVisitor.html#structfield.ribs
|
||||
|
||||
@@ -139,11 +157,13 @@ blocks), which isn't a full namespace in its own right.
|
||||
## Overall strategy
|
||||
|
||||
To perform the name resolution of the whole crate, the syntax tree is traversed
|
||||
top-down and every encountered name is resolved. This works for most kinds of
|
||||
names, because at the point of use of a name it is already introduced in the [`Rib`]
|
||||
top-down and every encountered name is resolved.
|
||||
This works for most kinds of names,
|
||||
because at the point of use of a name it is already introduced in the [`Rib`]
|
||||
hierarchy.
|
||||
|
||||
There are some exceptions to this. Items are bit tricky, because they can be
|
||||
There are some exceptions to this.
|
||||
Items are bit tricky, because they can be
|
||||
used even before encountered ‒ therefore every block needs to be first scanned
|
||||
for items to fill in its [`Rib`].
|
||||
|
||||
@@ -156,14 +176,15 @@ Therefore, the resolution is performed in multiple stages.
|
||||
## Speculative crate loading
|
||||
|
||||
To give useful errors, rustc suggests importing paths into scope if they're
|
||||
not found. How does it do this? It looks through every module of every crate
|
||||
and looks for possible matches. This even includes crates that haven't yet
|
||||
been loaded!
|
||||
not found.
|
||||
How does it do this?
|
||||
It looks through every module of every crate and looks for possible matches.
|
||||
This even includes crates that haven't yet been loaded!
|
||||
|
||||
Eagerly loading crates to include import suggestions that haven't yet been
|
||||
loaded is called _speculative crate loading_, because any errors it encounters
|
||||
shouldn't be reported: [`rustc_resolve`] decided to load them, not the user. The function
|
||||
that does this is [`lookup_import_candidates`] and lives in
|
||||
shouldn't be reported: [`rustc_resolve`] decided to load them, not the user.
|
||||
The function that does this is [`lookup_import_candidates`] and lives in
|
||||
[`rustc_resolve::diagnostics`].
|
||||
|
||||
[`rustc_resolve`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/index.html
|
||||
@@ -176,8 +197,9 @@ the load is speculative.
|
||||
|
||||
## TODO: [#16](https://github.com/rust-lang/rustc-dev-guide/issues/16)
|
||||
|
||||
This is a result of the first pass of learning the code. It is definitely
|
||||
incomplete and not detailed enough. It also might be inaccurate in places.
|
||||
This is a result of the first pass of learning the code.
|
||||
It is definitely incomplete and not detailed enough.
|
||||
It also might be inaccurate in places.
|
||||
Still, it probably provides useful first guidepost to what happens in there.
|
||||
|
||||
* What exactly does it link to and how is that published and consumed by
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
The `rustc_private` feature allows external crates to use compiler internals.
|
||||
|
||||
### Using `rustc_private` with Official Toolchains
|
||||
### Using `rustc_private` with official toolchains
|
||||
|
||||
When using the `rustc_private` feature with official Rust toolchains distributed via rustup, you need to install two additional components:
|
||||
|
||||
1. **`rustc-dev`**: Provides compiler libraries
|
||||
2. **`llvm-tools`**: Provides LLVM libraries required for linking
|
||||
|
||||
#### Installation Steps
|
||||
#### Installation steps
|
||||
|
||||
Install both components using rustup:
|
||||
|
||||
@@ -21,7 +21,7 @@ Install both components using rustup:
|
||||
rustup component add rustc-dev llvm-tools
|
||||
```
|
||||
|
||||
#### Common Error
|
||||
#### Common error
|
||||
|
||||
Without the `llvm-tools` component, you'll encounter linking errors like:
|
||||
|
||||
@@ -40,7 +40,7 @@ For custom-built toolchains or environments not using rustup, additional configu
|
||||
- LLVM libraries must be available in your system's library search paths
|
||||
- The LLVM version must match the one used to build your Rust toolchain
|
||||
|
||||
#### Troubleshooting Steps
|
||||
#### Troubleshooting steps
|
||||
|
||||
1. Verify LLVM is installed and accessible
|
||||
2. Ensure that library paths are set:
|
||||
@@ -53,9 +53,10 @@ For custom-built toolchains or environments not using rustup, additional configu
|
||||
|
||||
When developing out-of-tree projects that use `rustc_private` crates, you can configure `rust-analyzer` to recognize these crates.
|
||||
|
||||
#### Configuration Steps
|
||||
#### Configuration steps
|
||||
|
||||
1. Configure `rust-analyzer.rustc.source` to `"discover"` in your editor settings.
|
||||
|
||||
1. Configure `rust-analyzer.rustc.source` to `"discover"` in your editor settings.
|
||||
For VS Code, add to `rust_analyzer_settings.json`:
|
||||
```json
|
||||
{
|
||||
@@ -69,11 +70,11 @@ When developing out-of-tree projects that use `rustc_private` crates, you can co
|
||||
rustc_private = true
|
||||
```
|
||||
|
||||
This configuration allows `rust-analyzer` to properly recognize and provide IDE support for `rustc_private` crates in out-of-tree projects.
|
||||
This configuration allows `rust-analyzer` to properly recognize and provide IDE support for `rustc_private` crates in out-of-tree projects.
|
||||
|
||||
### Getting Nightly Documentation for `rustc_private`
|
||||
### Getting nightly documentation for `rustc_private`
|
||||
|
||||
#### Latest Nightly
|
||||
#### Latest nightly
|
||||
|
||||
For the latest nightly, you can install the `rustc-docs` component and open it directly in your browser:
|
||||
|
||||
@@ -84,9 +85,11 @@ rustup doc --rustc-docs
|
||||
|
||||
> Note: The `rustc-docs` component is only available for recent nightly toolchains and may not be present for every nightly date. It was first introduced in [PR #75560](https://github.com/rust-lang/rust/pull/75560) (August 2020).
|
||||
|
||||
#### Older Nightlies
|
||||
#### Older nightlies
|
||||
|
||||
If you depend on compiler internals from an older nightly, you may want to refer to the internal documentation from that particular nightly. The only way to do this is to generate the documentation locally. For example, to get documentation for `nightly-2025-11-08`:
|
||||
If you depend on compiler internals from an older nightly, you may want to refer to the internal documentation from that particular nightly.
|
||||
The only way to do this is to generate the documentation locally.
|
||||
For example, to get documentation for `nightly-2025-11-08`:
|
||||
|
||||
Get the Git commit hash for that nightly:
|
||||
|
||||
@@ -95,10 +98,11 @@ rustup toolchain install nightly-2025-11-08
|
||||
rustc +nightly-2025-11-08 --version --verbose
|
||||
```
|
||||
|
||||
The output will include a `commit-hash` line identifying the exact source revision. Check out `rust-lang/rust` at that commit, then follow the steps in [compiler documentation](../building/compiler-documenting.md).
|
||||
The output will include a `commit-hash` line identifying the exact source revision.
|
||||
Check out `rust-lang/rust` at that commit, then follow the steps in [compiler documentation](../building/compiler-documenting.md).
|
||||
|
||||
|
||||
### Additional Resources
|
||||
### Additional resources
|
||||
|
||||
- [GitHub Issue #137421] explains that `rustc_private` linker failures often occur because `llvm-tools` is not installed
|
||||
|
||||
|
||||
@@ -3,45 +3,51 @@
|
||||
This section is about the stability attributes and schemes that allow stable
|
||||
APIs to use unstable APIs internally in the rustc standard library.
|
||||
|
||||
**NOTE**: this section is for *library* features, not *language* features. For instructions on
|
||||
stabilizing a language feature see [Stabilizing Features](./stabilization-guide.md).
|
||||
**NOTE**: this section is for *library* features, not *language* features.
|
||||
For instructions on stabilizing a language feature,
|
||||
see [Stabilizing Features](./stabilization-guide.md).
|
||||
|
||||
## unstable
|
||||
|
||||
The `#[unstable(feature = "foo", issue = "1234", reason = "lorem ipsum")]`
|
||||
attribute explicitly marks an item as unstable. Items that are marked as
|
||||
attribute explicitly marks an item as unstable.
|
||||
Items that are marked as
|
||||
"unstable" cannot be used without a corresponding `#![feature]` attribute on
|
||||
the crate, even on a nightly compiler. This restriction only applies across
|
||||
crate boundaries, unstable items may be used within the crate that defines
|
||||
them.
|
||||
the crate, even on a nightly compiler.
|
||||
This restriction only applies across
|
||||
crate boundaries, unstable items may be used within the crate that defines them.
|
||||
|
||||
The `issue` field specifies the associated GitHub [issue number]. This field is
|
||||
required and all unstable features should have an associated tracking issue. In
|
||||
rare cases where there is no sensible value `issue = "none"` is used.
|
||||
The `issue` field specifies the associated GitHub [issue number].
|
||||
This field is required,
|
||||
and all unstable features should have an associated tracking issue.
|
||||
In rare cases where there is no sensible value, `issue = "none"` is used.
|
||||
|
||||
The `unstable` attribute infects all sub-items, where the attribute doesn't
|
||||
have to be reapplied. So if you apply this to a module, all items in the module
|
||||
will be unstable.
|
||||
have to be reapplied.
|
||||
So, if you apply this to a module, all items in the module will be unstable.
|
||||
|
||||
If you rename a feature, you can add `old_name = "old_name"` to produce a
|
||||
If you rename a feature, you can add `old_name = "old_name"` to produce a
|
||||
useful error message.
|
||||
|
||||
You can make specific sub-items stable by using the `#[stable]` attribute on
|
||||
them. The stability scheme works similarly to how `pub` works. You can have
|
||||
public functions of nonpublic modules and you can have stable functions in
|
||||
unstable modules or vice versa.
|
||||
them.
|
||||
The stability scheme works similarly to how `pub` works.
|
||||
You can have public functions of non-public modules,
|
||||
and you can have stable functions in unstable modules or vice versa.
|
||||
|
||||
Previously, due to a [rustc bug], stable items inside unstable modules were
|
||||
available to stable code in that location.
|
||||
As of <!-- date-check --> September 2024, items with [accidentally stabilized
|
||||
paths] are marked with the `#[rustc_allowed_through_unstable_modules]` attribute
|
||||
to prevent code dependent on those paths from breaking. Do *not* add this attribute
|
||||
to any more items unless that is needed to avoid breaking changes.
|
||||
to prevent code dependent on those paths from breaking.
|
||||
Do *not* add this attribute to any more items,
|
||||
unless that is needed to avoid breaking changes.
|
||||
|
||||
The `unstable` attribute may also have the `soft` value, which makes it a
|
||||
future-incompatible deny-by-default lint instead of a hard error. This is used
|
||||
by the `bench` attribute which was accidentally accepted in the past. This
|
||||
prevents breaking dependencies by leveraging Cargo's lint capping.
|
||||
future-incompatible deny-by-default lint instead of a hard error.
|
||||
This is used
|
||||
by the `bench` attribute which was accidentally accepted in the past.
|
||||
This prevents breaking dependencies by leveraging Cargo's lint capping.
|
||||
|
||||
[issue number]: https://github.com/rust-lang/rust/issues
|
||||
[rustc bug]: https://github.com/rust-lang/rust/issues/15702
|
||||
@@ -49,22 +55,26 @@ prevents breaking dependencies by leveraging Cargo's lint capping.
|
||||
|
||||
## stable
|
||||
The `#[stable(feature = "foo", since = "1.420.69")]` attribute explicitly
|
||||
marks an item as stabilized. Note that stable functions may use unstable things in their body.
|
||||
marks an item as stabilized.
|
||||
Note that stable functions may use unstable things in their body.
|
||||
|
||||
## rustc_const_unstable
|
||||
|
||||
The `#[rustc_const_unstable(feature = "foo", issue = "1234", reason = "lorem
|
||||
ipsum")]` has the same interface as the `unstable` attribute. It is used to mark
|
||||
`const fn` as having their constness be unstable. This is only needed in rare cases:
|
||||
ipsum")]` has the same interface as the `unstable` attribute.
|
||||
It is used to mark `const fn` as having their constness be unstable.
|
||||
This is only needed in rare cases:
|
||||
- If a `const fn` makes use of unstable language features or intrinsics.
|
||||
(The compiler will tell you to add the attribute if you run into this.)
|
||||
- If a `const fn` is `#[stable]` but not yet intended to be const-stable.
|
||||
- To change the feature gate that is required to call a const-unstable intrinsic.
|
||||
|
||||
Const-stability differs from regular stability in that it is *recursive*: a
|
||||
`#[rustc_const_unstable(...)]` function cannot even be indirectly called from stable code. This is
|
||||
`#[rustc_const_unstable(...)]` function cannot even be indirectly called from stable code.
|
||||
This is
|
||||
to avoid accidentally leaking unstable compiler implementation artifacts to stable code or locking
|
||||
us into the accidental quirks of an incomplete implementation. See the rustc_const_stable_indirect
|
||||
us into the accidental quirks of an incomplete implementation.
|
||||
See the rustc_const_stable_indirect
|
||||
and rustc_allow_const_fn_unstable attributes below for how to fine-tune this check.
|
||||
|
||||
## rustc_const_stable
|
||||
@@ -75,7 +85,8 @@ a `const fn` as having its constness be `stable`.
|
||||
## rustc_const_stable_indirect
|
||||
|
||||
The `#[rustc_const_stable_indirect]` attribute can be added to a `#[rustc_const_unstable(...)]`
|
||||
function to make it callable from `#[rustc_const_stable(...)]` functions. This indicates that the
|
||||
function to make it callable from `#[rustc_const_stable(...)]` functions.
|
||||
This indicates that the
|
||||
function is ready for stable in terms of its implementation (i.e., it doesn't use any unstable
|
||||
compiler features); the only reason it is not const-stable yet are API concerns.
|
||||
|
||||
@@ -105,7 +116,8 @@ To stabilize a feature, follow these steps:
|
||||
1. Ask a **@T-libs-api** member to start an FCP on the tracking issue and wait for
|
||||
the FCP to complete (with `disposition-merge`).
|
||||
2. Change `#[unstable(...)]` to `#[stable(since = "CURRENT_RUSTC_VERSION")]`.
|
||||
3. Remove `#![feature(...)]` from any test or doc-test for this API. If the feature is used in the
|
||||
3. Remove `#![feature(...)]` from any test or doc-test for this API.
|
||||
If the feature is used in the
|
||||
compiler or tools, remove it from there as well.
|
||||
4. If this is a `const fn`, add `#[rustc_const_stable(since = "CURRENT_RUSTC_VERSION")]`.
|
||||
Alternatively, if this is not supposed to be const-stabilized yet,
|
||||
@@ -121,14 +133,15 @@ and the associated
|
||||
|
||||
## allow_internal_unstable
|
||||
|
||||
Macros and compiler desugarings expose their bodies to the call
|
||||
site. To work around not being able to use unstable things in the standard
|
||||
Macros and compiler desugarings expose their bodies to the call site.
|
||||
To work around not being able to use unstable things in the standard
|
||||
library's macros, there's the `#[allow_internal_unstable(feature1, feature2)]`
|
||||
attribute that allows the given features to be used in stable macros.
|
||||
|
||||
Note that if a macro is used in const context and generates a call to a
|
||||
`#[rustc_const_unstable(...)]` function, that will *still* be rejected even with
|
||||
`allow_internal_unstable`. Add `#[rustc_const_stable_indirect]` to the function to ensure the macro
|
||||
`allow_internal_unstable`.
|
||||
Add `#[rustc_const_stable_indirect]` to the function to ensure the macro
|
||||
cannot accidentally bypass the recursive const stability checks.
|
||||
|
||||
## rustc_allow_const_fn_unstable
|
||||
@@ -138,14 +151,16 @@ indirectly.
|
||||
|
||||
However, sometimes we do know that a feature will get stabilized, just not when, or there is a
|
||||
stable (but e.g. runtime-slow) workaround, so we could always fall back to some stable version if we
|
||||
scrapped the unstable feature. In those cases, the `[rustc_allow_const_fn_unstable(feature1,
|
||||
scrapped the unstable feature.
|
||||
In those cases, the `[rustc_allow_const_fn_unstable(feature1,
|
||||
feature2)]` attribute can be used to allow some unstable features in the body of a stable (or
|
||||
indirectly stable) `const fn`.
|
||||
|
||||
You also need to take care to uphold the `const fn` invariant that calling it at runtime and
|
||||
compile-time needs to behave the same (see also [this blog post][blog]). This means that you
|
||||
compile-time needs to behave the same (see also [this blog post][blog]).
|
||||
This means that you
|
||||
may not create a `const fn` that e.g. transmutes a memory address to an integer,
|
||||
because the addresses of things are nondeterministic and often unknown at
|
||||
because the addresses of things are non-deterministic and often unknown at
|
||||
compile-time.
|
||||
|
||||
**Always ping @rust-lang/wg-const-eval if you are adding more
|
||||
@@ -159,7 +174,8 @@ Any crate that uses the `stable` or `unstable` attributes must include the
|
||||
## deprecated
|
||||
|
||||
Deprecations in the standard library are nearly identical to deprecations in
|
||||
user code. When `#[deprecated]` is used on an item, it must also have a `stable`
|
||||
user code.
|
||||
When `#[deprecated]` is used on an item, it must also have a `stable`
|
||||
or `unstable `attribute.
|
||||
|
||||
`deprecated` has the following form:
|
||||
@@ -172,20 +188,26 @@ or `unstable `attribute.
|
||||
)]
|
||||
```
|
||||
|
||||
The `suggestion` field is optional. If given, it should be a string that can be
|
||||
used as a machine-applicable suggestion to correct the warning. This is
|
||||
The `suggestion` field is optional.
|
||||
If given, it should be a string that can be
|
||||
used as a machine-applicable suggestion to correct the warning.
|
||||
This is
|
||||
typically used when the identifier is renamed, but no other significant changes
|
||||
are necessary. When the `suggestion` field is used, you need to have
|
||||
are necessary.
|
||||
When the `suggestion` field is used, you need to have
|
||||
`#![feature(deprecated_suggestion)]` at the crate root.
|
||||
|
||||
Another difference from user code is that the `since` field is actually checked
|
||||
against the current version of `rustc`. If `since` is in a future version, then
|
||||
against the current version of `rustc`.
|
||||
If `since` is in a future version, then
|
||||
the `deprecated_in_future` lint is triggered which is default `allow`, but most
|
||||
of the standard library raises it to a warning with
|
||||
`#![warn(deprecated_in_future)]`.
|
||||
|
||||
## unstable_feature_bound
|
||||
The `#[unstable_feature_bound(foo)]` attribute can be used together with `#[unstable]` attribute to mark an `impl` of stable type and stable trait as unstable. In std/core, an item annotated with `#[unstable_feature_bound(foo)]` can only be used by another item that is also annotated with `#[unstable_feature_bound(foo)]`. Outside of std/core, using an item with `#[unstable_feature_bound(foo)]` requires the feature to be enabled with `#![feature(foo)]` attribute on the crate.
|
||||
The `#[unstable_feature_bound(foo)]` attribute can be used together with `#[unstable]` attribute to mark an `impl` of stable type and stable trait as unstable.
|
||||
In std/core, an item annotated with `#[unstable_feature_bound(foo)]` can only be used by another item that is also annotated with `#[unstable_feature_bound(foo)]`.
|
||||
Outside of std/core, using an item with `#[unstable_feature_bound(foo)]` requires the feature to be enabled with `#![feature(foo)]` attribute on the crate.
|
||||
|
||||
Currently, the items that can be annotated with `#[unstable_feature_bound]` are:
|
||||
- `impl`
|
||||
@@ -193,7 +215,8 @@ Currently, the items that can be annotated with `#[unstable_feature_bound]` are:
|
||||
- trait
|
||||
|
||||
## 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.
|
||||
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")`
|
||||
attribute should be used to produce a good error message for users of the removed feature.
|
||||
|
||||
|
||||
@@ -462,8 +462,8 @@ These are some useful panels from the dashboard:
|
||||
|
||||
- Pipeline duration: check how long the auto builds take to run.
|
||||
- Top slowest jobs: check which jobs are taking the longest to run.
|
||||
- Change in median job duration: check what jobs are slowest than before. Useful
|
||||
to detect regressions.
|
||||
- Change in median job duration: check what jobs are slowest than before.
|
||||
This is useful for detecting regressions.
|
||||
- Top failed jobs: check which jobs are failing the most.
|
||||
|
||||
To learn more about the dashboard, see the [Datadog CI docs].
|
||||
|
||||
@@ -458,7 +458,8 @@ as they must be compilable by a stage 0 rustc that may be a beta or even stable
|
||||
|
||||
By default, run-make tests print each subprocess command and its stdout/stderr.
|
||||
When running with `--no-capture` on `panic=abort` test suites (such as `cg_clif`),
|
||||
this can flood the terminal. Omit `--verbose-run-make-subprocess-output` to
|
||||
this can flood the terminal.
|
||||
Omit `--verbose-run-make-subprocess-output` to
|
||||
suppress this output for passing tests — failing tests always print regardless:
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user