Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 `&`"

Continue Experimentation with Pin Ergonomics (rust-lang/rust-project-goals#389)
Progress
Point of contact

Frank King

Champions

compiler (Oliver Scherer), lang (TC)

Task owners

Frank King

1 detailed update available.

Comment by [Frank King][] posted on 2025-11-21:

Status update:

Design a language feature to solve Field Projections (rust-lang/rust-project-goals#390)
Progress
Point of contact

Benno Lossin

Champions

lang (Tyler Mandry)

Task owners

Benno Lossin

3 detailed updates available.

Comment by [Benno Lossin][] posted on 2025-11-01:

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&lt;'a, F: Field&lt;Base = Self::Target&gt;&gt;(
    this: *mut Self,
) -&gt; Self::OutputMove&lt;'a, F&gt;;

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&lt;'a, F: Field&lt;Base = T&gt;&gt;(
    this: *mut Self,
) -&gt; F::Type {
    let ptr = unsafe { (*this).0.pointer.as_ptr() };
    ptr::read(unsafe {
        &lt;*const T as Project&gt;::project::&lt;'a, F&gt;(&amp;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:

  1. Add a ProjectMoveBack trait that declares an operation which accepts a value that is moved back into the projected one, or
  2. Add &own references.

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 T pointing to non-static values (for example coming from a Box::leak_owned function).
  • 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
  • there is different behavior between &own T and &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(&amp;own self) -&gt; &amp;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.

Comment by [Benno Lossin][] posted on 2025-11-02:

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&lt;'a, F: Field&lt;Base = Self::Target&gt;&gt;(
    this: Kind::Ptr&lt;Self&gt;,
) -&gt; Self::Output&lt;'a, F&gt;;
}

}

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).

Comment by [Benno Lossin][] posted on 2025-11-06:

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 the Place* traits which govern what kind of place operations are possible on *x given x: 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.a and &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 Projection trait?
  • What do we do about non-indirected place containers like MaybeUninit<T>, UnsafeCell<T> and ManuallyDrop<T>?
  • does BorrowKind work as a model for the borrow checker?
  • how do we make match ergonomics 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

Aapo Alasuutari

Champions

compiler (Oliver Scherer), lang (Tyler Mandry)

Task owners

Aapo Alasuutari

1 detailed update available.

Comment by [Aapo Alasuutari][] posted on 2025-11-11:

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

David Wood

Champions

cargo (Eric Huss), compiler (David Wood), libs (Amanieu d'Antras)

Task owners

Adam Gemmell, David Wood

No detailed updates available.
Production-ready cranelift backend (rust-lang/rust-project-goals#397)
Progress
Point of contact

Folkert de Vries

Champions

compiler (bjorn3)

Task owners

bjorn3, Folkert de Vries, [Trifecta Tech Foundation]

No detailed updates available.
Promoting Parallel Front End (rust-lang/rust-project-goals#121)
Progress
Point of contact

Sparrow Li

Task owners

Sparrow Li

No detailed updates available.
Relink don't Rebuild (rust-lang/rust-project-goals#400)
Progress
Point of contact

Jane Lusby

Champions

cargo (Weihang Lo), compiler (Oliver Scherer)

Task owners

Ally Sommers, Piotr Osiewicz

No detailed updates available.

"Higher-level Rust"

Ergonomic ref-counting: RFC decision and preview (rust-lang/rust-project-goals#107)
Progress
Point of contact

Niko Matsakis

Champions

compiler (Santiago Pastorino), lang (Niko Matsakis)

Task owners

Niko Matsakis, Santiago Pastorino

2 detailed updates available.

Comment by [Niko Matsakis][] posted on 2025-11-05:

Three new blog posts:

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 Alias or Share as the name for Handle trait; I am currently leaning towards Alias because it can be used as both a noun and a verb and is a bit more comparable to clone -- i.e., you can say "an alias of foo" just like you'd say "a clone of foo".
  • We should look for solutions that apply well to clone and alias so that higher-level Rust gets the ergonomic benefits even when cloning "heavier-weight" types to which Alias does not apply.
Comment by [Niko Matsakis][] posted on 2025-11-12:

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.

Stabilize cargo-script (rust-lang/rust-project-goals#119)
Progress
Point of contact

Ed Page

Champions

cargo (Ed Page), lang (Josh Triplett), lang-docs (Josh Triplett)

Task owners

Ed Page

1 detailed update available.

Comment by [Ed Page][] posted on 2025-11-21:

Key developments

  • rust-lang/rust#148051

Blockers:

  • rustdoc deciding on and implementing how they want frontmatter handled in doctests

"Unblocking dormant traits"

Evolving trait hierarchies (rust-lang/rust-project-goals#393)
Progress
Point of contact

Taylor Cramer

Champions

lang (Taylor Cramer), types (Oliver Scherer)

Task owners

Taylor Cramer, Taylor Cramer & others

No detailed updates available.
In-place initialization (rust-lang/rust-project-goals#395)
Progress
Point of contact

Alice Ryhl

Champions

lang (Taylor Cramer)

Task owners

Benno Lossin, Alice Ryhl, Michael Goulet, Taylor Cramer, Josh Triplett, Gary Guo, Yoshua Wuyts

1 detailed update available.

Comment by [Alice Ryhl][] posted on 2025-11-14:

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

Next-generation trait solver (rust-lang/rust-project-goals#113)
Progress
Point of contact

lcnr

Champions

types (lcnr)

Task owners

Boxy, Michael Goulet, lcnr

1 detailed update available.

Comment by [lcnr][] posted on 2025-11-13:

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.

Stabilizable Polonius support on nightly (rust-lang/rust-project-goals#118)
Progress
Point of contact

Rémy Rakic

Champions

types (Jack Huey)

Task owners

Amanda Stjerna, Rémy Rakic, Niko Matsakis

No detailed updates available.

Goals looking for help

Other goal updates

Add a team charter for rustdoc team (rust-lang/rust-project-goals#387)
Progress Will not complete
Point of contact

Guillaume Gomez

Champions

rustdoc (Guillaume Gomez)

1 detailed update available.

Comment by [Guillaume Gomez][] posted on 2025-11-21:

Done in https://github.com/rust-lang/rust-forge/pull/852.

Borrow checking in a-mir-formality (rust-lang/rust-project-goals#122)
Progress
Point of contact

Niko Matsakis

Champions

types (Niko Matsakis)

Task owners

Niko Matsakis, tiif

3 detailed updates available.

Comment by [Niko Matsakis][] posted on 2025-11-05:

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.

Comment by [Niko Matsakis][] posted on 2025-11-12:

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.

Comment by [Niko Matsakis][] posted on 2025-11-19:

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.

C++/Rust Interop Problem Space Mapping (rust-lang/rust-project-goals#388)
Progress
Point of contact

Jon Bauman

Champions

compiler (Oliver Scherer), lang (Tyler Mandry), libs (David Tolnay)

Task owners

Jon Bauman

No detailed updates available.
Comprehensive niche checks for Rust (rust-lang/rust-project-goals#262)
Progress
Point of contact

Bastian Kersting

Champions

compiler (Ben Kimock), opsem (Ben Kimock)

Task owners

Bastian Kersting], Jakob Koschel

No detailed updates available.
Progress
Point of contact

Boxy

Champions

lang (Niko Matsakis)

Task owners

Boxy, Noah Lev

1 detailed update available.

Comment by [Boxy][] posted on 2025-11-05:

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.

Continue resolving `cargo-semver-checks` blockers for merging into cargo (rust-lang/rust-project-goals#104)
Progress
Point of contact

Predrag Gruevski

Champions

cargo (Ed Page), rustdoc (Alona Enraght-Moony)

Task owners

Predrag Gruevski

1 detailed update available.

Comment by [Predrag Gruevski][] posted on 2025-11-02:

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.

Develop the capabilities to keep the FLS up to date (rust-lang/rust-project-goals#391)
Progress
Point of contact

Pete LeVasseur

Champions

bootstrap (Jakub Beránek), lang (Niko Matsakis), spec (Pete LeVasseur)

Task owners

Pete LeVasseur, Contributors from Ferrous Systems and others TBD, t-spec and contributors from Ferrous Systems

2 detailed updates available.

Comment by [Pete LeVasseur][] posted on 2025-11-05:

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
  • 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?
Comment by [Pete LeVasseur][] posted on 2025-11-21:

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.

Emit Retags in Codegen (rust-lang/rust-project-goals#392)
Progress
Point of contact

Ian McCormack

Champions

compiler (Ralf Jung), opsem (Ralf Jung)

Task owners

Ian McCormack

1 detailed update available.

Comment by [Ian McCormack][] posted on 2025-11-11:

We've posted a pre-RFC for feedback, and we'll continue updating and expanding the draft here. This reflects most of the current state of the implementation, aside from tracking interior mutability precisely, which is still TBD but is described in the RFC.

Expand the Rust Reference to specify more aspects of the Rust language (rust-lang/rust-project-goals#394)
Progress
Point of contact

Josh Triplett

Champions

lang-docs (Josh Triplett), spec (Josh Triplett)

Task owners

Amanieu d'Antras, Guillaume Gomez, Jack Huey, Josh Triplett, lcnr, Mara Bos, Vadim Petrochenkov, Jane Lusby

1 detailed update available.

Comment by [Josh Triplett][] posted on 2025-11-12:

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").

Finish the libtest json output experiment (rust-lang/rust-project-goals#255)
Progress
Point of contact

Ed Page

Champions

cargo (Ed Page)

Task owners

Ed Page

1 detailed update available.

Comment by [Ed Page][] posted on 2025-11-21:

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:

Finish the std::offload module (rust-lang/rust-project-goals#109)
Progress
Point of contact

Manuel Drehwald

Champions

compiler (Manuel Drehwald), lang (TC)

Task owners

Manuel Drehwald, LLVM offload/GPU contributors

1 detailed update available.

Comment by [Manuel Drehwald][] posted on 2025-11-19:

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.

  1. 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.rs file, but also in dependencies (either lib.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.
  2. 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.
  3. We now provide a helpful error message if a user forgets enabling lto=fat: https://github.com/rust-lang/rust/pull/148855
  4. 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

  1. Re-enable macOS build (probably easy)
  2. Talk with Enzyme Devs about maintenance
  3. Merge rlib support (under review)
  4. upstream ADbenchmarks from r-l/enzyme to r-l/r as codegen tests (easy)
  5. Write a block post/article for https://blog.rust-lang.org/inside-rust/

GPU offload

  1. 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.
  2. 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 7840U unfortunately turned out to be not supported by AMD drivers.
  3. 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!
  4. 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.

Getting Rust for Linux into stable Rust: compiler features (rust-lang/rust-project-goals#407)
Progress
Point of contact

Tomas Sedovic

Champions

compiler (Wesley Wiser)

Task owners

(depending on the flag)

1 detailed update available.

Comment by [Tomas Sedovic][] posted on 2025-11-19:

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).

Getting Rust for Linux into stable Rust: language features (rust-lang/rust-project-goals#116)
Progress
Point of contact

Tomas Sedovic

Champions

lang (Josh Triplett), lang-docs (TC)

Task owners

Ding Xiang Fei

1 detailed update available.

Comment by [Tomas Sedovic][] posted on 2025-11-19:

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.

Implement Open API Namespace Support (rust-lang/rust-project-goals#256)
Progress
Point of contact

Help Wanted

Champions

cargo (Ed Page), compiler (b-naber), crates-io (Carol Nichols)

Task owners

b-naber, Ed Page

No detailed updates available.
MIR move elimination (rust-lang/rust-project-goals#396)
Progress
Point of contact

Amanieu d'Antras

Champions

lang (Amanieu d'Antras)

Task owners

Amanieu d'Antras

1 detailed update available.

Comment by [Amanieu d'Antras][] posted on 2025-11-15:

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.

Prototype a new set of Cargo "plumbing" commands (rust-lang/rust-project-goals#264)
Progress
Point of contact

Help Wanted

Task owners

Help wanted, Ed Page

No detailed updates available.
Prototype Cargo build analysis (rust-lang/rust-project-goals#398)
Progress
Point of contact

Weihang Lo

Champions

cargo (Weihang Lo)

Task owners

Help wanted Weihang Lo, Weihang Lo

1 detailed update available.

Comment by [Weihang Lo][] posted on 2025-11-04:

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.

reflection and comptime (rust-lang/rust-project-goals#406)
Progress
Point of contact

Oliver Scherer

Champions

compiler (Oliver Scherer), lang (Scott McMurray), libs (Josh Triplett)

Task owners

oli-obk

1 detailed update available.

Comment by [Niko Matsakis][] posted on 2025-11-12:

Another related PR:

https://github.com/rust-lang/rust/pull/148820

Rework Cargo Build Dir Layout (rust-lang/rust-project-goals#401)
Progress
Point of contact

Ross Sullivan

Champions

cargo (Weihang Lo)

Task owners

Ross Sullivan

1 detailed update available.

Comment by [Ross Sullivan][] posted on 2025-11-21:

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.

Run more tests for GCC backend in the Rust's CI (rust-lang/rust-project-goals#402)
Progress Completed
Point of contact

Guillaume Gomez

Champions

compiler (Wesley Wiser), infra (Marco Ieni)

Task owners

Guillaume Gomez

1 detailed update available.

Comment by [Guillaume Gomez][] posted on 2025-11-19:

This project goal has been completed. I updated the first issue to reflect it. Closing the issue then.

Rust Stabilization of MemorySanitizer and ThreadSanitizer Support (rust-lang/rust-project-goals#403)
Progress
Point of contact

Jakob Koschel

Task owners

[Bastian Kersting](https://github.com/1c3t3a), [Jakob Koschel](https://github.com/jakos-sec)

1 detailed update available.

Comment by [Jakob Koschel][] posted on 2025-11-21:

We've had a bunch of discussions and I opened a MCP (link, zulip).

I think the final sentiment was creating new targets for the few sanitizers and platforms that are critical. I'm in the process of prototyping something to get new feedback on it.

Rust Vision Document (rust-lang/rust-project-goals#269)
Progress
Point of contact

Niko Matsakis

Task owners

vision team

1 detailed update available.

Comment by [Niko Matsakis][] posted on 2025-11-05:

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).

rustc-perf improvements (rust-lang/rust-project-goals#275)
Progress
Point of contact

James

Champions

compiler (David Wood), infra (Jakub Beránek)

Task owners

James, Jakub Beránek, David Wood

1 detailed update available.

Comment by [Jakub Beránek][] posted on 2025-11-19:

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.

Stabilize public/private dependencies (rust-lang/rust-project-goals#272)
Progress
Point of contact

Help Wanted

Champions

cargo (Ed Page)

Task owners

Help wanted, Ed Page

No detailed updates available.
Stabilize rustdoc `doc_cfg` feature (rust-lang/rust-project-goals#404)
Progress
Point of contact

Guillaume Gomez

Champions

rustdoc (Guillaume Gomez)

Task owners

Guillaume Gomez

No detailed updates available.
SVE and SME on AArch64 (rust-lang/rust-project-goals#270)
Progress
Point of contact

David Wood

Champions

compiler (David Wood), lang (Niko Matsakis), libs (Amanieu d'Antras)

Task owners

David Wood

1 detailed update available.

Comment by [Niko Matsakis][] posted on 2025-11-05:

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 ^SizeOfVal sigil 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: SizeOfVal sort of made sense, but it would not compose well if we add additional families of "opt-out" traits like Destruct and Forget, 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

#![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 }

and 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&lt;T: ?Sized&gt; DoThing for T {
        default fn do_thing() {}
    }
    
    impl&lt;T: Sized&gt; 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.

Type System Documentation (rust-lang/rust-project-goals#405)
Progress
Point of contact

Boxy

Champions

types (Boxy)

Task owners

Boxy, lcnr

1 detailed update available.

Comment by [Boxy][] posted on 2025-11-05:

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
    • 'erased regions 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, Fn bounds are somewhat special in relation to this
    • opaques inheriting late bound function parameters
  • non opaque type, impl Trait
    • RPITIT in traits desugaring
    • impl Trait in 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
  • 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::Infer in ty overview
  • generalization
  • coroutines
    • deferred coroutine obligations
    • witness types?
    • why -Zhigher-ranked-assumptions exists
  • 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

Jack Wrenn

Champions

compiler (Jack Wrenn), lang (Scott McMurray)

Task owners

Jacob Pratt, Jack Wrenn, Luca Versari

No detailed updates available.