The Rust project is currently working towards a slate of 41 project goals, with 13 of them designated as Flagship Goals. This post provides selected updates on our progress towards these goals (or, in some cases, lack thereof). The full details for any particular goal are available in its associated tracking issue on the rust-project-goals repository.
Flagship goals
"Beyond the `&`"
| Progress | |
| Point of contact | |
| Champions | compiler (Oliver Scherer), lang (TC) |
| Task owners |
1 detailed update available.
Status update:
- [x] pattern matching support of
&pin const|mut Ttypes, merged. - [x]
&pinpattern andref pin mutbinding mode, merged. - [ ]
Drop::pin_drop, waiting for review (new updates since the last review).- Unresolved question: the current implementation requires changing the
src/docs/booksubmodule, but the top repo and the sub repo must be changed together to pass the CI tests in both repos. It's because a default body is added toDrop::dropand it becomes a provided method instead of a required method in rustdoc. Is there any way to avoid that? (Possibly keep rustdoc treatingDrop::dropas a required method?)
- Unresolved question: the current implementation requires changing the
- [ ] coercion between
&pin const|mut Tand&{mut} T, waiting for review (fresh).
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
3 detailed updates available.
Moving Projections and &own
Moving projections are a third kind of projection that already exists in Rust today for Box as well as any local variable holding a struct. While we won't be including it in an MVP, we still want to make sure that we can extend the language with moving projections. Here is an example with Box:
#![allow(unused)] fn main() { fn destructure_box(mut b: Box<Struct>) -> Box<Struct> { let f1 = b.f1; b.f1 = F1::new(); b } }
This projection moves the field out of the box, invalidating it in the process. To make it valid again, a new value has to be moved in for that field. Alternatively, the partially valid box can be dropped, this will drop all other fields of Struct and then deallocate the Box. Note that this last property is implemented by compiler magic today and moving projections would allow this special behavior for Box to be a library implementation instead.
To make this kind of projection available for all types, we can make it a proper operation by adding this trait:
#![allow(unused)] fn main() { pub unsafe trait ProjectMove: Projectable { type OutputMove<'a, F: Field<Base = Self::Target>>;unsafe fn project_move<'a, F: Field<Base = Self::Target>>( this: *mut Self, ) -> Self::OutputMove<'a, F>; unsafe fn drop_husk(husk: *mut Self); }}
Importantly, we also need a drop_husk function which is responsible for cleaning up the "husk" that remains when all fields have been move-projected. In the case of Box, it deallocates the memory. So for Box we could implement this trait like this:
#![allow(unused)] fn main() { impl<T> ProjectMove for Box<T> { type OutputMove<'a, F: Field<Base = T>> = F::Type;unsafe fn project_move<'a, F: Field<Base = T>>( this: *mut Self, ) -> F::Type { let ptr = unsafe { (*this).0.pointer.as_ptr() }; ptr::read(unsafe { <*const T as Project>::project::<'a, F>(&raw const ptr) }) } unsafe fn drop_husk(husk: *mut Self) { // this is exactly the code run by `Box::drop` today, as the compiler // drops the `T` before `Box::drop` is run. let ptr = (*husk).0; unsafe { let layout = Layout::for_value_raw(ptr.as_ptr()); if layout.size() != 0 { (*husk).1.deallocate(From::from(ptr.cast()), layout); } } } }}
To support moving back into a value we have two options:
- Add a
ProjectMoveBacktrait that declares an operation which accepts a value that is moved back into the projected one, or - Add
&ownreferences.
Until now, we have explored the second option, because there are lot's of other applications for &own.
&own References
A small interlude on &own references.
An &'a own T is a special kind of exclusive reference that owns the value it points to. This means that if you drop an &own T, you also drop the pointee. You can obtain an &own T by constructing it directly to local variable &own my_local or by deriving it from an existing &own via field projections. Smart pointers generally also allow creating &own T from &own SmartPtr<T>.
One important difference to &mut T is that &own is not only temporally unique (i.e. there are no other references to that value not derived from it) but also unique for that value. In other words, one can create at most one &own T to a local variable.
#![allow(unused)] fn main() { let mut val = Struct { ... }; let x = &own val; //~ HELP: ownership transferred here drop(x); let y = &own val; //~ ERROR: cannot own `val` twice }
Since the drop(x) statement drops val, the borrow checker must disallow any future access. However, we are allowed to move a value back into the memory of val:
#![allow(unused)] fn main() { let mut val = Struct { ... }; let x = &own val; drop(x); val = Struct { ... }; let y = &own val; }
The lifetime 'a in &'a own T is that of the backing memory. It means that when 'a expires, the memory also is no longer valid (or rather it cannot be proven that it is valid after 'a). For this reason an &'a own T has to be dropped (or forgotten) before 'a expires (since after that it cannot be dropped any more).
&own T itself supports moving projections (another indicator that having them is a good idea). However only for types that don't implement Drop (similar to normal struct destructuring -- there are also talks about lifting this requirement, but no new issues arise from projecting &own).
&own and pinning
To make &pin own T with !(T: Unpin) sound in the face of panics, we have to add drop flags or have unforgettable types. We explored a design using drop flags below; there are separate efforts to experimenting with a Leak/Forget trait ongoing, I think it might be a better solution than drop flags at least for &own.
We need drop flags to ensure the drop guarantee of pinned values. The drop flag will be stored when the original &own is created and it will live on the stack of the function that created it. They are needed for the following scenario:
#![allow(unused)] fn main() { fn foo() { let x = Struct { ... }; bar(&pin own x); }fn bar(x: &pin own Struct) { if random() { std::mem::forget(x); } if random() { panic!() } } }
Since x is pinned on the stack, it needs to be dropped before foo returns (even if it unwinds). When bar forgets the owned reference, the destructor is not run, if it now panics, the destructor needs to be run in foo. But since it gave away ownership of x to bar, it is possible that bar already dropped x (this is the case when the first random() call returns false). To keep track of this, we need a drop flag in the stack frame of foo that gets set to true when x is dropped.
There are several issues with drop flags:
- we can't have
&'static own Tpointing to non-static values (for example coming from aBox::leak_ownedfunction). - field projections complicate things: if we project to a field, then we could possibly forget one field, but drop another
- solution: just store drop flags not only for the whole struct, but also all transitive fields that implement
Drop
- solution: just store drop flags not only for the whole struct, but also all transitive fields that implement
- there is different behavior between
&own Tand&pin own T, the former can be forgotten and the destructor will not run, the latter can also be forgotten, but the destructor runs regardless.
This last point convinces me that we actually want &pin own T: !Leak when T: !Leak; but IIUC, that wouldn't prevent the following code from working:
fn main() { let x = Struct { ... }; let x = &pin own x; Box::leak(Box::new(x)); }
DerefMove
The DerefMove operation & trait is something that has been discussed in the past (I haven't dug up any discussions on it though). It is the analogous operation of &own to Deref. We need to figure out the hierarchy wrt. Deref and DerefMut, but ignoring that issue for the moment, here is how DerefMove would look like:
#![allow(unused)] fn main() { trait DerefMove: DropHusk { trait Target: ?Sized;fn deref_move(&own self) -> &own Self::Target; }}
Note the super trait requirement DropHusk -- it provides a special drop operation for Self when the &own Self::Target reference has been dropped. Box<T> for example would deallocate the backing memory via DropHusk. Its definition looks like this:
#![allow(unused)] fn main() { pub unsafe trait DropHusk { unsafe fn drop_husk(husk: *mut Self); } }
We would of course also use this trait for ProjectMove. Implementing DropHusk on its own does nothing; implementing DerefMove or ProjectMove will make the compiler call drop_husk instead of Drop::drop when the value goes out of scope after it has been projected or DerefMove::deref_move has been called.
We observed that DerefMove is a lot more restrictive in its usability than Deref--- and we need projections to make it actually useful in the common case. The reason for this is that &own can only be created once, but one would like to be able to create it once per field (which is exactly what moving projections allow). Consider this example:
#![allow(unused)] fn main() { let b = Box::new(Struct { ... }); let field1 = &own b.field1; // desugars to `DerefMove::deref_move` let field2 = &own b.field2; //~ ERROR: cannot own `b` twice }
The "cannot own `b` twice error comes from the way the deref desugaring works:
#![allow(unused)] fn main() { let b = Box::new(Struct { ... }); let field1 = &own DerefMove::deref_move(&own b).f1; let field2 = &own DerefMove::deref_move(&own b).f2; // ^^^ ERROR: cannot own `b` twice }
Now it's clear that we're trying to create two &own to the same value and that can't work (the issue also arises for &mut, but that already is covered by ProjectExclusive).
We can write this instead:
#![allow(unused)] fn main() { let b = Box::new(Struct { ... }); let b = &own b; let field1 = &own b.field1; let field2 = &own b.field2; }
But that's cumbersome.
We also note that ProjectMove is the correct projection for ArcRef, as it avoids any additional refcount updates. We can rely on the ergonomic refcounting proposal to provide ergonomic ways to clone the value & perform more projections.
Having a single Project trait
The definition of the now 3 Project* traits are 100% verbatim the same (modulo renaming of course), so we spent some time trying to unify them into a single trait. While we cannot get rid of having to have three traits, we can merge them into a single one by adding a generic:
#![allow(unused)] fn main() { #[sealed] pub trait ProjectKind { type Ptr<T: ?Sized>; }pub enum Shared {} pub enum Exclusive {}
impl ProjectKind for Shared { type Ptr<T: ?Sized> = *const T; }
impl ProjectKind for Exclusive { type Ptr<T: ?Sized> = *mut T; }
pub trait Projectable { type Target; }
pub unsafe trait Project<Kind: ProjectKind>: Projectable { type Output<'a, F: Field<Base = Self::Target>>;
unsafe fn project<'a, F: Field<Base = Self::Target>>( this: Kind::Ptr<Self>, ) -> Self::Output<'a, F>; }}
We would need some more compiler magic to ensure that nobody implements this trait generically, so impl<K> Project<K> for MyType, to keep our approach extendible (this could be an attribute if it is also useful in other cases #[rustc_deny_generic_impls]).
The benefit of merging the definitions is that we only have one single trait that we need to document and we could also add documentation on the ProjectKind types. There are also ergonomic downsides, for example all output types are now called Output and thus need to be fully qualified if multiple projection impls exist (<MyType as Project<Exclusive>>::Output<'_, F> vs MyType::OutputExclusive<'_, F>).
To make this proposal compatible with moving projections, we also either need more compiler magic to ensure that if Kind = Move we require Self: DropHusk. Or we could use associated traits and add one to ProjectKind that's then used in Project (Kind = Shared would then set this to Pointee).
This approach also makes me think a bit more about the syntax, if we discover more projections in the future, it might make sense to go for an extensible approach, like [[@keyword][]][] expr{->,.@,.,~}ident (so for example [[@move][]][] x->y or [Andrea D'Angelo][] x.y).
A new Perspective: Projections via Places
[@Nadrieril][] opened this zulip thread with the idea that "The normal rust way to reborrow a field uses places". He then proceeded to brainstorm a similar design for field projections with a crucial difference: making places the fundamental building block. We had a very long discussion in that thread (exchanging the existing ideas about field projection and the novel place-involving ones) that culminated in this awesome writeup by [@Nadrieril][]: https://hackmd.io/[[@Nadrieril][]][]/HJ0tuCO1-e. It is a very thorough document, so I will only be able to summarize it partially here:
- instead of the
Project*traits, we have thePlace*traits which govern what kind of place operations are possible on*xgivenx: MySmartPtr, those are reading, writing and borrowing. - we can allow custom smart pointer reborrowing possibly using the syntax
[[@MySmartPtr][]][] <place-expr> - we need multi-projections to allow simultaneous existence of
&mut x.field.aand&mut x.field.b
We still have many things to flesh out in this proposal (some of these pointed out by [@Nadrieril][]):
- how do FRTs still fit into the equation? And what are the types implementing the
Projectiontrait? - What do we do about non-indirected place containers like
MaybeUninit<T>,UnsafeCell<T>andManuallyDrop<T>? - does
BorrowKindwork as a model for the borrow checker? - how do we make
matchergonomics work nicely? - how do we get around the orphan rule limitations?
- several smaller issues/questions...
This is a very interesting viewpoint and I'm inclined to make this the main proposal idea. The traits are not too different from the current field projection design and the special borrow checker behavior was also intended at least for the first level of fields. So this is a natural evolution of the field projection proposal. Thanks a lot to [@Nadrieril][] for the stellar writeup!
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
We've worked towards coherence checking of the CoerceShared trait, and have come to a conclusion that (at least as a first step) only one lifetime, the first one, shall participate in reborrowing. Problems abound with how to store the field mappings for CoerceShared.
"Flexible, fast(er) compilation"
| Progress | |
| Point of contact | |
| Champions | cargo (Eric Huss), compiler (David Wood), libs (Amanieu d'Antras) |
| Task owners |
No detailed updates available.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners | bjorn3, Folkert de Vries, [Trifecta Tech Foundation] |
No detailed updates available.
| Progress | |
| Point of contact | |
| Task owners |
No detailed updates available.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
No detailed updates available.
"Higher-level Rust"
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
2 detailed updates available.
Three new blog posts:
- Explicit capture clauses
- Bikeshedding
Handleand other follow-up thoughts - But then again...maybe alias?
The most important conclusions from those posts are
- Explicit capture clauses would be useful, I proposed one specific syntax but bikeshedding will be required. To be "ergonomic" we need the ability to refer to full places, e.g.,
move(cx.foo.clone()) || use(cx.foo). - We should consider
AliasorShareas the name forHandletrait; I am currently leaning towardsAliasbecause it can be used as both a noun and a verb and is a bit more comparable to clone -- i.e., you can say "analiasoffoo" just like you'd say "acloneoffoo". - We should look for solutions that apply well to
cloneandaliasso that higher-level Rust gets the ergonomic benefits even when cloning "heavier-weight" types to whichAliasdoes not apply.
New blog post:
- https://smallcultfollowing.com/babysteps/blog/2025/11/10/just-call-clone/
Exploring one way to make things more ergonomic while remaining explicit, which is to make .clone() and .alias() (1) understood by move closure desugaring and (2) optimized away when redundant.
| Progress | |
| Point of contact | |
| Champions | cargo (Ed Page), lang (Josh Triplett), lang-docs (Josh Triplett) |
| Task owners |
1 detailed update available.
Key developments
- rust-lang/rust#148051
Blockers:
- rustdoc deciding on and implementing how they want frontmatter handled in doctests
"Unblocking dormant traits"
| Progress | |
| Point of contact | |
| Champions | |
| Task owners | Taylor Cramer, Taylor Cramer & others |
No detailed updates available.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners | Benno Lossin, Alice Ryhl, Michael Goulet, Taylor Cramer, Josh Triplett, Gary Guo, Yoshua Wuyts |
1 detailed update available.
On Nov 12th, there was a mini-design meeting organized by Xiangfei Ding on inplace initialization. The attendees were Xiangfei Ding, Alice Ryhl, Benno Lossin, Tyler Mandry, and Taylor Cramer.
We discussed this document: https://hackmd.io/[@rust-for-linux-][]/H11r2RXpgl
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
The new solver is now officially used by Rust Analyzer: https://rust-analyzer.github.io/thisweek/2025/10/27/changelog-299.html. A huge shoutout to Jack Huey Chayim Refael Friedman Shoyu Vanilla and Laurențiu Nicola for that work.
On the rustc end Rémy Rakic spent a lot of time triaging the most recent crater run. This uncovered a bunch of new edge cases, resulting in 6 new tracked issues.
We've also merged fixes for 4 minor issues over the last 3 weeks: https://github.com/rust-lang/rust/pull/148292 https://github.com/rust-lang/rust/pull/148173 https://github.com/rust-lang/rust/pull/147840. Thanks to Jana Dönszelmann, tiif and adwin for implementing these. adwin was also instrumental in diagnosing the underlying issue of https://github.com/rust-lang/trait-system-refactor-initiative/issues/245.
Going forward, we intend to continue the crater triage while fixing remaining issues until we're ready for stabilization :> the remaining issues are tracked in https://github.com/orgs/rust-lang/projects/61/views/1.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
No detailed updates available.
Goals looking for help
Other goal updates
| Progress | |
| Point of contact | |
| Champions |
1 detailed update available.
Done in https://github.com/rust-lang/rust-forge/pull/852.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
3 detailed updates available.
tiif and I have been meeting weekly here and pushing changes to the living-large branch of a-mir-formality/nikomatsakis.
We are making progress, we have a minirust type checker and the start of a borrow checker. We've decided to try to use a "judgment-like" approach rather than modeling this as dataflow, as I believe it will give greater insight into the "structure" of the trait checker.
tiif, Jack Huey, and I met today and did more work on the "living-large" branch. The borrow checker judgments are taking shape. My expectation is that we will walk the CFG, tracking the sets of borrows that have occurred so far. At each statement, we will have a judgment that looks at (a) the subtyping relations generated by the type check (flow-insensitive, like NLL); (b) the loans issued so far and not killed; and (c) the live places that may be accessed later. We'll require then that if you are accessing a place P, then there are no loans accessible from a live place that have borrowed P in an incompatible way.
Continued work this week:
Elaborated some on the definition of the when an access or a statement is valid. We are working our way towards what we believe will be a "largely accurate" model of today's NLL -- obviously we'll then want to test it and compare behavior around various edge cases.
| Progress | |
| Point of contact | |
| Champions | compiler (Oliver Scherer), lang (Tyler Mandry), libs (David Tolnay) |
| Task owners |
No detailed updates available.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
No detailed updates available.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
Since the lang meeting most progress on this project goal has been unrelated to adt_const_params.
There's been a large amount of work on min_generic_const_args, specifically Noah Lev's PR (#139558) which once landed the core of the impl work for the feature will be done. I've reviewed it together with Oliver Scherer and it's pretty much ready to go other than some small reviews.
Once this PR lands I'm hoping that there should be a fair amount of "smallish" PRs that can be made which could be a good set of PRs to mentor new-ish contributors on.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
Status update as of November 1
Key developments:
- Draft PR for exposing implied bounds in rustdoc JSON: https://github.com/rust-lang/rust/pull/148379
- A concrete plan for how that new info turns into dozens of new lints covering many kinds of bounds
Linting ?Sized and 'static bounds turned out to be quite a bit more complex than I anticipated. The key issue is that seeing T: Foo + ?Sized does not guarantee that T can be unsized, since we might have Foo: Sized which renders the ?Sized relaxation ineffective. Similarly, seeing T: Foo might also non-obviously imply T: 'static via a similar implied bound.
Failure to correctly account for implied bounds would lead to catastrophic false-positives and false-negatives. For example, changing T: Foo to T: Foo + 'static could be a major breaking change or a no-op, depending on whether we have Foo: 'static (either directly or implicitly via other trait bounds).
We cannot determine implied bounds using information present in rustdoc JSON today, so the rustdoc team and I have been iterating on the best way to compute and include that information in rustdoc JSON. Assuming something similar to the aforementioned PR becomes part of rustdoc JSON, cargo-semver-checks stands to gain several dozen new lints covering these tricky cases over trait associated types, generic type parameters, and APIT/RPIT/RPITIT.
| Progress | |
| Point of contact | |
| Champions | bootstrap (Jakub Beránek), lang (Niko Matsakis), spec (Pete LeVasseur) |
| Task owners | Pete LeVasseur, Contributors from Ferrous Systems and others TBD, |
2 detailed updates available.
Meeting minutes from meeting held on 2025-10-31 (thank you to Tomas Sedovic 🥰)
Top-level:
- Keep high quality bar, merge small, well-vetted changes when possible
- Need concentrated effort to get the 1.90 FLS updates merged
- Hristian Kirtchev and Tshepang Mbambo are navigating this currently with TC
- Once 1.90 merged, we attempt first go as a team at 1.91
Discussion:
- Suggest that everyone read the Glossary as a starting point
- How to best triage / handle incoming issues?
- TC and Pete LeVasseur moved labels onto FLS repo that were needed
- Pete LeVasseur created issue template, that's in review, to help focus triage
Meeting notes here: 2025-11-14 - t-fls Meeting
Key developments: PR merged for 1.90 update of the FLS. We're preparing now to work on the 1.91 update of the FLS. Blockers: None currently Help wanted: Anyone that's familiar with the Rust Reference is more than encouraged to read through the FLS to get a sense of it and where further alignment may be possible. Feel free to open issues on the FLS repo as you find things.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners | Amanieu d'Antras, Guillaume Gomez, Jack Huey, Josh Triplett, lcnr, Mara Bos, Vadim Petrochenkov, Jane Lusby |
1 detailed update available.
We're putting together a prototype/demo of our reference changes at https://rust-lang.github.io/project-goal-reference-expansion/ . This includes a demonstration of tooling changes to provide stability markers (both "documenting unstable Rust" and "unstable documentation of stable Rust").
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
Key developments:
- libtest2:
#[test]macro added- Support for
should_panic - Support for
ignore - Support for custom error types
- compile-fail tests for macros
Blockers
- None
Help wanted:
- Round out libtest compatibility
| Progress | |
| Point of contact | |
| Champions | compiler (Manuel Drehwald), lang (TC) |
| Task owners | Manuel Drehwald, LLVM offload/GPU contributors |
1 detailed update available.
Automatic Differentiation
Time for the next update. By now, we've had std::autodiff for around a year in upstream rustc, but not in nightly. In order to get some more test users, I asked the infra team to re-evaluate just shipping autodiff as-is. This means that for the moment, we will increase the binary size of rustc by ~5%, even for nightly users who don't use this feature. We still have an open issue to avoid this overhead by using dlopen, please reach out if you have time to help. Thankfully, my request was accepted, so I spent most of my time lately preparing that release.
- As part of my cleanup I went through old issues, and realized we now partly support rlib's! That's a huge improvement, because it means you can use autodiff not only in your
main.rsfile, but also in dependencies (eitherlib.rs, or even rely on crates that use autodiff). With the help of Ben Kimock I figured out how to get the remaining cases covered, hopefully the PR will land soon. - I started documentation improvements in https://github.com/rust-lang/rust/pull/149082 and https://github.com/rust-lang/rust/pull/148201, which should be visible on the website from tomorrow onwards. They are likely still not perfect, so please keep opening issues if you have questions.
- We now provide a helpful error message if a user forgets enabling
lto=fat: https://github.com/rust-lang/rust/pull/148855 - After two months of work, [@sgasho][] managed to add Rust CI to enzyme! Unfortunately, Enzyme devs broke and disabled it directly, so we'll need to talk about maintaining it as part of shipping Enzyme in nightly.
I have the following elements on my TODO list as part shipping AD on nightly
- Re-enable macOS build (probably easy)
- Talk with Enzyme Devs about maintenance
- Merge rlib support (under review)
- upstream ADbenchmarks from r-l/enzyme to r-l/r as codegen tests (easy)
- Write a block post/article for https://blog.rust-lang.org/inside-rust/
GPU offload
- The llvm dev talk about GPU programming went great, I got to talk to a lot of other developers in the area of llvm offload. I hope to use some of the gained knowledge soon. Concrete steps planned are the integration of libc-gpu for IO from kernels, as well as moving over my code from the OpenMP API to the slightly lower level liboffload API.
- We confirmed that our gpu offload prototype works on more hardware. By now we have the latest AMD APU generation covered, as well as an MI 250X and an RTX 4050. My own Laptop with a slightly older
AMD Ryzen 7 PRO 7840Uunfortunately turned out to be not supported by AMD drivers. - The offload intrinsic PR by Marcelo Domínguez is now marked as ready, and I left my second round of review. Hopefully, we can land it soon!
- I spend some time trying to build and potentially ship the needed offload changes in nightly, unfortunately I still fail to build it in CI: https://github.com/rust-lang/rust/pull/148671.
All in all, I think we made great progress over the last month, and it's motivating that we finally have no blockers left for flipping the llvm.enzyme config on our nightly builds.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners | (depending on the flag) |
1 detailed update available.
Update from the 2025-11-05 meeting.
-Zharden-sls / rust#136597
Wesley Wiser left a comment on the PR, Andr
-Zno-jump-tables / rust#145974
Merged, expected to ship in Rust 1.93. The Linux kernel added support for the new name for the option (-Cjump-tables=n).
| Progress | |
| Point of contact | |
| Champions | lang (Josh Triplett), lang-docs (TC) |
| Task owners |
1 detailed update available.
Update from the 2025-11-05 meeting.
Deref/Receiver
Ding Xiang Fei posted his reasoning for the trait split in the Zulip thread and suggested adding a second RFC to explain.
TC recommended writing a Reference PR. The style forces one to explain the model clearly which should then make writing the RFC easier.
The lang experiment PR for arbitrary self types have feature gates for the two options we're exploring.
Arbitrary Self Types and derive(CoercePointee) / tracking issue #44874
theemathas opened an issue derive(CoercePointee) accepts ?Sized + Sized #148399. This isn't a critical issue, just an error that arguably should be a lint.
Boxy opened a fix for a derive(CoercePointee) blocker: Forbid freely casting lifetime bounds of dyn-types
.
RFC #3851: Supertrait Auto-impl
Ding Xiang Fei is working on the implementation (the parser and HIR interface for it). Ding's also working on a more complete section dedicated to questions raised by obi1kenobi
Field projections
Benno Lossin has been posting super detailed updates on the tracking issue
We've discussed the idea of virtual places (see Zulip thread where they were proposed).
Inlining C code into Rust code
Matt Mauer had an idea to compile C code into LLVM bytecode (instead of object file) and then the llvm-link tool to merge them together and treat everything in the second bytecode file as a static inlined function. Matt suggested we could integrate this into the rustc passes.
This would make it easy to inline certain functions into Rust code without full LTO.
Relevant Zulip thread.
This sounds like a good candidate for the next Project Goals period.
| Progress | |
| Point of contact | |
| Champions | cargo (Ed Page), compiler (b-naber), crates-io (Carol Nichols) |
| Task owners |
No detailed updates available.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
An RFC draft covering the MIR changes necessary to support this optimization has been written and is currently being reviewed by T-opsem. It has already received one round of review and the feedback has been incorporated in the draft.
| Progress | |
| Point of contact | |
| Task owners |
|
No detailed updates available.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
Instead of using a full-fledged database like SQLite, we switched to a basic JSONL-based logging system to collect build metrics. A simple design doc can be found here: https://hackmd.io/K5-sGEJeR5mLGsJLXqsHrw.
Here are the recent pull requests:
- https://github.com/rust-lang/cargo/pull/16150
- https://github.com/rust-lang/cargo/pull/16179
To enable it, set CARGO_BUILD_ANALYSIS_ENABLED=true or set the Cargo config file like this:
[build.analysis]
enabled = true
As of today (nightly-2025-11-03), it currently emits build-started and timing-info two log events to $CARGO_HOME/log/ (~/.cargo/log/ by default). The shape of timing-info JSON is basically the shape of the unstable --timing=json. I anticipate when this is stabilized we don't need --timing=json.
The build.analysis.enable is a non-blocking unstable feature. Unless bugs, should be able to set unconditionally even on stable toolchain. When not supported, it would just warn the unknown config merely.
| Progress | |
| Point of contact | |
| Champions | compiler (Oliver Scherer), lang (Scott McMurray), libs (Josh Triplett) |
| Task owners | oli-obk |
1 detailed update available.
Another related PR:
https://github.com/rust-lang/rust/pull/148820
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
Status update November 21, 2025
October was largely spent working out design details of the build cache and locking design.
https://github.com/rust-lang/cargo/pull/16155 was opened with an initial implementation for fine grain locking for Cargo's build-dir however it needs to be reworked after the design clarifications mentioned above.
In November I had a change of employer so I my focus was largely on that. However, we did make some progress towards locking in https://github.com/rust-lang/cargo/pull/16230 which no longer lock the artifact-dir for cargo check. This is expected to land in 1.93.0.
I'm hoping to push fine grain locking forward later this month and in December.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
This project goal has been completed. I updated the first issue to reflect it. Closing the issue then.
| Progress | |
| Point of contact | |
| Task owners | [Bastian Kersting](https://github.com/1c3t3a), [Jakob Koschel](https://github.com/jakos-sec) |
1 detailed update available.
| Progress | |
| Point of contact | |
| Task owners | vision team |
1 detailed update available.
Update:
Jack Huey has been doing great work building out a system for analyzing interviews. We are currently looking at slicing the data along a few dimensions:
- What you know (e.g., experience in other languages, how much experience with Rust)
- What you are trying to do (e.g., application area)
- Where you are trying to do it (e.g., country)
and asking essentially the same set of questions for each, e.g., what about Rust worked well, what did not work as well, what got you into Rust, etc.
Our plan is to prepare a draft of an RFC with some major conclusions and next steps also a repository with more detailed analysis (e.g., a deep dive into the Security Critical space).
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
The new system has been running in production without any major issues for a few weeks now. In a few weeks, I plan to start using the second collector, and then announce the new system to Project members to tell them how they can use its new features.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
|
No detailed updates available.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
No detailed updates available.
| Progress | |
| Point of contact | |
| Champions | compiler (David Wood), lang (Niko Matsakis), libs (Amanieu d'Antras) |
| Task owners |
1 detailed update available.
Notes from our meeting today:
Syntax proposal: only keyword
We are exploring the use of a new only keyword to identify "special" bounds that will affect the default bounds applied to the type parameter. Under this proposal, T: SizeOfVal is a regular bound, but T: only SizeOfVal indicates that the T: const Sized default is suppressed.
For the initial proposal, only can only be applied to a known set of traits; one possible extension would be to permit traits with only supertraits to also have only applied to them:
#![allow(unused)] fn main() { trait MyDeref: only SizeOfVal { } fn foo<T: only MyDeref>() { }// equivalent to
trait MyDeref: only SizeOfVal { } fn foo<T: MyDeref + only SizeOfVal>() { } }
We discussed a few other syntactic options:
- A
^SizeOfValsigil was appealing due to the semver analogy but rejected on the basis of it being cryptic and hard to google. - The idea of applying the keyword to the type parameter
only T: SizeOfValsort of made sense, but it would not compose well if we add additional families of "opt-out" traits likeDestructandForget, and it's not clear how it applies to supertraits.
Transitioning target
After testing, we confirmed that relaxing Target bound will result in significant breakage without some kind of transitionary measures.
We discussed the options for addressing this. One option would be to leverage "Implementable trait aliases" RFC but that would require a new trait (Deref20XX) that has a weaker bound an alias trait Deref = Deref20XX<Target: only SizeOfVal>. That seems very disruptive.
Instead, we are considering an edition-based approach where (in Rust 2024) a T: Target bound is defaulted to T: Deref<Target: only SizeOfVal> and (in Rust 20XX) T: Target is defaulted to T: Deref<Target: only Pointee>. The edition transition would therefore convert bounds to one of those two forms to be fully explicit.
One caveat here is that this edition transition, if implemented naively, would result in stronger bounds than are needed much of the time. Therefore, we will explore the option of using bottom-up analysis to determine when transitioning whether the 20XX bound can be used instead of the more conservative 2024 bound.
Supertrait bounds
We explored the implications of weakening supertrait bounds a bit, looking at this example
and#![allow(unused)] fn main() { trait FooTr<T: ?Sized> {}struct Foo<T: ?Sized>(std::marker::PhantomData<T>);
fn bar<T: ?Sized>() {}
trait Bar: FooTr<Self> /*: no longer MetaSized */ { // ^^^^^^^^^^^ error! // real examples are
Pin }TypeOf::of: fn foo(&self, x: Foo<Self>) { // ^^^^^^^^^^^^ error! bar::<Self>(); // ^^^^^^^^^^ error!// real examples are in core::fmt and core::iter: trait DoThing { fn do_thing() {} } impl<T: ?Sized> DoThing for T { default fn do_thing() {} } impl<T: Sized> DoThing for T { fn do_thing() {} } self.do_thing(); // ^^^^^^^^^^^^^ error! // specialisation case is not an issue because that feature isn't stable, we can adjust core, but is a hazard with expanding trait hierarchies in future if stabilisation is ever stabilised }}
The experimental_default_bounds work originally added Self: Trait bounds to default methods but moved away from that because it could cause region errors (source 1 / source 2). We expect the same would apply to us but we are not sure.
We decided not to do much on this, the focus remains on the Deref::Target transition as it has more uncertainty.
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |
1 detailed update available.
A bit late on this update but I've sat down with lcnr a little while back and we tried to come up with a list of topics that we felt fell under type system documentation. This is an entirely unordered list and some topics may already be adequately covered in the dev guide already.
Regardless this effectively serves as a "shiny future" for everything I'd like to have documentation about somewhere (be it dev guide or in-tree module level documentation):
- opaque types
- non defining vs defining uses
- member constraints (borrowck overlap)
- checking item bounds
- high level normalization/opaque type storage approach (new solver)
- normalization incompleteness
- method/function incompleteness
- how does
use<...>work 'erasedregions causes problems with outlives item bounds in liveness- consistency across defining scopes
- RPITIT inference? does this have special stuff
- capturing of bound vars in opaques under binders,
Fnbounds are somewhat special in relation to this - opaques inheriting late bound function parameters
- non opaque type,
impl Trait- RPITIT in traits desugaring
impl Traitin bindings- APIT desugaring impl details
- const generics
- anonymous constants
- ConstArgHasType
- TSVs vs RVs and generally upstream doc from lang meeting to dev guide
- deterministic CTFE requirement
- HIR typeck
- expectations (and how used incorrectly :3)
- method lookup + assorted code cleanups
- coercions
- auto-deref/reborrows (in coercions/method selection)
- closure signature inference
- fudge_inference_if_ok :>
- diverging block handling :3
- fallback :3
- MIR borrowck
- MIR typeck
- why do we want two typecks
- region dependent goals in new solver (interaction with lack-of region uniquification)
- overlaps with opaque types
- compute region graph
- closure requirements
- borrowck proper
- MIR typeck
- compare predicate entailment :>
- param env jank
- implied bounds handling
- trait objects: recent FCPs :3
- dyn compatibility soundness interactions (see coerce pointee/arbitrary self types stuff)
- dyn compatibility for impl reasons (monomorphization)
- projection bounds handling
- args not required for wf
ty::Inferintyoverview- generalization
- coroutines
- deferred coroutine obligations
- witness types?
- why
-Zhigher-ranked-assumptionsexists
- binders and universes
existsA forallB A == B- build more of an intuition than current docs :thinking_face:
- talk about hr implied bounds there/be more explicit/clear in https://rustc-dev-guide.rust-lang.org/traits/implied-bounds.html?highlight=implied#proving-implicit-implied-bounds
- incompleteness
- what is it
- what kinds are OK (not entirely sure yet. small explanation and add a note)
- trait solving
- cycles
- general overview of how trait solving works as a concept (probably with example and handwritten proof trees)
- important: first go "prove stuff by recursively proving nested requirements", then later introduce candidates
- clauses/predicates
- running pending goals in a loop
- what kinds of incompleteness (overlap with opaques)
- builtin impls and how to add them
- hir to ty lowering :>
- itemctxt vs fnctxt behaviours
- normalization in lowering
- lowering should be lossy
- idempotency(?)
- cycles from param env construction
- const generics jank about Self and no generic parameters allowed
- well formedness checking + wf disambiguation page
- normalization & aliases
- be more clear about normalizing ambig aliases to infer vars :thinking_face:
- normalize when equating infer vars with aliases (overlap with generalization?)
- item bounds checking
- interactions with implied bounds (overlap with implied bounds and hir ty lowering)
- variance
Since making this list I've started working on writing documentation about coercions/adjustments. So far this has mostly resulted in spending a lot of time reading the relevant code in rustc. I've discovered a few bugs and inconsistencies in behaviour and made some nice code cleanups which should be valuable for people learning how coercions are implemented already. This can be seen in #147565
I intend to start actually writing stuff in the dev guide for coercions/adjustments now as that PR is almost done.
I also intend to use a zulip thread (#t-compiler/rustc-dev-guide > Type System Docs Rewrite) for more "lightweight" and informal updates on this project goal, as well as just miscellaneous discussion about work relating to this project goal
| Progress | |
| Point of contact | |
| Champions | |
| Task owners |