Skip to content

Rustc pull update#22563

Merged
lnicola merged 39 commits into
masterfrom
rustc-pull
Jun 11, 2026
Merged

Rustc pull update#22563
lnicola merged 39 commits into
masterfrom
rustc-pull

Conversation

@workflows-rust-analyzer

Copy link
Copy Markdown
Contributor

Latest update from rustc.

bors and others added 30 commits June 8, 2026 06:23
…d-for-pattern, r=Mark-Simulacrum

perf: use `get_unchecked` for `TwoWaySearcher`



## What is this PR?

*This is related to rust-lang/rust#27721.*

This PR is a proposal for a performance improvement in `std::pattern`.  

Profiling of [https://github.com/quickwit-oss/quickwit](https://github.com/quickwit-oss/quickwit) in production shows that `TwoWaySearcher::next` is one of the most CPU-time-consuming functions, so I thought I would give it a look.  
I read the [contribution guide](https://std-dev-guide.rust-lang.org/development/perf-benchmarking.html) and this seems to be a fitting proposal.

It seems like `TwoWaySearcher::next` and `TwoWaySearcher::next_back` could be made faster by using `get_unchecked` in the inner loop comparisons instead of regular indexing, which is safe in the conditions where it would be done (indices are within bounds by construction).  
I added some `SAFETY` comments in the code to explain why this is safe, as I believe is customary in those cases (and according to [this page as well](https://std-dev-guide.rust-lang.org/policy/safety-comments.html)).

### Benchmarks

I ran the existing bencharmks before/after the changes (only on my laptop, I can run them in other places if that's necessary). 

```
./x.py bench library/coretests -- pattern::
```

We seem to be getting a ~7.5-12% performance improvement at a very low cost, which sounds worthwhile to me.  
But this is the first time I'm proposing a change in Rust, so I'm looking forward to feedback on this.

```
BEFORE CHANGES
    pattern::ends_with_char   3398.91ns/iter +/- 526.28
    pattern::ends_with_str    3545.04ns/iter +/- 1108.76
    pattern::starts_with_char 3348.31ns/iter +/- 352.38
    pattern::starts_with_str  3710.59ns/iter +/- 435.57

AFTER CHANGES
    pattern::ends_with_char   3125.99ns/iter +/- 567.09  (-8.03%)
    pattern::ends_with_str    3106.43ns/iter +/- 258.33  (-12.38%)
    pattern::starts_with_char 3094.55ns/iter +/- 595.42  (-7.59%)
    pattern::starts_with_str  3365.75ns/iter +/- 268.88  (-9.29%)
```

System info for the benchmarks run

<details>

```
Based on commit 8317fef20409adedaa7c385fa6e954867bf626fc

rustc 1.96.0-dev
binary: rustc
commit-hash: unknown
commit-date: unknown
host: aarch64-apple-darwin
release: 1.96.0-dev
LLVM version: 22.1.2

Apple M4 Max
16
64 GB
ProductName:		macOS
ProductVersion:		26.3
BuildVersion:		25D125
(this was run on AC and without any heavy load from other apps or whatnot)
```

</details>
`rust-analyzer` subtree update

Subtree update of `rust-analyzer` to 57116fa.

Created using https://github.com/rust-lang/josh-sync.

r? @ghost
Use alternate means of detecting enums in `is_udt`

This fixes a small regression from rust-lang/rust#155336

Flat enums are excluded from `is_udt` since LLDB natively handles them correctly. The previous logic (`SBType.IsScopedEnumerationType()`) behaved correctly for non-msvc targets, but for some reason on msvc enums don't count as scoped enumerations?

The new logic checks the type returned by `SBType.GetEnumerationIntegerType()`. If the queried type isn't an enum, the returned type is invalid. This behaves correctly on both msvc and non-msvc targets, and its behavior doesn't conflict with sum-type enums.

As always, testing on msvc isn't really possible atm. That should change soon though =)

---

try-job: aarch64-apple
…henkov

Staticlib hide internal symbols

According to issue rust-lang/rust#104707, when building a staticlib, all Rust internal symbols — mangled symbols, `#[rustc_std_internal_symbol]` items, allocator shims, etc. — leak out of the static archive. In contrast, cdylib correctly exports only `#[no_mangle]` symbols via a linker version script.

`-Zstaticlib-hide-internal-symbols` directly post-processes ELF object files in the archive: parsing the `SHT_SYMTAB` sections and setting `STV_HIDDEN` visibility on any `GLOBAL/WEAK` defined symbol that is not in the exported symbol set, without changing the binding. This is an in-place modification (only writing the st_other byte per matching entry), with zero overhead.

Supported on ELF targets (Linux, BSD, etc.) and Apple targets (macOS, iOS, etc.). On unsupported targets (Windows), a warning is emitted and the flag has no effect.

**Update**: The rename counterpart (`-Zstaticlib-rename-internal-symbols`) is in rust-lang/rust#156950.

The test code are as follows:

1.a std rust staticlib:
```rust
use std::collections::HashMap;
use std::panic::{catch_unwind, AssertUnwindSafe};

#[no_mangle]
pub extern "C" fn my_add(a: i32, b: i32) -> i32 { a + b }

#[no_mangle]
pub extern "C" fn my_hash_lookup(key: u64) -> u64 {
    let mut map = HashMap::new();
    for i in 0..100u64 { map.insert(i, i.wrapping_mul(2654435761)); }
    *map.get(&key).unwrap_or(&0)
}

pub fn internal_reverse(s: &str) -> String { s.chars().rev().collect() }

#[no_mangle]
pub extern "C" fn my_format_number(n: i32) -> i32 {
    let s = format!("number: {}", n); s.len() as i32
}

#[no_mangle]
pub extern "C" fn my_safe_div(a: i32, b: i32) -> i32 {
    match catch_unwind(AssertUnwindSafe(|| {
        if b == 0 { panic!("division by zero!"); }
        a / b
    })) {
        Ok(result) => result,
        Err(_) => -1,
    }
}

#[no_mangle]
pub extern "C" fn my_uncaught_panic() { panic!("uncaught panic across FFI"); }
```

1.b downstream c program:
```c
extern int my_add(int a, int b);
extern unsigned long my_hash_lookup(unsigned long key);
extern int my_format_number(int n);
extern int my_safe_div(int a, int b);
extern void my_uncaught_panic(void);

int main() {
    int failures = 0;
    if (my_add(10, 20) != 30) failures++;
    if (my_hash_lookup(5) != 5UL * 2654435761UL) failures++;
    if (my_format_number(42) != 10) failures++;
    if (my_safe_div(100, 5) != 20) failures++;
    if (my_safe_div(100, 0) != -1) failures++;
    pid_t pid = fork();
    if (pid == 0) { alarm(5); my_uncaught_panic(); _exit(0); }
    else { waitpid(pid, &status, 0); }
    return failures;
}
```

The test results with different compiler flags(which might cause binary size reduction) are as follows:
1.c result with `-Zstaticlib-hide-internal-symbols`
```
  settings                   OFF        ON  -Zsave     ALL    OFF.dynsym ON.dynsym
  ------------------------------------------------------------------------
  default                 1.7M      1.5M  204K (12%)    1735       5    1730
  lto_thin                616K      584K  33K (5%)     246       5     241
  lto_fat                 525K      525K    0 (0%)       6       5       1
  opt_s                   1.7M      1.5M  204K (12%)    1735       5    1730
  opt_z                   1.7M      1.5M  204K (12%)    1735       5    1730
  lto_thin_z              602K      570K  32K (5%)     246       5     241
  lto_fat_z               514K      514K    0 (0%)       6       5       1
  full                    514K      514K    0 (0%)       6       5       1
```

1.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols`
```
  settings                   OFF        ON  -Zsave     ALL    OFF.dynsym ON.dynsym
  ------------------------------------------------------------------------
  default                 1.7M      1.5M  162K (9%)    1735       5    1730
  lto_thin                616K      599K  18K (2%)     246       5     241
  lto_fat                 525K      535K  -1% (-1%)       6       5       1
  opt_s                   1.7M      1.5M  162K (9%)    1735       5    1730
  opt_z                   1.7M      1.5M  162K (9%)    1735       5    1730
  lto_thin_z              602K      585K  18K (2%)     246       5     241
  lto_fat_z               514K      524K  -1% (-1%)       6       5       1
  full                    514K      523K  -1% (-1%)       6       5       1
```

2.a no_std rust staticlib
```rust
#![no_std]
#![feature(core_intrinsics)]

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! { loop {} }

#[no_mangle]
pub extern "C" fn embedded_add(a: i32, b: i32) -> i32 { a.wrapping_add(b) }

#[no_mangle]
pub extern "C" fn embedded_checksum(data: *const u8, len: usize) -> u8 {
    if data.is_null() { return 0; }
    let slice = unsafe { core::slice::from_raw_parts(data, len) };
    let mut sum: u8 = 0;
    for &byte in slice { sum = sum.wrapping_add(byte); }
    sum
}

fn internal_helper() -> i32 { 42 }
#[no_mangle]
pub extern "C" fn call_internal() -> i32 { internal_helper() }

#[no_mangle]
pub extern "C" fn embedded_trigger_abort() { core::intrinsics::abort(); }
```
2.b downstream c program
```c
extern int embedded_add(int a, int b);
extern unsigned char embedded_checksum(const unsigned char *data, unsigned long len);
extern int call_internal(void);
extern void embedded_trigger_abort(void);

int main() {
    int failures = 0;
    if (embedded_add(10, 20) != 30) failures++;
    unsigned char data[] = {1, 2, 3};
    if (embedded_checksum(data, 3) != 6) failures++;
    if (call_internal() != 42) failures++;
    pid_t pid = fork();
    if (pid == 0) { embedded_trigger_abort(); _exit(0); }
    else { waitpid(pid, &status, 0); }
    return failures;
}
```

The test results with different compiler flags(which might cause binary size reduction) are as follows:
2.c result with `-Zstaticlib-hide-internal-symbols`
```
  settings                   OFF        ON  -Zsave     ALL    OFF.dynsym ON.dynsym
  ------------------------------------------------------------------------
  default                 485K      429K  56K (11%)     490       4     486
  lto_thin                180K      180K    0 (0%)       4       4       0
  lto_fat                 179K      179K    0 (0%)       4       4       0
  opt_s                   485K      429K  56K (11%)     490       4     486
  opt_z                   485K      429K  56K (11%)     490       4     486
  lto_thin_z              180K      180K    0 (0%)       4       4       0
  lto_fat_z               179K      179K    0 (0%)       4       4       0
  full                    179K      179K    0 (0%)       4       4       0
```

2.d result with `-Zstaticlib-hide-internal-symbols + -Zstaticlib-rename-internal-symbols`
```
  settings                   OFF        ON  -Zsave     ALL    OFF.dynsym ON.dynsym
  ------------------------------------------------------------------------
  default                 485K      447K  39K (7%)     490       4     486
  lto_thin                180K      189K  -5% (-5%)       4       4       0
  lto_fat                 179K      189K  -5% (-5%)       4       4       0
  opt_s                   485K      448K  38K (7%)     490       4     486
  opt_z                   485K      448K  38K (7%)     490       4     486
  lto_thin_z              180K      189K  -5% (-5%)       4       4       0
  lto_fat_z               179K      189K  -5% (-5%)       4       4       0
  full                    179K      189K  -5% (-5%)       4       4       0
```

Test results show that this compiler option is beneficial for scenarios where LTO cannot be enabled.

r? @bjorn3 @petrochenkov
Implement feature `integer_casts`

Tracking issue: rust-lang/rust#157388
…thanBrouwer

Rename `errors.rs` file to `diagnostics.rs` (2/N)

Follow-up of rust-lang/rust#157485.

r? @JonathanBrouwer
Use `mul nuw nsw` in `intrinsics::copy`

Essentially the same as rust-lang/rust#157560, just for `copy` instead of `copy_nonoverlapping`.

> Yeah, in fact both copy and copy_nonoverlapping could use this since we know the result must be at most isize::MAX else it cannot be inbounds.
> ~ rust-lang/rust#157560 (comment)

r? saethlin
…anBrouwer

Suggest comma multiple

Following from rust-lang/rust#157545

If there are multiple missing comma's, suggest fixing all of them in one step to avoid error cascade.

For example:
```
error: attribute items not separated with `,`
   |
LL |     name = "name"
   |                  ^ help: try adding `,` here
```
followed by
```
error: attribute items not separated with `,`
   |
LL |     kind = "static"
   |                    ^ help: try adding `,` here
```
after adding the comma.

Now this becomes one error:
```
error: attribute items not separated with `,`
  --> $DIR/attr-missing-comma.rs:10:18
   |
LL |     name = "name"
   |                  ^
   |
help: try adding `,` here
   |
LL |     name = "name",
   |                  +
help: try adding `,` here
   |
LL |     kind = "static",
   |                    +
```
…uwer

Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#157599 (`rust-analyzer` subtree update)
 - rust-lang/rust#157298 (Use alternate means of detecting enums in `is_udt`)
 - rust-lang/rust#155338 (Staticlib hide internal symbols)
 - rust-lang/rust#157402 (Implement feature `integer_casts`)
 - rust-lang/rust#157452 (Fix WASI links)
 - rust-lang/rust#157535 (Rename `errors.rs` file to `diagnostics.rs` (2/N))
 - rust-lang/rust#157585 (Rename `errors.rs` file to `diagnostics.rs` (3/N))
 - rust-lang/rust#157588 (Use `mul nuw nsw` in `intrinsics::copy`)
 - rust-lang/rust#157592 (Suggest comma multiple)
…r=BoxyUwU

remove UnevaluatedConstKind::def_id

this is some of the const side of rust-lang/rust#152245

not quite a _full_ removal, there's still some spicy things such as `UnevaluatedConstKind::def_span` remaining that won't quite work for new non-DefID `UnevaluatedConstKind` cases, but IMO this is the bulk of the work, and feature-specific things can deal with their quirks in their own PRs when they know their own use cases.

r? @BoxyUwU 

self-reminder: file an issue on what to do about rustc_public's handling of the raw DefIds in rustc_public AliasTy/AliasConst
…rochenkov

Rewrite `rustc_span::symbol::Interner` to avoid double hashing



Involves resorting to raw `HashTable` and writing an ad-hoc `IndexMap`-like structure, as we cannot get access to raw hashes otherwise.

My local cachegrind profile shows ~ -20_000_000 Ir

r? @petrochenkov
…seZ4

Link LLVM dynamically on x86_64-apple



Link LLVM dynamically on x86_64-apple just like we did for aarch64-apple-darwin
* rust-lang/rust#157205

r? @ZuseZ4
Incorrect types can't cause unsafety and making it untyped will make it
easier to get rid of the ProcMacro enum in the proc-macro ABI.
Change type of async context parameter after state transform.

`Future::poll` expects a `&mut std::task::Context<'_>`. Meanwhile, async coroutines use `std::future::ResumeTy` as resume parameter. This is meant to workaround the limitations of borrowck, which cannot prove that coroutines implement `for<'a, 'b> CoroutineTrait<&'a mut Context<'b>>`.

In the coroutine state transform, we need to change the signature from `ResumeTy` to the proper `&mut Context<'_>`. The current code attempts to find locals that have type `ResumeTy` to change their type. This is needlessly complex and relies on undocumented behaviour of the MIR builder.

Instead, this PR proposes to replace the `ResumeTy` argument with a new local, with value `ResumeTy(transmute(context))`.

Based on rust-lang/rust#156875.
…lubby789

bootstrap: Handle dotted table keys when parsing bootstrap.toml

Fixes rust-lang/rust#156948

`bootstrap.py` has a small hand-rolled reader that pulls the stage0 cargo and rustc out of `bootstrap.toml` before the real TOML parser is built. It only understood `[table]` headers, so the dotted form that `bootstrap.example.toml` now uses (`build.cargo = "..."`) was silently dropped, and the cargo/rustc lookup matched those keys in any table rather than only `[build]`.

Teach the reader to strip an optional dotted prefix and treat it as the key's table, the same way `configure.py` does when it writes the file, and scope the cargo/rustc lookup to `[build]`. New tests cover the dotted form, equivalence with the section form, wrong-table rejection, and dotted target keys.

*Disclosure: the code was written by AI (Claude); reviewed and tested by me.*
Disable `tests/debuginfo/pretty-std.rs` `OsString` cdb check

## Summary

Since approx. Windows SDK 20348, the corresponding cdb (and/or its underlying WinDbg engine) changed or regressed the `OsStr`/`OsString` visualization, and no longer renders the emoji. Since approx. SDK/cdb 26100, the output formatting of the string containing UTF-8 (i.e. the multi-byte emoji grapheme) seems to have further regressed (e.g. the end quotation mark is no longer shown and command output becomes garbled).

Relevant issues:

* rust-lang/rust#88840
* rust-lang/rust#148743
* rust-lang/rust#88796

This was failing for me locally on host Windows MSVC under `./x test tests/debuginfo`. And the issues re. this case failing has been open for a long while and have not been addressed, so I propose disabling this case.

I believe this is either a regression or a change in cdb and/or the underlying WinDbg. I have not bothered filing such a cdb bug report, I don't know enough about this.

The check was actually relaxed to not require the emoji to be rendered properly in the output in rust-lang/rust#88842, but I feel like that regressed the original intention of the check (that multi-byte Unicode graphemes are properly rendered), so I just restored the original checks but commented them out.

Maybe r? @wesleywiser (or compiler)
Remove ProcMacro enum from proc macro ABI

Instead encode this information in the crate metadata. This helps shrink the proc-macro ABI to just the parts necessary for transmitting raw bytes to perform RPC on top of.

r? @petrochenkov cc @cyrgani
…ess, r=GuillaumeGomez

rustdoc: Test & document `test_harness` code block attribute

They were fully untested and undocumented previously despite being stable.
Context: [#t-rustdoc > &#96;test_harness&#96; langstr @ 💬](https://rust-lang.zulipchat.com/#narrow/channel/266220-t-rustdoc/topic/.60test_harness.60.20langstr/near/546748038).

While at it, I've also improved the documentation for code block attributes in general.
I was only inspired to do so because there was no good place for `test_harness` and because it got hard to skim due to a lack of subsubsections.
…am-check, r=lcnr

Fix marker trait winnowing depending on impl order

Story: I was looking through this code for an unrelated reason and happened to notice the duplicate condition.  That seemed obviously wrong, especially in light of the comment, so I worked backward to what it affected, wrote a test that failed, and then found that the test matched an existing `known-bug` test, which pointed me to rust-lang/rust#109481.

---

The `TypeOutlives` handler in `evaluate_predicate_recursively` means to check whether a type in a `T: 'a` predicate has free regions, bound regions, non-region inference variables, or non-region generic parameters -- and if so, to return `EvaluatedToOkModuloRegions` rather than `EvaluatedToOk`.  Correspondingly, the comment says "no free lifetimes or generic parameters".  But the code was mistakenly checking `has_non_region_infer()` twice instead of checking both `has_non_region_infer()` and `has_non_region_param()`.

This meant that `TypeOutlives(T, 'static)` where `T` is a type parameter returned `EvaluatedToOk` -- claiming the result holds unconditionally -- when the correct answer is `EvaluatedToOkModuloRegions`.

The distinction matters during marker trait winnowing in `prefer_lhs_over_victim`, which uses `must_apply_considering_regions()` (true only for `EvaluatedToOk`) to decide whether one impl beats another when there are multiple candidates.  With the bug, a `T: 'static`-bounded impl appeared equally as strong as an unrestricted impl, making the winner depend on source order.  This caused spurious E0310 errors when the more-constrained impl happened to appear after the less-constrained one.

Fixes rust-lang/rust#109481.

This same symptom was originally filed as rust-lang/rust#84917 and fixed in PR rust-lang/rust#88139.  Then PR rust-lang/rust#102472 rewrote the `TypeOutlives` handler, introducing the duplicate `has_non_region_infer()` and losing the param check, regressing this. Around this same time, rust-lang/rust#109481 was filed.  It noted the connection to rust-lang/rust#102472 -- the bug only appeared after it -- but the duplicate condition was not noticed.

r? @lcnr

cc @oli-obk @nikomatsakis
Fix async drop glue for Box<T>

Fixes rust-lang/rust#143658.

This fixes async drop behavior for boxed values so that async drop glue reaches the boxed value’s async destructor in async drop context.

The change updates async-drop needs-drop analysis so `Box<T>` is handled specially for async drop by considering the boxed pointee and allocator when deciding whether async drop glue is needed.

This PR intentionally does not change the broader AsyncDrop design. It only fixes behavior under the existing `#![feature(async_drop)]` implementation.

Reviewer notes:
- `async-drop-box-allocator.rs` already covers async-dropping the allocator of a `Box`; this PR adds distinct coverage for the boxed value itself.
- Boxed dyn pointees are intentionally not pulled into this fix, preserving existing dynamic async-drop limitations.
- The change is isolated to async drop analysis; sync `needs_drop` behavior is unchanged.

@rustbot label F-async_drop
…iscross,Mark-Simulacrum

Make `Literal::byte_character_value` work with bytes as well

As noted in [this comment](rust-lang/rust#151973 (comment)), `byte_character_value` should work for bytes, so this PR fixes it.

r? @traviscross
Implement rustc_public::CrateDef{,Type} for FieldDef

This makes a few changes to rustc_public to make it a little easier to analyze ADT types.

* It implements `CrateDef` and `CrateDefType` for `FieldDef`, which allows easy access to the underlying `DefId`, names, and tool annotations.
* It adds `Crate::adts` to simplify stepping through all the ADTs in the crate.

Note that I did use Gemini to assist with writing this patch, but I wrote most of it, reviewed all the vode, and verified the tests pass locally.
…nBrouwer

Arg splat experiment - syntax impl

This PR is part of the argument splatting lang experiment, and FFI overloading / C++ interop project goals:
- rust-lang/rust#153629
- https://rust-lang.github.io/rust-project-goals/2026/overloading-for-ffi.html
- https://rust-lang.github.io/rust-project-goals/2025h2/interop-problem-map.html

I've split it from rust-lang/rust#153697 to make reviewing easier, see that PR for more details.

The PR is the initial implementation of the feature:
- `splat` incomplete feature gate
- `#[splat]` attribute on function arguments
- feature gate and UI tests for item type filtering, non-splattable arguments

Once this PR merges, I'll rebase rust-lang/rust#153697.
Add multibyte JSON diagnostic regression test

Closes rust-lang/rust#157148.

This pr adds ui coverage for json diagnostics with rendered ansi output on a
source line containing multibyte text.

Current main emits the original warning without ICEing. This test maintains that
behavior.
… r=GuillaumeGomez

Reorder `impl` restriction rendering and add bottom margin

This PR moves the `impl` restriction rendering above the trait description.
It also adds an ⓘ marker, italicizes the text, and adds a bottom margin.
Tracking issue: rust-lang/rust#105077

before:
<img width="1108" height="651" alt="image" src="https://github.com/user-attachments/assets/520d95cf-a648-44e7-8036-e453cfbdf569" />

after:
<img width="1085" height="671" alt="image" src="https://github.com/user-attachments/assets/84493e56-6227-433b-93d0-4fcbe28ac00c" />

r? @GuillaumeGomez
cc @Urgau @jhpratt
…fmease

Report duplicate relaxed bounds during ast lowering

Instead of during hir-ty-lowering.

Not sure it is worth erroring on at all, but it's better to do it directly during lowering instead of collecting bounds after the fact.
jhpratt and others added 8 commits June 9, 2026 16:53
fix doc for unicode normalization faq on `casefold` APIs

APIs added in rust-lang/rust#154742 have an outbound doc link to https://www.unicode.org/faq/normalization, but this URL appears to not exist.

The correct URL appears to be https://www.unicode.org/faq/normalization.html

cc @Jules-Bertholet
Update to ar_archive_writer v0.5.2

This includes rust-lang/ar_archive_writer#32 and rust-lang/ar_archive_writer#33. The former fixes a panic when there are more than 64k archive members.
…y, r=lqd

Add test for matches in `rustc_must_match_exhaustively`

r? @lcnr
Make trait refs & assoc ty paths properly induce trait object lifetime defaults



## Trait Object Lifetime Defaults

### Primer & Definitions

You could read [this section](https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes) in the Reference but it has several issues (see rust-lang/reference#1407). Here's a small explainer by me that only mentions the parts relevant to this PR:

Basically, given `dyn Trait` (≠ `dyn Trait + '_`) we want to deduce its *trait object lifetime bound* from context without relying on normal region inference as we might not be in a body[^1]. The "context" means the closest – what I call – *(eligible) container* `C<X0, …, Xn>` that wraps this trait object type. A *container* is to be understood as a use site of a "parametrized definition" (more general than type constructors). Currently *eligible* are ADTs, type aliases, traits and enum variants.

So if we have `C<dyn Trait>` (e.g., `&'r dyn Trait` or `Struct<'r, dyn Trait>`), `D<C<dyn Trait>>` or `C<N<dyn Trait>>` (e.g., `Struct<'r, (dyn Trait,)>`), we use the explicit[^2] outlives-bounds on the corresponding type parameter of `C` to determine the trait object lifetime bound. Here, `C` & `D` denote (eligible) containers and `N` denotes a generic type that is **not** an eligible container. E.g., given `struct Struct<'a, T: 'a + ?Sized>(…);`, we elaborate `Struct<'r, dyn Trait>` to `Struct<'r, dyn Trait + 'r>`.

Finally, we call lifetime bounds used as the default for *constituent* trait object types of an eligible container `C` the *trait object lifetime defaults* (*induced by* `C`). These defaults may of course end up getting shadowed in parts of the type by the defaults induced by any inner eligible containers.

### Changes Made

**These changes are theoretically breaking**.

1. Make *resolved* associated type paths / projections eligible containers.
   * `<Y0 as TraitRef<X0, …, Xn>>::AssocTy<Y1, …, Ym>` now induces *trait object lifetime defaults* for constituents `Y0` to `Ym` (`TraitRef` is considered a separate container, see also list item **(3)**).
   * Notably, for the self type `Y0` of (resolved) projections we now look at the bounds on the `Self` type param of the relevant trait (e.g., given `trait Outer<'a>: 'a { type Proj; }` or `trait Outer<'a> where Self: 'a { type Proj; }` we elaborate `<dyn Inner as Outer<'r>>::Proj` to `<dyn Inner + 'r as Outer<'r>>::Proj`).
   * Example breakages:
     ```rs
     trait Outer<'a> { type Ty<T: ?Sized + 'a>; }
     impl<'a> Outer<'a> for () { type Ty<T: ?Sized + 'a> = &'a T; }
     trait Inner {}
 
     fn f<'r>(x: <() as Outer<'r>>::Ty<dyn Inner>) {
     //                                ~~~~~~~~~
     //                                this branch:  dyn Inner + 'r       (due to bound `'a` on `T`)
     //                                stable/main:  dyn Inner + 'static  (due to item signature fallback)
         let _: <() as Outer<'r>>::Ty<dyn Inner + 'static> = x;
     //         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     //         this branch:  error: lifetime may not live long enough // `'r` must outlive `'static`
     //         stable/main:  OK
     }
     ```
     ```rs
     trait Outer { type Ty; }
     trait Inner {}

     impl<'a> Outer for dyn Inner + 'a { type Ty = &'a (); }

     fn f<'r>(x: *mut &'r <dyn Inner as Outer>::Ty) {
     //                    ~~~~~~~~~
     //                    this branch:  dyn Inner + 'static  (due to lack of bounds on `Outer`; the assoc type path shadows the default induced by the type ctor `&`)
     //                    stable/main:  dyn Inner + 'r       (due to bound `'a` on `T` in (pseudo) `builtin type &<'a, T: 'a + ?Sized>;`)
         let _: *mut &'r <dyn Inner + 'r as Outer>::Ty = x;
     //         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     //         this branch:  error: lifetime may not live long enough // `'r` must outlive `'static`
     //         stable/main:  OK
     }
     ```
2. In *type-relative* paths `Y0::Name<Y1, …, Ym>` consider the trait object lifetime default **indeterminate**
   * Meaning if we're in an "item context" / "item signature" / "non-body" (& the principal trait isn't bounded by any outlives-bounds which would take precedence over the default) we will **reject** any implicit trait object lifetime bounds that would take on that default
   * Reason: Limitations of the current implementation which can't be easily overcome
     * RBV (which resolves trait object lifetime defaults by recursing into the local crate "in one sitting") would require the resolution of *type-relative* paths in order to look up the generics but these paths are only resolved in HIR ty lowering (that can selectively lower local items) which depends on the results of RBV (cyclic dependency!)
     * While one might be able to resolve type-relative paths in RBV in an ad-hoc fashion, it would require a lot of duplication with HIR ty lowering and its impl would be very brittle (RTN does something like that in RBV but we require a more sophisticated resolver)
     * I did attempt that but it got too gnarly and brittle and would've likely been incomplete anyway
     * See also [this GH thread](rust-lang/rust#129543 (comment))
     * See also [#t-types/meetings > 2025-09-16 weekly @ 💬](https://rust-lang.zulipchat.com/#narrow/channel/326132-t-types.2Fmeetings/topic/2025-09-16.20weekly/near/539889059)
   * This should still be maximally forward compatible and allow us to implement the desired behavior in the future.
   * Example breakage:
     ```rs
     trait Outer { type Ty<'a, T: 'a + ?Sized>; }
     trait Inner {}
 
     fn f<'r, T: Outer>(x: T::Ty<'r, dyn Inner>) {}
     //                              ~~~~~~~~~
     //                              this branch:  error: indeterminate  (reservation)
     //                              stable/main:  dyn Inner + 'static   (due to item signature fallback)
     ```
3. Fixes trait object lifetime defaults inside trait refs `TraitRef<X0, …, Xn>` (this fell out from the previous changes). They used to be completely broken due to a nasty off-by-one error for not accounting for the implicit `Self` type param of traits which lead to cases like
   * `Outer<'r, dyn Inner>` (with `trait Outer<'a, T: 'a + ?Sized> {}`) getting rejected as *indeterminate* (it tries to access a *lifetime* at index 1 instead 0) ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=0069c89b2313f0f447ff8b6f7de9adfa)) 
   * `Outer<'r, 's, dyn Inner>` (with `trait Outer<'a, 'b, T: 'a + ?Sized> {}`) elaborating `dyn Inner` to `dyn Inner + 's` instead of `dyn Inner + 'r`(!) which subsequently gets rejected of course since `'s` isn't known to outlive `'r` ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=9c521165e0ac0d868a8087cd7ca861fe))
   * The same applies to trait *alias* refs (feature `trait_alias`)
   * Example breakage:
     ```rs
     trait Outer<'a, 'b, T: 'a + ?Sized> {}
     trait Inner {}
 
     struct F<'r, T>
     where
         T: Outer<'r, 'static, dyn Inner>
     //                        ~~~~~~~~~
     //                        this branch:  dyn Inner + 'r       (correctly mapping `'a` => `'r`)
     //                        stable/main:  dyn Inner + 'static  (incorrectly mapping `'a` => `'static` due to off-by-one)
     {
         g: G<'r, T>,
     //     ~~~~~~~~
     //     this branch:  error: mismatched types
     //                          expected: `Outer<'r, 'static, (dyn Inner + 'static)>`
     //                             found: `Outer<'r, 'static, (dyn Inner + 'r)>`
     //     stable/main:  OK
     }
 
     struct G<'r, T>(&'r (), T)
     where
         T: Outer<'r, 'static, dyn Inner + 'static>;
     ```
4. In associated type binding `TraitRef<AssocTy<X0, …, Xn> = Y>` consider the trait object lifetime default **indeterminate** (in `X0`, …, `Xn` and `Y`) if `X0`, …, `Xn` contains any lifetime arguments.
   * Meaning if we're in an item context (& the principal trait isn't bounded) we will **reject** any implicit trait object lifetime bounds that would take on that default
   * This reserves us the right to (1) take into account the *item bounds* of `AssocTy` in the future when computing the default for `Y` (2) take into account the parameter bounds of `AssocTy` in the future when computing the defaults for `X0`, …, `Xn`.
   * This extends a preexisting hack that – given `TraitRef<X0, …, Xn, AssocTy<Y0, …, Ym> = Z>` – treats the default indeterminate in `Y0`, …, `Ym` and `Z` if `X0`, …, `Xn` contains any lifetime arguments. 
   * Rephrased, this hack / reservation previously didn't account for GAT args, only trait ref args, which is insufficient
   * See also [this GH comment of mine](rust-lang/rust#115379 (comment))
   * Example breakages:
     ```rs
     trait Outer { type Ty<'a>: ?Sized; }
     trait Inner {}

     fn f<'r>(_: impl Outer<Ty<'r> = dyn Inner>) {}
     //                              ~~~~~~~~~
     //                              this branch:  error: indeterminate  (reservation)
     //                              stable/main:  dyn Inner + 'static   (forced)
     ```
     ```rs
     trait Outer { type Ty<'a, T: ?Sized + 'a>; }
     trait Inner {}

     fn f<'r>(_: impl Outer<Ty<'r, dyn Inner> = ()>) {}
     //                            ~~~~~~~~~
     //                            this branch:  error: indeterminate  (reservation)
     //                            stable/main:  dyn Inner + 'static   (forced)
     ```

#### Motivation

Both trait object lifetime default RFCs ([599](https://rust-lang.github.io/rfcs/0599-default-object-bound.html) and [1156](https://rust-lang.github.io/rfcs/1156-adjust-default-object-bounds.html)) never explicitly specify what constitutes a — what I call — *(eligible) container* but it only makes sense to include anything that can be parametrized by generics and can be mentioned in places where we don't perform full region inference … like associated types. So it's only *consistent* to make this change.

#### Breakages

**These changes are theoretically breaking** because they can lead to different trait object lifetime bounds getting deduced compared to main which is obviously user observable. Moreover, we're now explicitly rejecting implicit trait object lifetime bounds inside type-relative paths (excl. the self type) and on the RHS of assoc type bindings if the assoc type has lifetime params.
However, the latest crater run found 0 non-spurious regressions (see [here](rust-lang/rust#129543 (comment)) and [here](rust-lang/rust#129543 (comment))).

---

Fixes rust-lang/rust#115379.
Fixes rust-lang/rust#140710.
Fixes rust-lang/rust#141997.


[^1]: If we *are* in a body we do use to normal region inference as a fallback.
[^2]: Indeed, we don't consider implied bounds (inferred outlives-bounds).
Rollup of 17 pull requests



Successful merges:

 - rust-lang/rust#157166 (Change type of async context parameter after state transform.)
 - rust-lang/rust#157335 (bootstrap: Handle dotted table keys when parsing bootstrap.toml)
 - rust-lang/rust#157503 (Disable `tests/debuginfo/pretty-std.rs` `OsString` cdb check)
 - rust-lang/rust#157571 (Remove ProcMacro enum from proc macro ABI)
 - rust-lang/rust#148183 (rustdoc: Test & document `test_harness` code block attribute)
 - rust-lang/rust#153847 (Fix marker trait winnowing depending on impl order)
 - rust-lang/rust#156067 (Fix async drop glue for Box<T>)
 - rust-lang/rust#156399 (fix improper ctypes in Znext solver)
 - rust-lang/rust#157338 (Make `Literal::byte_character_value` work with bytes as well)
 - rust-lang/rust#157410 (Implement rustc_public::CrateDef{,Type} for FieldDef)
 - rust-lang/rust#157605 (Arg splat experiment - syntax impl)
 - rust-lang/rust#157630 (Add multibyte JSON diagnostic regression test)
 - rust-lang/rust#157633 (Reorder `impl` restriction rendering and add bottom margin)
 - rust-lang/rust#157642 (Report duplicate relaxed bounds during ast lowering)
 - rust-lang/rust#157652 (fix doc for unicode normalization faq on `casefold` APIs)
 - rust-lang/rust#157661 (Update to ar_archive_writer v0.5.2)
 - rust-lang/rust#157668 (Add test for matches in `rustc_must_match_exhaustively`)

Failed merges:

 - rust-lang/rust#157670 (Rename `errors.rs` file to `diagnostics.rs` (4/N))
Set !captures metadata for store of &Freeze

When a `&Freeze` reference is stored (with retag), emit `!captures !{!"address", !"read_provenance"}` metadata to indicate that it's UB to write through the stored pointer.

Related to rust-lang/rust#146844.

r? @ghost
This updates the rust-version file to 485ec3fbcc12fa14ef6596dabb125ad710499c9e.
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 11, 2026
@lnicola

lnicola commented Jun 11, 2026

Copy link
Copy Markdown
Member

I can't look into it right now, but this might need a no-default-features or something (because of the new default). CC @bjorn3

@lnicola

lnicola commented Jun 11, 2026

Copy link
Copy Markdown
Member

Yeah, reverting the default feature seems to fix this. Not sure if it was intentional.

@bjorn3

bjorn3 commented Jun 11, 2026

Copy link
Copy Markdown
Member

I think I changed that for rust-analyzer and then accidentally committed it.

@lnicola lnicola added this pull request to the merge queue Jun 11, 2026

[features]
default = ["in-rust-tree"]
default = []

@bjorn3 bjorn3 Jun 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
default = []
default = []
#default = ["in-rust-tree"]

would be a full revert. Your choice if you want to apply this.

View changes since the review

Merged via the queue into master with commit 0be02f1 Jun 11, 2026
19 checks passed
@lnicola lnicola deleted the rustc-pull branch June 11, 2026 08:18
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants