Eagerly collect mono items for non-generic closures
This allows users to use `-Zprint-mono-items=eager` to eagerly monomorphize closures and coroutine bodies, in case they want to inspect the LLVM or ASM for those items.
`-Zprint-mono-items`, which used to be called `-Zprint-trans-items`, was originally added in https://github.com/rust-lang/rust/pull/30900:
> Eager mode is meant to be used in conjunction with incremental compilation
> where a stable set of translation items is more important than a minimal
> one. Thus, eager mode will instantiate drop-glue for every drop-able type
> in the crate, even of no drop call for that type exists (yet). It will
> also instantiate default implementations of trait methods, something that
> otherwise is only done on demand.
Although it remains an unstable option, its purpose has somewhat expanded since then, and as far as I can tell it's generally useful for cases when you want to monomorphize as many items as possible, even if they're unreachable. Specifically, it's useful for debugging since you can look at the codegen'd body of a function, since we don't emit items that are not reachable in monomorphization.
And even more specifically, it would be very to monomorphize the coroutine body of an async fn, since those you can't easily call those without a runtime. This PR enables this usecase since we now monomorphize `DefKind::Closure`.
Adds `#[rustc_force_inline]` which is similar to always inlining but
reports an error if the inlining was not possible, and which always
attempts to inline annotated items, regardless of optimisation levels.
It can only be applied to free functions to guarantee that the MIR
inliner will be able to resolve calls.
`-Zrandomize-layout` harder. `Foo<T> != Foo<U>`
Tracking issue: #106764
Previously randomize-layout only used a deterministic shuffle based on the seed stored in an Adt's ReprOptions, meaning that `Foo<T>` and `Foo<U>` were shuffled by the same seed. This change adds a similar seed to each calculated LayoutData so that a struct can be randomized both based on the layout of its fields and its per-type seed.
Primitives start with simple seed derived from some of their properties. Though some types can no longer be distinguished at that point, e.g. usize and u64 will still be treated the same.
previously field ordering was using the same seed for all instances of Foo,
now we pass seed values through the layout tree so that not only
the struct itself affects layout but also its fields
Implement `const Destruct` in old solver
Self-explanatory. Not totally settled that this is the best structure for built-in trait impls for effect goals in the new solver, but it's almost certainly the simplest.
r? lcnr or re-roll
Suggest Replacing Comma with Semicolon in Incorrect Repeat Expressions
Fixes#80173
This PR detects typos in repeat expressions like `["_", 10]` and `vec![String::new(), 10]` and suggests replacing comma with semicolon.
Also, improves code in other place by adding doc comments and making use of a helper function to check if a type implements `Clone`.
References:
1. For `vec![T; N]`: https://doc.rust-lang.org/std/macro.vec.html
2. For `[T; N]`: https://doc.rust-lang.org/std/primitive.array.html
Exhaustively handle expressions in patterns
We currently have this invariant in HIR that a `PatKind::Lit` or a `PatKind::Range` only contains
* `ExprKind::Lit`
* `ExprKind::UnOp(Neg, ExprKind::Lit)`
* `ExprKind::Path`
* `ExprKind::ConstBlock`
So I made `PatKind::Lit` and `PatKind::Range` stop containing `Expr`, and instead created a `PatLit` type whose `kind` enum only contains those variants.
The only place code got more complicated was in clippy, as it couldn't share as much anymore with `Expr` handling
It may be interesting on merging `ExprKind::{Path,Lit,ConstBlock}` in the future and using the same `PatLit` type (under a new name).
Then it should also be easier to eliminate any and all `UnOp(Neg, Lit) | Lit` matching that we have across the compiler. Some day we should fold the negation into the literal itself and just store it on the numeric literals
`best_blame_constraint`: Blame better constraints when the region graph has cycles from invariance or `'static`
This fixes#132749 by changing which constraint is blamed for region errors in several cases. `best_blame_constraint` had a heuristic that tried to pinpoint the constraint causing an error by filtering out any constraints where the outliving region is unified with the ultimate target region being outlived. However, it used the SCCs of the region graph to do this, which is unreliable; in particular, if the target region is `'static`, or if there are cycles from the presence of invariant types, it was skipping over the constraints it should be blaming. As is the case in that issue, this could lead to confusing diagnostics. The simplest fix seems to work decently, judging by test stderr: this makes `best_blame_constraint` no longer filter constraints by their outliving region's SCC.
There are admittedly some quirks in the test output. In many cases, subdiagnostics that depend on the particular constraint being blamed have either started or stopped being emitted. After starting at this for quite a while, I think anything too fickle about whether it outputs based on the particular constraint being blamed should instead be looking at the constraint path as a whole, similar to what's done for [the placeholder-from-predicate note](https://github.com/rust-lang/rust/compare/master...dianne:rust:better-blame-constraints-for-static#diff-3c0de6462469af483c9ecdf2c4b00cb26192218ef2d5c62a0fde75107a74caaeR506).
Very many tests involving invariant types gained a note pointing out the types' invariance, but in a few cases it was lost. A particularly illustrative example is [tests/ui/lifetimes/copy_modulo_regions.stderr](https://github.com/rust-lang/rust/compare/master...dianne:rust:better-blame-constraints-for-static?expand=1#diff-96e1f8b29789b3c4ce2f77a5e0fba248829b97ef9d1ce39e7d2b4aa57b2cf4f0); I'd argue the new constraint is a better one to blame, but it lacks the variance diagnostic information that's elsewhere in the constraint path. If desired, I can try making that note check the whole path rather than just the blamed constraint.
The subdiagnostic [`BorrowExplanation::add_object_lifetime_default_note`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/diagnostics/explain_borrow/enum.BorrowExplanation.html#method.add_object_lifetime_default_note) depends on a `Cast` being blamed, so [a special case](364ca7f99c) was necessary to keep it from disappearing from tests specifically testing for it. However, see the FIXME comment in that commit; I think the special case should be removed once that subdiagnostic works properly, but it's nontrivial enough to warrant a separate PR. Incidentally, this removes the note from a test where it was being added erroneously: in [tests/ui/borrowck/two-phase-surprise-no-conflict.stderr](https://github.com/rust-lang/rust/compare/master...dianne:rust:better-blame-constraints-for-static?expand=1#diff-8cf085af8203677de6575a45458c9e6b03412a927df879412adec7e4f7ff5e14), the object lifetime is explicitly provided and it's not `'static`.
Convert typeck constraints in location-sensitive polonius
In this PR, we do a big chunk of the work of localizing regular outlives constraints.
The slightly annoying thing is handling effectful statements: usually the subset graph propagates loans at a single point between regions, and liveness propagates loans between points within a single region, but some statements have effects applied on exit.
This was also a problem before, in datalog polonius terms and Niko's solution at the time, this is about: the mid-point. The idea was to duplicate all MIR locations into two physical points, and orchestrate the effects with that. Somewhat easier to do, but double the CFG.
We've always believed we didn't _need_ midpoints in principle, as we can represent changes on exit as on happening entry to the successor, but there's some difficulty in tracking the position information at sufficient granularity through outlives relation (especially since we also have bidirectional edges and time-traveling now).
Now, that is surely what we should be doing in the future. In the mean time, I infer this from the kind of statement/terminator where an outlives constraint arose. It's not particularly complicated but some explanation will help clarify the code.
Assignments (in their various forms) are the quintessential example of these crossover cases: loans that would flow into the LHS would not be visible on entry to the point but on exit -- so we'll localize these edges to the successor. Let's look at a real-world example, involving invariance for bidirectional edges:
```rust
let mut _1: HashMap<i32, &'7 i32>;
let mut _3: &'9 mut HashMap<i32, &'10 i32>;
...
/* at bb1[3]: */ _3 = &'3 mut _1;
```
Here, typeck expectedly produces 3 outlives constraints today:
1. `'3 -> '9`
2. `'7 -> '10`
3. `'10 -> '7`
And we localize them like so,
1. `'3 -> '9` flows into the LHS and becomes: `3_bb1_3 -> 9_bb1_4`
2. `'7 -> '10` flows into the LHS and becomes: `7_bb1_3 -> 10_bb1_4`
3. `'10 -> '7` flows from the LHS and becomes: `10_bb1_4 -> 7_bb1_3` (time traveling 👌)
---
r? ``@jackh726``
To keep you entertained during the holidays I also threw in a couple of small changes removing cruft in the borrow checker.
We're actually getting there. The next PR will be the last one needed to get end-to-end tests working.
Use a post-monomorphization typing env when mangling components that come from impls
When mangling associated methods of impls, we were previously using the wrong param-env. Instead of using a fully monomorphized param-env like we usually do in codegen, we were taking the post-analysis param-env, and treating it as an early binder to *re-substitute* the impl args. I've pointed out the problematic old code in an inline comment.
This would give us param-envs with possibly trivial predicates that would prevent normalization via param-env shadowing.
In the example test linked below, `tests/ui/symbol-names/normalize-in-param-env.rs`, this happens when we mangle the impl `impl<P: Point2> MyFrom<P::S> for P` with the substitution `P = Vec2`. Because the where clause of the impl is `P: Point2`, which elaborates to `[P: Point2, P: Point, <P as Point>::S projects-to <P as Point2>::S2]` and the fact that `impl Point2 for Vec2` normalizes `Vec2::S2` to `Vec2::S`, this causes a cycle.
The proper fix here is to use a fully monomorphized param-env for the case where the impl is properly substituted.
Fixes#135143
While #134081 uncovered this bug for legacy symbol mangling, it was preexisting for v0 symbol mangling. This PR fixes both. The test requires a "hack" because we strip the args of the instance we're printing for legacy symbol mangling except for drop glue, so we box a closure to ensure we generate drop glue.
r? oli-obk
A few borrowck tweaks to improve 2024 edition migration lints
See first two commits' changes to test outputs. Test coverage in this area is kinda weak, but I think it affects more cases than this (like the craters that will begin to trigger the `tail_expr_drop_order` tests in #134523).
Third commit is a drive-by change that removes a deref hack from `UseSpans` which doesn't really improve diagnostics much.
Add a notion of "some ABIs require certain target features"
I think I finally found the right shape for the data and checks that I recently added in https://github.com/rust-lang/rust/pull/133099, https://github.com/rust-lang/rust/pull/133417, https://github.com/rust-lang/rust/pull/134337: we have a notion of "this ABI requires the following list of target features, and it is incompatible with the following list of target features". Both `-Ctarget-feature` and `#[target_feature]` are updated to ensure we follow the rules of the ABI. This removes all the "toggleability" stuff introduced before, though we do keep the notion of a fully "forbidden" target feature -- this is needed to deal with target features that are actual ABI switches, and hence are needed to even compute the list of required target features.
We always explicitly (un)set all required and in-conflict features, just to avoid potential trouble caused by the default features of whatever the base CPU is. We do this *before* applying `-Ctarget-feature` to maintain backward compatibility; this poses a slight risk of missing some implicit feature dependencies in LLVM but has the advantage of not breaking users that deliberately toggle ABI-relevant target features. They get a warning but the feature does get toggled the way they requested.
For now, our logic supports x86, ARM, and RISC-V (just like the previous logic did). Unsurprisingly, RISC-V is the nicest. ;)
As a side-effect this also (unstably) allows *enabling* `x87` when that is harmless. I used the opportunity to mark SSE2 as required on x86-64, to better match the actual logic in LLVM and because all x86-64 chips do have SSE2. This infrastructure also prepares us for requiring SSE on x86-32 when we want to use that for our ABI (and for float semantics sanity), see https://github.com/rust-lang/rust/issues/133611, but no such change is happening in this PR.
r? `@workingjubilee`
rustc_intrinsic: support functions without body
We synthesize a HIR body `loop {}` but such bodyless intrinsics.
Most of the diff is due to turning `ItemKind::Fn` into a brace (named-field) enum variant, because it carries a `bool`-typed field now. This is to remember whether the function has a body. MIR building panics to avoid ever translating the fake `loop {}` body, and the intrinsic logic uses the lack of a body to implicitly mark that intrinsic as must-be-overridden.
I first tried actually having no body rather than generating the fake body, but there's a *lot* of code that assumes that all function items have HIR and MIR, so this didn't work very well. Then I noticed that even `rustc_intrinsic_must_be_overridden` intrinsics have MIR generated (they are filled with an `Unreachable` terminator) so I guess I am not the first to discover this. ;)
r? `@oli-obk`
Project to `TyKind::Error` when there are unconstrained non-lifetime (ty/const) impl params
It splits the `enforce_impl_params_are_constrained` function into lifetime/non-lifetime, and queryfies the latter. We can then use the result of the latter query (`Result<(), ErrorGuaranteed>`) to intercept projection and constrain the projected type to `TyKind::Error`, which ensures that we leak no ty or const vars to places that don't expect them, like `normalize_erasing_regions`.
The reason we split `enforce_impl_params_are_constrained` into two parts is because we only error for *lifetimes* if the lifetime ends up showing up in any of the associated types of the impl (e.g. we allow `impl<'a> Foo { type Assoc = (); }`). However, in order to compute the `type_of` query for the anonymous associated type of an RPITIT, we need to do trait solving (in `query collect_return_position_impl_trait_in_trait_tys`). That would induce cycles. Luckily, it turns out for lifetimes we don't even care about if they're unconstrained, since they're erased in all contexts that we are trying to fix ICEs. So it's sufficient to keep this check separated out of the query.
I think this is a bit less invasive of an approach compared to #127973. The major difference between this PR and that PR is that we queryify the check instead of merging it into the `explicit_predicates_of` query, and we use the result to taint just projection goals, rather than trait goals too. This doesn't require a lot of new tracking in `ItemCtxt` and `GenericPredicates`, and it also seems to not require any other changes to typeck like that PR did.
Fixes#123141Fixes#125874Fixes#126942Fixes#127804Fixes#130967
r? oli-obk
Improve infer (`_`) suggestions in `const`s and `static`s
Fixes https://github.com/rust-lang/rust/issues/135010.
This PR does a few things to (imo) greatly improve the error message when users write something like `static FOO: [i32; _] = [1, 2, 3]`.
Firstly, it adapts the recovery code for when we encounter `_` in a const/static to work a bit more like `fn foo() -> _`, and removes the somewhat redundant query `diagnostic_only_typeck`.
Secondly, it changes the lowering for `[T; _]` to always lower under the `feature(generic_arg_infer)` logic to `ConstArgKind::Infer`. We still issue the feature error, so it's not doing anything *observable* on the good path, but it does mean that we no longer erroneously interpret `[T; _]`'s array length as a `_` **wildcard expression** (à la destructuring assignment, like `(_, y) = expr`).
Lastly it makes the suggestions verbose and fixes (well, suppresses) a bug with stashing and suggestions.
r? oli-obk
Spruce up the docs of several queries related to the type/trait system and const eval
- Editorial
- Proper rustdoc summary/synopsis line by making use of extra paragraphs: Leads to better rendered output on module pages, in search result lists and overall, too
- Use rustdoc warning blocks for admonitions of the form "do not call / avoid calling this query directly"
- Use intra-doc links of the form ``[`Self::$query`]`` to cross-link queries. Indeed, such links are generally a bit brittle due to the existence of `TyCtxtFeed` which only contains a subset of queries. Therefore the docs of `feedable` queries cannot cross-link to non-`feedable` ones. I'd say it's fine to use intra-doc links despite the potential/unlikely occasional future breakage (if a query with the aforementioned characteristics becomes `feedable`). `Self::` is nicer than `TyCtxt::` (which would be more stable) since it accounts for other contexts like `TyCtxt{Feed,At,Ensure{,WithValue}}`
- Informative
- Generally add, flesh out and correct some doc comments
- Add *Panic* sections (to a few selected queries only). The lists of panics aren't necessarily exhaustive and focus on the more "obvious" or "important" panics.
- Where applicable add a paragraph calling attention to the relevant [`#[rustc_*]` TEST attribute](https://rustc-dev-guide.rust-lang.org/compiler-debugging.html#rustc_-test-attributes)
The one non-doc change (it's internal and not observable):
Be even more defensive in `query constness`'s impl (spiritual follow-up to #134122) (see self review comment).
Fixes#133494.
r\? **any**(compiler-errors, oli-obk)
Begin to implement type system layer of unsafe binders
Mostly TODOs, but there's a lot of match arms that are basically just noops so I wanted to split these out before I put up the MIR lowering/projection part of this logic.
r? oli-obk
Tracking:
- https://github.com/rust-lang/rust/issues/130516