Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rustc dev guide subtree update #138485

Merged
merged 34 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
78e0d10
Rewrite effects checking chapter
fee1-dead Feb 20, 2025
243f569
Don't suggest explicitly `cfg`-gating `trace!` calls in bootstrap
moxian Mar 5, 2025
515be00
Merge pull request #2269 from moxian/patch-1
jieyouxu Mar 6, 2025
41f95b0
consider `explicit_implied_const_bounds`
fee1-dead Mar 8, 2025
24f3812
numbers were not sequential, so stop trying
tshepang Mar 8, 2025
93a8c7e
only a few are needed as examples
tshepang Mar 8, 2025
ce2eef3
link to latest major llvm update pr
tshepang Mar 8, 2025
2391f10
fix text
tshepang Mar 8, 2025
f1a0665
ignore-stage0 and only-stage0 do not exist
tshepang Mar 8, 2025
d9c920b
Merge pull request #2272 from rust-lang/tshepang-patch-2
jieyouxu Mar 9, 2025
fc7ad74
Merge pull request #2271 from rust-lang/tshepang-patch-1
jieyouxu Mar 9, 2025
7f83057
Merge pull request #2270 from tshepang/example-llvm-prs
jieyouxu Mar 9, 2025
d51c922
use new terminology
tshepang Mar 10, 2025
7751672
already mentioned before showing code snippet
tshepang Mar 10, 2025
7384623
Merge pull request #2274 from rust-lang/tshepang-patch-2
tshepang Mar 10, 2025
f2e7735
add a pause, for readability
tshepang Mar 10, 2025
e9088e4
Merge pull request #2275 from rust-lang/tshepang-patch-2
tshepang Mar 10, 2025
7c6d6e3
clean --bless text
tshepang Mar 10, 2025
225e571
Merge pull request #2276 from rust-lang/tshepang-patch-2
tshepang Mar 10, 2025
4b2c077
add missing punctuation
tshepang Mar 10, 2025
4cc14ce
Merge pull request #2277 from rust-lang/tshepang-patch-2
tshepang Mar 10, 2025
e405878
Merge pull request #2273 from rust-lang/tshepang-patch-1
jieyouxu Mar 10, 2025
240a6d3
Merge pull request #2258 from fee1-dead-contrib/constck
oli-obk Mar 10, 2025
26176b0
less text for same effect
tshepang Mar 13, 2025
d0a3160
Merge pull request #2281 from rust-lang/tshepang-patch-1
tshepang Mar 13, 2025
d4c5e75
Preparing for merge from rustc
jieyouxu Mar 13, 2025
7bde176
Merge from rustc
jieyouxu Mar 13, 2025
440d336
Document `fetch.prunetags = true` gotcha during rustc-pull
jieyouxu Mar 13, 2025
ed29ebb
Merge pull request #2282 from jieyouxu/fetch-prunetags
Kobzol Mar 13, 2025
190187b
Remove the doc for `no-system-llvm`
cuviper Mar 13, 2025
27d71f0
Merge pull request #2284 from rust-lang/cuviper-patch-1
jieyouxu Mar 13, 2025
88aaf1d
Fix grammar and remove redundant info
KonaeAkira Mar 13, 2025
a863f2c
Merge pull request #2285 from KonaeAkira/master
tshepang Mar 14, 2025
3d9bf08
Merge pull request #2283 from jieyouxu/sync
jieyouxu Mar 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/doc/rustc-dev-guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ cargo +stable install josh-proxy --git https://github.com/josh-project/josh --ta
Older versions of `josh-proxy` may not round trip commits losslessly so it is important to install this exact version.

### Pull changes from `rust-lang/rust` into this repository

1) Checkout a new branch that will be used to create a PR into `rust-lang/rustc-dev-guide`
2) Run the pull command
```
Expand All @@ -95,3 +96,15 @@ Older versions of `josh-proxy` may not round trip commits losslessly so it is im
$ cargo run --manifest-path josh-sync/Cargo.toml rustc-push <branch-name> <gh-username>
```
2) Create a PR from `<branch-name>` into `rust-lang/rust`

#### Minimal git config

For simplicity (ease of implementation purposes), the josh-sync script simply calls out to system git. This means that the git invocation may be influenced by global (or local) git configuration.

You may observe "Nothing to pull" even if you *know* rustc-pull has something to pull if your global git config sets `fetch.prunetags = true` (and possibly other configurations may cause unexpected outcomes).

To minimize the likelihood of this happening, you may wish to keep a separate *minimal* git config that *only* has `[user]` entries from global git config, then repoint system git to use the minimal git config instead. E.g.

```
$ GIT_CONFIG_GLOBAL=/path/to/minimal/gitconfig GIT_CONFIG_SYSTEM='' cargo +stable run --manifest-path josh-sync/Cargo.toml -- rustc-pull
```
2 changes: 1 addition & 1 deletion src/doc/rustc-dev-guide/rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4ecd70ddd1039a3954056c1071e40278048476fa
8536f201ffdb2c24925d7f9e87996d7dca93428b
2 changes: 1 addition & 1 deletion src/doc/rustc-dev-guide/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@
- [Inference details](./opaque-types-impl-trait-inference.md)
- [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md)
- [Region inference restrictions][opaque-infer]
- [Effect checking](./effects.md)
- [Const condition checking](./effects.md)
- [Pattern and Exhaustiveness Checking](./pat-exhaustive-checking.md)
- [Unsafety Checking](./unsafety-checking.md)
- [MIR dataflow](./mir/dataflow.md)
Expand Down
23 changes: 9 additions & 14 deletions src/doc/rustc-dev-guide/src/backend/updating-llvm.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,14 @@ so let's go through each in detail.
at the time of the branch,
and the remaining part is the current date.

2. Apply Rust-specific patches to the llvm-project repository.
1. Apply Rust-specific patches to the llvm-project repository.
All features and bugfixes are upstream,
but there's often some weird build-related patches
that don't make sense to upstream.
These patches are typically the latest patches in the
rust-lang/llvm-project branch that rustc is currently using.

3. Build the new LLVM in the `rust` repository.
1. Build the new LLVM in the `rust` repository.
To do this,
you'll want to update the `src/llvm-project` repository to your branch,
and the revision you've created.
Expand Down Expand Up @@ -151,7 +151,7 @@ so let's go through each in detail.
download-ci-llvm = false
```

4. Test for regressions across other platforms. LLVM often has at least one bug
1. Test for regressions across other platforms. LLVM often has at least one bug
for non-tier-1 architectures, so it's good to do some more testing before
sending this to bors! If you're low on resources you can send the PR as-is
now to bors, though, and it'll get tested anyway.
Expand All @@ -170,22 +170,17 @@ so let's go through each in detail.
* `./src/ci/docker/run.sh dist-various-2`
* `./src/ci/docker/run.sh armhf-gnu`

5. Prepare a PR to `rust-lang/rust`. Work with maintainers of
1. Prepare a PR to `rust-lang/rust`. Work with maintainers of
`rust-lang/llvm-project` to get your commit in a branch of that repository,
and then you can send a PR to `rust-lang/rust`. You'll change at least
`src/llvm-project` and will likely also change [`llvm-wrapper`] as well.

<!-- date-check: Sep 2024 -->
<!-- date-check: mar 2025 -->
> For prior art, here are some previous LLVM updates:
> - [LLVM 11](https://github.com/rust-lang/rust/pull/73526)
> - [LLVM 12](https://github.com/rust-lang/rust/pull/81451)
> - [LLVM 13](https://github.com/rust-lang/rust/pull/87570)
> - [LLVM 14](https://github.com/rust-lang/rust/pull/93577)
> - [LLVM 15](https://github.com/rust-lang/rust/pull/99464)
> - [LLVM 16](https://github.com/rust-lang/rust/pull/109474)
> - [LLVM 17](https://github.com/rust-lang/rust/pull/115959)
> - [LLVM 18](https://github.com/rust-lang/rust/pull/120055)
> - [LLVM 19](https://github.com/rust-lang/rust/pull/127513)
> - [LLVM 20](https://github.com/rust-lang/rust/pull/135763)

Note that sometimes it's easiest to land [`llvm-wrapper`] compatibility as a PR
before actually updating `src/llvm-project`.
Expand All @@ -194,17 +189,17 @@ so let's go through each in detail.
others interested in trying out the new LLVM can benefit from work you've done
to update the C++ bindings.

3. Over the next few months,
1. Over the next few months,
LLVM will continually push commits to its `release/a.b` branch.
We will often want to have those bug fixes as well.
The merge process for that is to use `git merge` itself to merge LLVM's
`release/a.b` branch with the branch created in step 2.
This is typically
done multiple times when necessary while LLVM's release branch is baking.

4. LLVM then announces the release of version `a.b`.
1. LLVM then announces the release of version `a.b`.

5. After LLVM's official release,
1. After LLVM's official release,
we follow the process of creating a new branch on the
rust-lang/llvm-project repository again,
this time with a new date.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ Both `tracing::*` macros and the `tracing::instrument` proc-macro attribute need

```rs
#[cfg(feature = "tracing")]
use tracing::{instrument, trace};
use tracing::instrument;

struct Foo;

Expand All @@ -138,7 +138,6 @@ impl Step for Foo {

#[cfg_attr(feature = "tracing", instrument(level = "trace", name = "Foo::should_run", skip_all))]
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
#[cfg(feature = "tracing")]
trace!(?run, "entered Foo::should_run");

todo!()
Expand All @@ -154,7 +153,6 @@ impl Step for Foo {
),
)]
fn run(self, builder: &Builder<'_>) -> Self::Output {
#[cfg(feature = "tracing")]
trace!(?run, "entered Foo::run");

todo!()
Expand Down
5 changes: 2 additions & 3 deletions src/doc/rustc-dev-guide/src/building/new-target.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ These are a set of steps to add support for a new target. There are
numerous end states and paths to get there, so not all sections may be
relevant to your desired goal.

See also the associated documentation in the
[target tier policy][target_tier_policy_add].
See also the associated documentation in the [target tier policy].

<!-- toc -->

[target_tier_policy_add]: https://doc.rust-lang.org/rustc/target-tier-policy.html#adding-a-new-target
[target tier policy]: https://doc.rust-lang.org/rustc/target-tier-policy.html#adding-a-new-target

## Specifying a new LLVM

Expand Down
225 changes: 159 additions & 66 deletions src/doc/rustc-dev-guide/src/effects.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,159 @@
# Effects and effect checking

Note: all of this describes the implementation of the unstable `effects` and
`const_trait_impl` features. None of this implementation is usable or visible from
stable Rust.

The implementation of const traits and `~const` bounds is a limited effect system.
It is used to allow trait bounds on `const fn` to be used within the `const fn` for
method calls. Within the function, in order to know whether a method on a trait
bound is `const`, we need to know whether there is a `~const` bound for the trait.
In order to know whether we can instantiate a `~const` bound on a `const fn`, we
need to know whether there is a `const_trait` impl for the type and trait being
used (or whether the `const fn` is used at runtime, then any type implementing the
trait is ok, just like with other bounds).

We perform these checks via a const generic boolean that gets attached to all
`const fn` and `const trait`. The following sections will explain the desugarings
and the way we perform the checks at call sites.

The const generic boolean is inverted to the meaning of `const`. In the compiler
it is called `host`, because it enables "host APIs" like `static` items, network
access, disk access, random numbers and everything else that isn't available in
`const` contexts. So `false` means "const", `true` means "not const" and if it's
a generic parameter, it means "maybe const" (meaning we're in a const fn or const
trait).

## `const fn`

All `const fn` have a `#[rustc_host] const host: bool` generic parameter that is
hidden from users. Any `~const Trait` bounds in the generics list or `where` bounds
of a `const fn` get converted to `Trait<host> + Trait<true>` bounds. The `Trait<true>`
exists so that associated types of the generic param can be used from projections
like `<T as Trait>::Assoc`, because there are no `<T as ~const Trait>` projections for now.

## `#[const_trait] trait`s

The `#[const_trait]` attribute gives the marked trait a `#[rustc_host] const host: bool`
generic parameter. All functions of the trait "inherit" this generic parameter, just like
they have all the regular generic parameters of the trait. Any `~const Trait` super-trait
bounds get desugared to `Trait<host> + Trait<true>` in order to allow using associated
types and consts of the super traits in the trait declaration. This is necessary, because
`<Self as SuperTrait>::Assoc` is always `<Self as SuperTrait<true>>::Assoc` as there is
no `<Self as ~const SuperTrait>` syntax.

## `typeck` performing method and function call checks.

When generic parameters are instantiated for any items, the `host` generic parameter
is always instantiated as an inference variable. This is a special kind of inference var
that is not part of the type or const inference variables, similar to how we have
special inference variables for type variables that we know to be an integer, but not
yet which one. These separate inference variables fall back to `true` at
the end of typeck (in `fallback_effects`) to ensure that `let _ = some_fn_item_name;`
will keep compiling.

All actually used (in function calls, casts, or anywhere else) function items, will
have the `enforce_context_effects` method invoked.
It trivially returns if the function being called has no `host` generic parameter.

In order to error if a non-const function is called in a const context, we have not
yet disabled the const-check logic that happens on MIR, because
`enforce_context_effects` does not yet perform this check.

The function call's `host` parameter is then equated to the context's `host` value,
which almost always trivially succeeds, as it was an inference var. If the inference
var has already been bound (since the function item is invoked twice), the second
invocation checks it against the first.
# Effects and const condition checking

## The `HostEffect` predicate

[`HostEffectPredicate`]s are a kind of predicate from `~const Tr` or `const Tr`
bounds. It has a trait reference, and a `constness` which could be `Maybe` or
`Const` depending on the bound. Because `~const Tr`, or rather `Maybe` bounds
apply differently based on whichever contexts they are in, they have different
behavior than normal bounds. Where normal trait bounds on a function such as
`T: Tr` are collected within the [`predicates_of`] query to be proven when a
function is called and to be assumed within the function, bounds such as
`T: ~const Tr` will behave as a normal trait bound and add `T: Tr` to the result
from `predicates_of`, but also adds a `HostEffectPredicate` to the
[`const_conditions`] query.

On the other hand, `T: const Tr` bounds do not change meaning across contexts,
therefore they will result in `HostEffect(T: Tr, const)` being added to
`predicates_of`, and not `const_conditions`.

[`HostEffectPredicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/predicate/struct.HostEffectPredicate.html
[`predicates_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.predicates_of
[`const_conditions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.const_conditions

## The `const_conditions` query

`predicates_of` represents a set of predicates that need to be proven to use an
item. For example, to use `foo` in the example below:

```rust
fn foo<T>() where T: Default {}
```

We must be able to prove that `T` implements `Default`. In a similar vein,
`const_conditions` represents a set of predicates that need to be proven to use
an item *in const contexts*. If we adjust the example above to use `const` trait
bounds:

```rust
const fn foo<T>() where T: ~const Default {}
```

Then `foo` would get a `HostEffect(T: Default, maybe)` in the `const_conditions`
query, suggesting that in order to call `foo` from const contexts, one must
prove that `T` has a const implementation of `Default`.

## Enforcement of `const_conditions`

`const_conditions` are currently checked in various places.

Every call in HIR from a const context (which includes `const fn` and `const`
items) will check that `const_conditions` of the function we are calling hold.
This is done in [`FnCtxt::enforce_context_effects`]. Note that we don't check
if the function is only referred to but not called, as the following code needs
to compile:

```rust
const fn hi<T: ~const Default>() -> T {
T::default()
}
const X: fn() -> u32 = hi::<u32>;
```

For a trait `impl` to be well-formed, we must be able to prove the
`const_conditions` of the trait from the `impl`'s environment. This is checked
in [`wfcheck::check_impl`].

Here's an example:

```rust
#[const_trait]
trait Bar {}
#[const_trait]
trait Foo: ~const Bar {}
// `const_conditions` contains `HostEffect(Self: Bar, maybe)`

impl const Bar for () {}
impl const Foo for () {}
// ^ here we check `const_conditions` for the impl to be well-formed
```

Methods of trait impls must not have stricter bounds than the method of the
trait that they are implementing. To check that the methods are compatible, a
hybrid environment is constructed with the predicates of the `impl` plus the
predicates of the trait method, and we attempt to prove the predicates of the
impl method. We do the same for `const_conditions`:

```rust
#[const_trait]
trait Foo {
fn hi<T: ~const Default>();
}

impl<T: ~const Clone> Foo for Vec<T> {
fn hi<T: ~const PartialEq>();
// ^ we can't prove `T: ~const PartialEq` given `T: ~const Clone` and
// `T: ~const Default`, therefore we know that the method on the impl
// is stricter than the method on the trait.
}
```

These checks are done in [`compare_method_predicate_entailment`]. A similar
function that does the same check for associated types is called
[`compare_type_predicate_entailment`]. Both of these need to consider
`const_conditions` when in const contexts.

In MIR, as part of const checking, `const_conditions` of items that are called
are revalidated again in [`Checker::revalidate_conditional_constness`].

[`compare_method_predicate_entailment`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_method_predicate_entailment.html
[`compare_type_predicate_entailment`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_type_predicate_entailment.html
[`FnCtxt::enforce_context_effects`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#method.enforce_context_effects
[`wfcheck::check_impl`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/wfcheck/fn.check_impl.html
[`Checker::revalidate_conditional_constness`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_const_eval/check_consts/check/struct.Checker.html#method.revalidate_conditional_constness

## `explicit_implied_const_bounds` on associated types and traits

Bounds on associated types, opaque types, and supertraits such as
```rust
trait Foo: ~const PartialEq {
type X: ~const PartialEq;
}

fn foo() -> impl ~const PartialEq {
// ^ unimplemented syntax
}
```

Have their bounds represented differently. Unlike `const_conditions` which need
to be proved for callers, and can be assumed inside the definition (e.g. trait
bounds on functions), these bounds need to be proved at definition (at the impl,
or when returning the opaque) but can be assumed for callers. The non-const
equivalent of these bounds are called [`explicit_item_bounds`].

These bounds are checked in [`compare_impl_item::check_type_bounds`] for HIR
typeck, [`evaluate_host_effect_from_item_bounds`] in the old solver and
[`consider_additional_alias_assumptions`] in the new solver.

[`explicit_item_bounds`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.explicit_item_bounds
[`compare_impl_item::check_type_bounds`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.check_type_bounds.html
[`evaluate_host_effect_from_item_bounds`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/effects/fn.evaluate_host_effect_from_item_bounds.html
[`consider_additional_alias_assumptions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_next_trait_solver/solve/assembly/trait.GoalKind.html#tymethod.consider_additional_alias_assumptions

## Proving `HostEffectPredicate`s

`HostEffectPredicate`s are implemented both in the [old solver] and the [new
trait solver]. In general, we can prove a `HostEffect` predicate when either of
these conditions are met:

* The predicate can be assumed from caller bounds;
* The type has a `const` `impl` for the trait, *and* that const conditions on
the impl holds, *and* that the `explicit_implied_const_bounds` on the trait
holds; or
* The type has a built-in implementation for the trait in const contexts. For
example, `Fn` may be implemented by function items if their const conditions
are satisfied, or `Destruct` is implemented in const contexts if the type can
be dropped at compile time.

[old solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_trait_selection/traits/effects.rs.html
[new trait solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_next_trait_solver/solve/effect_goals.rs.html
3 changes: 1 addition & 2 deletions src/doc/rustc-dev-guide/src/solve/trait-solving.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

This chapter describes how trait solving works with the new WIP solver located in
[`rustc_trait_selection/solve`][solve]. Feel free to also look at the docs for
[the current solver](../traits/resolution.md) and [the chalk solver](../traits/chalk.md)
can be found separately.
[the current solver](../traits/resolution.md) and [the chalk solver](../traits/chalk.md).

## Core concepts

Expand Down
Loading
Loading