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-12-18:
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

5 detailed updates available.

Comment by [Benno Lossin][] posted on 2025-12-07:

Since we have chosen virtual places as the new approach, we reviewed what open questions are most pressing for the design. Our discussion resulted in the following five questions:

  1. Should we have 1-level projections xor multi-level projections?
  2. What is the semantic meaning of the borrow checker rules (BorrowKind)?
  3. How should we add "canonical projections" for types such that we have nice and short syntax (like x~y or x.@y)?
  4. What to do about non-indirected containers (Cell, MaybeUninit, Mutex, etc)?
  5. How does one inspect/query Projection types?

We will focus on these questions in December as well as implementing FRTs.

Comment by [Benno Lossin][] posted on 2025-12-12:

Canonical Projections

We have discussed canonical projections and come up with the following solution:

#![allow(unused)]
fn main() {
pub trait CanonicalReborrow: HasPlace {
    type Output<'a, P: Projection<Source = Self::Target>>: HasPlace<Target = P::Target>
    where
        Self: PlaceBorrow<'a, P, Self::Output<'a, P>>;
}
}

Implementing this trait permits using the syntax @$place_expr where the place's origin is of the type Self (for example @x.y where x: Self and y is an identifier or tuple index, or @x.y.z etc). It is desugared to be:

#![allow(unused)]
fn main() {
@<<Self as CanonicalReborrow>::Output<'_, projection_from_place_expr!($place_expr)>> $place_expr
}

(The names of the trait, associated type and syntax are not final, better suggestions welcome.)

Reasoning

  • We need the Output associated type to support the @x.y syntax for Arc and ArcRef.
  • We put the FRT and lifetime parameter on Output in order to force implementers to always provide a canonical reborrow, so if @x.a works, then @x.b also works (when b also is a field of the struct contained by x).
    • This (sadly or luckily) also has the effect that making @x.a and @x.b return different wrapper types is more difficult to implement and requires a fair bit of trait dancing. We should think about discouraging this in the documentation.
Comment by [Benno Lossin][] posted on 2025-12-16:

Non-Indirected Containers

Types like MaybeUninit<T>, Cell<T>, ManuallyDrop<T>, RefCell<T> etc. currently do not fit into our virtual places model, since they don't have an indirection. They contain the place directly inline (and some are even repr(transparent)). For this reason, we currently don't have projections available for &mut MaybeUninit<T>.

Enter our new trait PlaceWrapper which these types implement in order to make projections available for them. We call these types place wrappers. Here is the definition of the trait:

#![allow(unused)]
fn main() {
pub unsafe trait PlaceWrapper<P: Projection<Source = Self::Target>>: HasPlace {
    type WrappedProjection: Projection<Source = Self>;

    fn wrap_projection(p: P) -> Self::WrappedProjection;
}
}

This trait should only be implemented when Self doesn't contain the place as an indirection (so for example Box must not implement the trait). When this trait is implemented, then Self has "virtual fields" available (actually all kinds of place projections). The name of these virtual fields/projections is the same as the ones of the contained place. But their output type is controlled by this trait.

As an example, here is the implementation for MaybeUninit:

#![allow(unused)]
fn main() {
impl<T, P: Projection<Source = T>> PlaceWrapper<P> for MaybeUninit<T> {
    type WrappedProjection = TransparentProjection<P, MaybeUninit<T>, MaybeUninit<P::Target>>;

    fn wrap_projection(p: P) -> Self::WrappedProjection {
        TransparentProjection(p, PhantomData, PhantomData)
    }
}
}

Where TransparentProjection will be available in the standard library defined as:

#![allow(unused)]
fn main() {
pub struct TransparentProjection<P, Src, Tgt>(P, PhantomData<Src>, PhantomData<Tgt>);

impl<P: Projection, Src, Tgt> Projection for TransparentProjection<P, Src, Tgt> {
    type Source = Src;
    type Target = Tgt;

    fn offset(&self) -> usize {
        self.0.offset()
    }
}
}

When there is ambiguity, because the wrapper and the wrapped types both have the same field, the wrapper's field takes precedence (this is the same as it currently works for Deref). It is still possible to refer to the wrapped field by first dereferencing the container, so x.field refers to the wrapper's field and (*x).field refers to the field of the wrapped type.

Comment by [Benno Lossin][] posted on 2025-12-20:

Field-by-Field Projections vs One-Shot Projections

We have used several different names for these two ways of implementing projections. The first is also called 1-level projections and the second multi-level projections.

The field-by-field approach uses field representing types (FRTs), which represent a single field of a struct with no indirection. When writing something like @x.y.z, we perform the place operation twice, first using the FRT field_of!(X, y) and then again with field_of!(T, z) where T is the resulting type of the first projection.

The second approach called one-shot projections instead extends FRTs with projections, these are compositions of FRTs, can be empty and dynamic. Using these we desugar @x.y.z to a single place operation.

Field-by-field projections have the advantage that they simplify the implementation for users of the feature, the compiler implementation and the mental model that people will have to keep in mind when interacting with field projections. However, they also have pretty big downsides, which either are fundamental to their design or would require significant complification of the feature:

  • They have less expressiveness than one-shot projections. For example, when moving out a subsubfield of x: &own Struct by doing let a = @x.field.a, we have to move out field, which prevents us from later writing let b = @x.field.b. One-shot projections allow us to track individual subsubfields with the borrow checker.
  • Field-by-field projections also make it difficult to define type-changing projections in an inference friendly way. Projecting through multiple fields could result in several changes of types in between, so we would have to require only canonical projections in certain places. However, this requires certain intermediate types for which defining their safety invariants is very complex.

We additionally note that the single function call desugaring is also a simplification that also lends itself much better when explaining what the @ syntax does.

All of this points in the direction of proceeding with one-shot projections and we will most likely do that. However, we must note that the field-by-field approach might yield easier trait definitions that make implementing the various place operations more manageable. There are several open issues on how to design the field-by-field API in the place variation (the previous proposal did have this mapped out clearly, but it does not translate very well to places), which would require significant effort to solve. So at this point we cannot really give a fair comparison. Our initial scouting of the solutions revealed that they all have some sort of limitation (as we explained above for intermediate projection types for example), which make field-by-field projections less desirable. So for the moment, we are set on one-shot projections, but when the time comes to write the RFC we need to revisit the idea of field-by-field projections.

Comment by [Benno Lossin][] posted on 2025-12-25:

Wiki Project

We started a wiki project at https://rust-lang.github.io/beyond-refs to map out the solution space. We intend to grow it into the single source of truth for the current state of the field projection proposal as well as unfinished and obsolete ideas and connections between them. Additionally, we will aim to add the same kind of information for the in-place initialization effort, since it has overlap with field projections and, more importantly, has a similarly large solution space.

In the beginning you might find many stub pages in the wiki, which we will work on making more complete. We will also mark pages that contain old or abandoned ideas as such as well as mark the current proposal.

This issue will continue to receive regular detailed updates, which are designed for those keeping reasonably up-to-date with the feature. For anyone out of the loop, the wiki project will be a much better place when it contains more content.

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-12-17:

Purpose

A refresher on what we want to achieve here: the most basic form of reborrowing we want to enable is this:

#![allow(unused)]
fn main() {
// Note: not Clone or Copy
#[derive(Reborrow)]
struct MyMutMarker<'a>(...);

// ...

let marker: MyMarkerMut = MyMutMarker::new();
some_call(marker);
some_call(marker);
}

ie. make it possible for an owned value to be passed into a call twice and have Rust inject a reborrow at each call site to produce a new bitwise copy of the original value for the passing purposes, and mark the original value as disabled for reads and writes for the duration of the borrow.

A notable complication appears with implementing such reborrowing in userland using explicit cals when dealing with returned values:

#![allow(unused)]
fn main() {
return some_call(marker.reborrow());
}

If the borrowed lifetime escapes through the return value, then this will not compile as the borrowed lifetime is based on a value local to this function. Alongside convenience, this is the major reason for the Reborrow traits work.

CoerceShared is a secondary trait that enables equivalent reborrowing that only disables the original value for writes, ie. matching the &mut T to &T coercion.

Update

We have the Reborrow trait working, albeit currently with a bug in which the marker must be bound as let mut. We are working towards a working CoerceShared trait in the following form:

#![allow(unused)]
fn main() {
trait CoerceShared<Target: Copy> {}
}

Originally the trait had a type Target ADT but this turned out to be unnecessary, as there is no reason to particularly disallow multiple coercion targets. The original reason for using an ADT to disallow multiple coercion targets was based on the trait also having an unsafe method, at which point unscrupulous users could use the trait as a generic coercion trait. Because the trait method was found to be unnecessary, the fear is also unnecessary.

This means that the trait has better chances of working with multiple coercing lifetimes (think a collection of &muts all coercing to &s, or only some of them). However, we are currently avoiding any support of multiple lifetimes as we want to avoid dealing with rmeta before we have the basic functionality working.

"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

1 detailed update available.

Comment by [David Wood][] posted on 2025-12-15:

rust-lang/rfcs#3873 is waiting on one checkbox before entering the final comment period. We had our sync meeting on the 11th and decided that we would enter FCP on rust-lang/rfcs#3874 and rust-lang/rfcs#3875 after rust-lang/rfcs#3873 is accepted. We've responded to almost all of the feedback on the next two RFCs and expect the FCP to act as a forcing-function so that the relevant teams take a look, they can always register concerns if there are things we need to address, and if we need to make any major changes then we'll restart the FCP.

Production-ready cranelift backend (rust-lang/rust-project-goals#397)
Progress Will not complete
Point of contact

Folkert de Vries

Champions

compiler (bjorn3)

Task owners

bjorn3, Folkert de Vries, [Trifecta Tech Foundation]

1 detailed update available.

Comment by [Folkert de Vries][] posted on 2025-12-01:

We did not receive the funding we needed to work on this goal, so no progress has been made.

Overall I think the improvements we felt comfortable promising are on the low side. Overall the amount of time spent in codegen for realistic changes to real code bases was smaller than expected, meaning that the improvements that cranelift can deliver for the end-user experience are smaller.

We still believe larger gains can be made with more effort, but did not feel confident in promising hard numbers.

So for now, let's close this.

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 Will not complete
Point of contact

Jane Lusby

Champions

cargo (Weihang Lo), compiler (Oliver Scherer)

Task owners

@dropbear32, @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

No detailed updates available.
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-12-15:

Key developments

  • A fence length limit was added in response to T-lang feedback (https://github.com/rust-lang/rust/pull/149358)
  • Whether to disallow or lint for CR inside of a frontmatter is under discussion (https://github.com/rust-lang/rust/pull/149823)

Blockers

  • https://github.com/rust-lang/rust/pull/146377
  • 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

1 detailed update available.

Comment by [Taylor Cramer][] posted on 2025-12-17:

Current status:

  • The RFC for auto impl supertraits has been updated to address SemVer compatibility issues.
  • There is a parsing PR kicking off an experimental implementation. The tracking issue for this experimental implementation is here.
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

No detailed updates available.
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-12-15:

We've continued to fix a bunch of smaller issues over the last month. Tim (Theemathas Chirananthavat) helped uncover a new potential issue due to non-fatal overflow which we'll have to consider before stabilizing the new solver: https://github.com/rust-lang/trait-system-refactor-initiative/issues/258.

I fixed two issues myself in https://github.com/rust-lang/rust/pull/148823 and https://github.com/rust-lang/rust/pull/148865.

tiif with help by Boxy fixed query cycles when evaluating constants in where-clauses: https://github.com/rust-lang/rust/pull/148698.

@adwinwhite fixed a subtle issues involving coroutine witnesses in https://github.com/rust-lang/rust/pull/149167 after having diagnosed the underlying issue there last month. They've also fixed a smaller diagnostics issue in https://github.com/rust-lang/rust/pull/149299. Finally, they've also fixed an edge case of impl well-formedness checking in https://github.com/rust-lang/rust/pull/149345.

Shoyu Vanilla fixed a broken interaction of aliases and fudging in https://github.com/rust-lang/rust/pull/149320. Looking into fudging and HIR typeck Expectation handling also uncovered a bunch of broken edge-cases and I've openedhttps://github.com/rust-lang/rust/issues/149379 to track these separately.

I have recently spent some time thinking about the remaining necessary work and posted a write-up on my personal blog: https://lcnr.de/blog/2025/12/01/next-solver-update.html. I am currently trying to get a clearer perspective on our cycle handling while slowly working towards an RFC for the changes there. This is challenging as we don't have a good theoretical foundation here yet.

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 Completed
Point of contact

Guillaume Gomez

Champions

rustdoc (Guillaume Gomez)

No detailed updates available.
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

4 detailed updates available.

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

PR https://github.com/rust-lang/a-mir-formality/pull/206 contains a "first draft" for the NLL rules. It checks for loan violations (e.g., mutating borrowed data) as well as some notion of outlives requirements. It does not check for move errors and there aren't a lot of tests yet.

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

The PR also includes two big improvements to the a-mir-formality framework:

  • support for (for_all) rules that can handle "iteration"
  • tracking proof trees, making it much easier to tell why something is accepted that should not be
Comment by [Niko Matsakis][] posted on 2025-12-10:

Update: opened https://github.com/rust-lang/a-mir-formality/pull/207 which contains support for &mut, wrote some new tests (including one FIXME), and added a test for NLL Problem Case #3 (which behaved as expected).

One interesting thing (cc Ralf Jung) is that we have diverged from MiniRust in a few minor ways:

  • We do not support embedding value expressions in place expressions.
  • Where MiniRust has a AddrOf operator that uses the PtrType to decide what kind of operation it is, we have added a Ref MIR operation. This is in part because we need information that is not present in MiniRust, specifically a lifetime.
  • We have also opted to extend goto with the ability to take multiple successors, so that goto b1, b2 can be seen as "goto either b1 or b2 non-deterministically" (the actual opsem would probably be to always go to b1, making this a way to add "fake edges", but the analysis should not assume that).
Comment by [Niko Matsakis][] posted on 2025-12-17:

Update: opened https://github.com/rust-lang/a-mir-formality/pull/210 with today's work. We are discussing how to move the checker to support polonius-alpha. To that end, we introduced feature gates (so that a-mir-formality can model nightly features) and did some refactoring of the type checker aiming at allowing outlives to become flow-sensitive.

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

2 detailed updates available.

Comment by [Boxy][] posted on 2025-12-30:

Since the last update both of my PRs I mentioned have landed, allowing for constructing ADTs in const arguments while making use of generic parameters. This makes MGCA effectively a "full" prototype where it can now fully demonstrate the core concept of the feature. There's still a lot of work left to do but now we're at the point of finishing out the feature :)

Once again huge thanks to camelid for sticking with me throughout this. Also thanks to errs, oli and lcnr for reviewing some of the work and chatting with me about possible impl decisions.

Some examples of what is possible with MGCA as of the end of this goal cycle:

#![allow(unused)]
#![feature(const_default, const_trait_impl, min_generic_const_args)]

fn main() {
trait Trait {
    #[type_const]
    const ASSOC: usize;
}

fn mk_array<T: const Default + Trait>() -> [T; T::ASSOC] {
    [const { T::default() }; _]
}
}
#![allow(unused)]
#![feature(adt_const_params, min_generic_const_args)]

fn main() {
fn foo<const N: Option<u32>>() {}

trait Trait {
    #[type_const]
    const ASSOC: usize;
}

fn bar<T: Trait, const N: u32>() {
    // the initializer of `_0` is a `N` which is a legal const argument
    // so this is ok.
    foo::<{ Some::<u32> { 0: N } }>();

    // this is allowed as mgca supports uses of assoc consts in the
    // type system. ie `<T as Trait>::ASSOC` is a legal const argument
    foo::<{ Some::<u32> { 0: <T as Trait>::ASSOC } }>();

    // this on the other hand is not allowed as `N + 1` is not a legal
    // const argument
    foo::<{ Some::<u32> { 0: N + 1 } }>(); // ERROR
}
}

As for adt_const_params we now have a zulip stream specifically for discussion of the upcoming RFC and the drafting of the RFC: #project-const-generics/adt_const_params-rfc. I've gotten part of the way through actually writing the RFC itself though it's gone slower than I had originally hoped as I've also been spending more time thinking through the implications of allowing private data in const generics.

I've debugged the remaining two ICEs making adt_const_params not fully ready for stabilization and written some brief instructions on how to resolve them. One ICE has been incidentally fixed (though more masked) by some work that Kivooeo has been doing on MGCA. The other has been picked up by someone I'm not sure the github handle of so that will also be getting fixed soon.

Comment by [Boxy][] posted on 2025-12-30:

Ah I forgot to mention, even though MGCA has a tonne of work left to do I expect it should be somewhat approachable for people to help out with. So if people are interested in getting involved now is a good time :)

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

No detailed updates available.
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

1 detailed update available.

Comment by [Pete LeVasseur][] posted on 2025-12-16:

Meeting notes here: FLS team meeting 2025-12-12

Key developments: We're close to completing the FLS release for 1.91.0, 1.91.1. We've started to operate as a team, merging a PR with the changelog entries, then opening up issues for each change required: ✅ #624(https://github.com/rust-lang/fls/issues/624), ✅ #625(https://github.com/rust-lang/fls/issues/625), ✅ #626(https://github.com/rust-lang/fls/issues/626), ⚠️ #623(https://github.com/rust-lang/fls/issues/623). #623(https://github.com/rust-lang/fls/issues/623) is still pending, as it requires a bit of alignment with the Reference on definitions and creation of a new example. Blockers: None currently Help wanted: We'd love more folks from the safety-critical community to contribute to picking up issues or opening an issue if you notice something is missing.

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-12-16:

Here's our December status update!

  • We have revised our prototype of the pre-RFC based on Ralf Jung's feedback. Now, instead of having two different retag functions for operands and places, we emit a single __rust_retag intrinsic in every situation. We also track interior mutability precisely. At this point, the implementation is mostly stable and seems to be ready for an MCP.

  • There's been some discussion here and in the pre-RFC about whether or not Rust will still have explicit MIR retag statements. We plan on revising our implementation so that we no longer rely on MIR retags to determine where to insert our lower-level retag calls. This should be a relatively straightforward change to the current prototype. If anything, it should make these changes easier to merge upstream, since they will no longer affect Miri.

  • BorrowSanitizer continues to gain new features, and we've started testing it on our first real crate (lru) (which has uncovered a few new bugs in our implementation). The two core Tree Borrows features that we have left to support are error reporting and garbage collection. Once these are finished, we will be able to expand our testing to more real-world libraries and confirm that we are passing each of Miri's test cases (and likely find more bugs lurking in our implementation). Our instrumentation pass ignores global and thread-local state for now, and it does not support atomic memory accesses outside of atomic load and store instructions. These operations should be relatively straightforward to add once we've finished higher-priority items.

  • Performance is slow. We do not know exactly how slow yet, since we've been focusing on feature support over benchmarking and optimization. This is at least partially due to the lack of garbage collection, based on what we're seeing from profiling. We will have a better sense of what our performance is like once we can compare against Miri on more real-world test cases.

As for what's next, we plan on posting an MCP soon, now that it's clear that we will be able to do without MIR retags. You can expect a more detailed status update on BorrowSanitizer by the end of January. This will discuss our implementation and plans for 2026. We will post that here and on our project website.

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-12-17:

In addition to further ongoing work on reference material (some of which is on track to be merged), we've had some extensive discussions about reference processes, maintenance, and stability markers. Niko Matsakis is putting together a summary and proposal for next steps.

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

No detailed updates available.
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

2 detailed updates available.

Comment by [Manuel Drehwald][] posted on 2025-12-02:

It's only been two weeks, but we got a good number of updates, so I already wanted to share them.

autodiff

  1. On the autodiff side, we landed the support for rlib and better docs. This means that our autodiff frontend is "almost" complete, since there are almost no cases left where you can't apply autodiff. There are a few features like custom-derivatives or support for dyn arguments that I'd like to add, but they are currently waiting for better docs on the Enzyme side. There is also a long-term goal off replacing the fat-lto requirement with the less invasive embed-bc requirement, but this proved to be tricky in the past and only affects compile times.
  2. @sgasho picked up my old PR to dlopen enzyme, and found the culprit of it failing after my last rebase. A proper fix might take a bit longer, but it might be worth waiting for. As a reminder, using dlopen in the future allows us to ship autodiff on nightly without increasing the size of rustc and therefore without making our infra team sad.

All in all, we have landed most of the hard work here, so that's a very comfortable position to be in before enabling it on nightly.

offload

  1. We have landed the intrinsic implementation of Marcelo Domínguez, so now you can offload functions with almost arbitrary arguments. In my first prototype, I had limited it to pointers to 256 f64 values. The updated usage example continues to live here in our docs. As you can see, we still require #[cfg(target_os=X)] annotations. Under the hood, the LLVM-IR which we generate is also still a bit convoluted. In his next PRs, he'll clean up the generated IR, and introduce an offload macro that users shall call instead of the internal offload intrinsic.
  2. I spend more time on enabling offload in our CI, to enable std::offload in nightly. After multiple iterations and support from LLVM offload devs, we found a cmake config that does not run into bugs, should not increase Rust CI time too much, and works with both in-tree llvm/clang builds, as well as external clang's (the current case in our Rust CI).
  3. I spend more time on simplifying the usage instructions in the dev guide. We started with two cargo calls, one rustc call, two clang calls, and two clang-helper binary calls. I was able to remove the rustc and one of the clang-offload-packager calls, by directly calling the underlying LLVM APIs. I also have an unmerged PR which removes the two clang calls. Once I cleaned it up and landed it, we would be down to only two cargo calls and one binary call to clang-linker-wrapper. Once I automated this last wrapper (and enabled offload in CI), nightly users should be able to experiment with std::offload.
Comment by [Manuel Drehwald][] posted on 2025-12-26:

Time for the next round of updates. Again, most of the updates were on the GPU side, but with some notable autodiff improvements too.

autodiff:

  1. @sgasho finished his work on using dlopen to load enzyme and the pr landed. This allowed Jakub Beránek and me to start working on distributing Enzyme via a standalone component.

  2. As a first step, I added a nicer error if we fail to find or dlopen our Enzyme backend. I also removed most of our autodiff fallbacks, we now unconditionally enable our macro frontend on nightly: https://github.com/rust-lang/rust/pull/150133 You may notice that cargo expand now works on autodiff code. This also allowed the first bug reports about ICE (internal compiler error) in our macro parser logic.

  3. Kobzol opened a PR to build Enzyme in CI. In theory, I should have been able to download that artifact, put it into my sysroot, and use the latest nightly to automatically load it. If that had worked, we could have just merged his PR, and everyone could have started using AD on nightly. Of course, things are never that easy. Even though both Enzyme, LLVM, and rustc were built in CI, the LLVM version shipped along with rustc does not seem compatible with the LLVM version Enzyme was built against. We assume some slight cmake mismatch during our CI builds, which we will have to debug.

offload:

  1. On the gpu side, Marcelo Domínguez finished his cleanup PR, and along the way also fixed using multiple kernels within a single codebase. When developing the offload MVP I had taken a lot of inspiration from the LLVM-IR generated by clang - and it looks like I had gotten one of the (way too many) LLVM attributes wrong. That caused some metadata to be fused when multiple kernels are present, confusing our offload backend. We started to find more bugs when working on benchmarks, more about the fixes for those in the next update.

  2. I finished cleaning up my offload build PR, and Oliver Scherer reviewed and approved it. Once the dev-guide gets synced, you should see much simpler usage instructions. Now it's just up to me to automate the last part, then you can compile offload code purely with cargo or rustc. I also improved how we build offload, which allows us to build it both in CI and locally. CI had some very specific requirements to not increase build times, since our x86-64-dist runner is already quite slow.

  3. Our first benchmarks directly linked against NVIDIA and AMD intrinsics on llvm-ir level. However, we already had an nvptx Rust module for a while, and since recently also an amdgpu module which nicely wraps those intrinsics. I just synced the stdarch repository into rustc a few minutes ago, so from now on, we can replace both with the corresponding Rust functions. In the near future we should get a higher level GPU module, which abstracts away naming differences between vendors.

  4. Most of my past rustc contributions were related to LLVM projects or plugins (Offload and Enzyme), and I increasingly encountered myself asking other people for updates or backports of our LLVM submodule, since upstream LLVM has fixes which were not yet merged into our LLVM submodule. Our llvm working group is quite small and I didn't want to burden them too much with my requests, so I recently asked them to join it, which also got approved. In the future I intend to help a little with the maintenance here.

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-12-05:

Update from the 2025-12-03 meeting:

-Zharden-sls

Wesley reviewed it again, provided a qualification, more changes requested.

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

2 detailed updates available.

Comment by [Tomas Sedovic][] posted on 2025-12-05:

Update from the 2025-12-03 meeting.

Deref / Receiver

Ding keeps working on the Reference draft. The idea is still not well-proliferated and people are not convinced this is a good way to go. We hope the method-probing section in Reference PR could clear thins up.

We're keeping the supertrait auto-impl experiment as an alternative.

RFC #3851: Supertrait Auto-impl

Ding addressed Predrag's requests on SemVer compatibility. He's also opened an implementation PR: https://github.com/rust-lang/rust/pull/149335. Here's the tracking issue: https://github.com/rust-lang/rust/issues/149556.

derive(CoercePointee)

Ding opened a PR to require additional checks for DispatchFromDyn: https://github.com/rust-lang/rust/pull/149068

In-place initialization

Ding will prepare material for a discussion at the LPC (Linux Plumbers Conference). We're looking to hear feedback on the end-user syntax for it.

The feature is going quite large, Ding will check with Tyler on the whether this might need a series of RFCs.

The various proposals on the table continue being discussed and there are signs (albeit slow) of convergence. The placing function and guaranteed return ones are superseded by outpointer. The more ergonomic ideas can be built on top. The guaranteed value placement one would be valuable in the compiler regardless and we're waiting for Olivier to refine it.

The feeling is that we've now clarified the constraints that the proposals must operate under.

Field projections

Nadri's Custom places proposal is looking good at least for the user-facing bits, but the whole thing is growing into a large undertaking. Benno's been focused on academic work that's getting wrapped up soon. The two will sync afterwards.

Comment by [Tomas Sedovic][] posted on 2025-12-18:

Quick bit of great news: Rust in the Linux kernel is no longer treated as an experiment, it's here to stay 🎉

https://lwn.net/SubscriberLink/1050174/63aa7da43214c3ce/

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

3 detailed updates available.

Comment by @sladyn98 posted on 2025-12-03:

Ed Page hey i would like to contribute to this I reached out on zulip. Bumping up the post in case it might have gone under the radar

CC Niko Matsakis

Comment by [Ed Page][] posted on 2025-12-03:

The work is more on the compiler side atm, so Eric Holk and b-naber could speak more to where they could use help.

Comment by [Eric Holk][] posted on 2025-12-06:

Hi @sladyn98 - feel free to ping me on Zulip about this.

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-12-17:

The RFC draft was reviewed in detail and Ralf Jung pointed out that the proposed semantics introduce issues because they rely on "no-behavior" (NB) with regards to choosing an address for a local. This can lead to surprising "time-traveling" behavior where the set of possible addresses that a local may have (and whether 2 locals can have the same address) depends on information from the future. For example:

#![allow(unused)]
fn main() {
// This program has DB
let x = String::new();
let xaddr = &raw const x;
let y = x; // Move out of x and de-initialize it.
let yaddr = &raw const y;
x = String::new(); // assuming this does not change the address of x
// x and y are both live here. Therefore, they can't have the same address.
assume(xaddr != yaddr);
drop(x);
drop(y);
}
#![allow(unused)]
fn main() {
// This program has UB
let x = String::new();
let xaddr = &raw const x;
let y = x; // Move out of x and de-initialize it.
let yaddr = &raw const y;
// So far, there has been no constraint that would force the addresses to be different.
// Therefore we can demonically choose them to be the same. Therefore, this is UB.
assume(xaddr != yaddr);
// If the addresses are the same, this next line triggers NB. But actually this next
// line is unreachable in that case because we already got UB above...
x = String::new();
// x and y are both live here.
drop(x);
drop(y);
}

With that said, there is still a possibility of achieving the optimization, but the scope will need to be scaled down a bit. Specifically, we would need to:

  • no longer perform a "partial free"/"partial allocation" when initializing or moving out of a single field of a struct. The lifetime of a local starts when any part of it is initialized and ends when it is fully moved out.
  • allow a local's address to change when it is re-initialized after having been fully moved out, which eliminates the need for NB.

This reduces the optimization opportunities since we can't merge arbitrary sub-field moves, but it still allows for eliminating moves when constructing a struct from multiple values.

The next step is for me to rework the RFC draft to reflect this.

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

2 detailed updates available.

Comment by [Weihang Lo][] posted on 2025-12-13:

Key developments: HTML replay logic has merge. Once it gets into nightly cargo report timings can open the timing report you have previously logged.

  • https://github.com/rust-lang/cargo/pull/16377
  • https://github.com/rust-lang/cargo/pull/16378
  • https://github.com/rust-lang/cargo/pull/16382

Blockers: No, except my own availability

Help wanted: Same as https://github.com/rust-lang/rust-project-goals/issues/398#issuecomment-3571897575

Comment by [Weihang Lo][] posted on 2025-12-26:

Key developments:

Headline: You should always enable build analysis locally, if you are using nightly and want the timing info data always available.

[unstable]
build-analysis = true

[build.analysis]
enabled = true
  • More log events are emitted: https://github.com/rust-lang/cargo/pull/16390
    • dependency resolution time
    • unit-graph construction
    • unit-registration (which contain unit metadata)
  • Timing replay from cargo report timings now has almost the same feature parity as cargo build --timings, except CPU usage: https://github.com/rust-lang/cargo/pull/16414
  • Rename rebuild event to unit-fingerprint, and is emitted also for fresh unit: https://github.com/rust-lang/cargo/pull/16408.
  • Proposed a new cargo report sessions command so that people can retrieve previous sessions IDs not use the latest one: https://github.com/rust-lang/cargo/pull/16428
  • Proposed to remove --timings=json which timing info in log files should be a great replacement: https://github.com/rust-lang/cargo/pull/16420
  • Documenting efforts for having man pages for nested commands `cargo report : https://github.com/rust-lang/cargo/pull/16430 and https://github.com/rust-lang/cargo/pull/16432

Besides implementations, we also discussed about:

  • The interaction of --message-format and structured logging system, as well as log event schemas and formats: https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/build.20analysis.20log.20format/with/558294271
  • A better name for RunId. We may lean towards SessionId which is a common name for logging/tracing ecosystem.
  • Nested Cargo calls to have a sticky session ID. At least a way to show they were invoked from the same top-level Cargo call.

Blockers: No, except my own availability

Help wanted: Same as https://github.com/rust-lang/rust-project-goals/issues/398#issuecomment-3571897575

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 [Oliver Scherer][] posted on 2025-12-15:

Updates

  • https://github.com/rust-lang/rust/pull/148820 adds a way to mark functions and intrinsics as only callable during CTFE
  • https://github.com/rust-lang/rust/pull/144363 has been unblocked and just needs some minor cosmetic work

Blockers

  • https://github.com/rust-lang/rust/pull/146923 (reflection MVP) has not been reviewed yet
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-12-23:

Status update December 23, 2025

The majority of December was spent iterating on https://github.com/rust-lang/cargo/pull/16155 . As mentioned in the previous update, the original locking design was not correct and we have been working through other solutions.

As locking is tricky to get right and there are many scenarios Cargo needs to support, we are trying to descope the initial implementation to an MVP, even if that means we lose some of the concurrency. Once we have an MVP on nightly, we can start gathering feedback on the scenarios that need improvement and iterate.

I'm hopeful that we get an unstable -Zfine-grain-locking on nightly in January for folks to try out in their workflows.


Also we are considering adding an opt-in for the new build-dir layout using an env var (CARGO_BUILD_DIR_LAYOUT_V2=true) to allow tool authors to begin migrating to the new layout. https://github.com/rust-lang/cargo/pull/16336

Before stabilizing this, we are doing crater run to test the impact of the changes and proactively reaching out to projects to minimize breakage as much as possible. https://github.com/rust-lang/rust/pull/149852

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

No detailed updates available.
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-12-15:

Based on the gathered feedback I opened a new MCP for the proposed new Tier 2 targets with sanitizers enabled. (https://github.com/rust-lang/compiler-team/issues/951)

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

Niko Matsakis

Task owners

vision team

No detailed updates available.
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-12-15:

We have enabled the second x64 machine, so we now have benchmarks running in parallel 🎉 There are some smaller things to improve, but next year we can move onto running benchmarks on Arm collectors.

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

1 detailed update available.

Comment by [Guillaume Gomez][] posted on 2025-12-17:

Opened stabilization PR but we have blockers I didn't hear of, so stabilization will be postponed until then.

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

3 detailed updates available.

Comment by [David Wood][] posted on 2025-12-15:

I haven't made any progress on Deref::Target yet, but I have been focusing on landing rust-lang/rust#143924 which has went through two rounds of review and will hopefully be approved soon.

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

Update: David and I chatted on Zulip. Key points:

David has made "progress on the non-Sized Hierarchy part of the goal, the infrastructure for defining scalable vector types has been merged (with them being Sized in the interim) and that'll make it easier to iterate on those and find issues that need solving".

On the Sized hierarchy part of the goal, no progress. We discussed options for migrating. There seem to be three big options:

(A) The conservative-but-obvious route where the T: Derefin the old edition is expanded to T: Deref<Target: SizeOfVal> (but in the new edition it means T: Deref<Target: Pointee>, i.e., no additional bounds). The main downside is that new Edition code using T: Deref can't call old Edition code using T: Deref as the old edition code has stronger bounds. Therefore new edition code must either use stronger bounds than it needs or wait until that old edition code has been updated.

(B) You do something smart with Edition.Old code where you figure out if the bound can be loose or strict by bottom-up computation. So T: Deref in the old could mean either T: Deref<Target: Pointee> or T: Deref<Target: SizeOfVal>, depending on what the function actually does.

(C) You make Edition.Old code always mean T: Deref<Target: Pointee> and you still allow calls to size_of_val but have them cause post-monomorphization errors if used inappropriately. In Edition.New you use stricter checking.

Options (B) and (C) have the downside that changes to the function body (adding a call to size_of_val, specifically) in the old edition can stop callers from compiling. In the case of Option (B), that breakage is at type-check time, because it can change the where-clauses. In Option (C), the breakage is post-monomorphization.

Option (A) has the disadvantage that it takes longer for the new bounds to roll out.

Given this, (A) seems the preferred path. We discussed options for how to encourage that roll-out. We discussed the idea of a lint that would warn Edition.Old code that its bounds are stronger than needed and suggest rewriting to T: Deref<Target: Pointee> to explicitly disable the stronger Edition.Old default. This lint could be implemented in one of two ways

  • at type-check time, by tracking what parts of the environment are used by the trait solver. This may be feasible in the new trait solver, someone from @rust-lang/types would have to say.
  • at post-mono time, by tracking which functions actually call size_of_val and propagating that information back to callers. You could then compare against the generic bounds declared on the caller.

The former is more useful (knowing what parts of the environment are necessary could be useful for more things, e.g., better caching); the latter may be easier or more precise.

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

Update to the previous post.

Tyler Mandry pointed me at this thread, where lcnr posted this nice blog post that he wrote detailing more about (C).

Key insights:

  • Because the use of size_of_val would still cause post-mono errors when invoked on types that are not SizeOfVal, you know that adding SizeOfVal into the function's where-clause bounds is not a breaking change, even though adding a where clause is a breaking change more generally.
  • But, to David Wood's point, it does mean that there is a change to Rust's semver rules: adding size_of_val would become a breaking change, where it is not today.

This may well be the best option though, particularly as it allows us to make changes to the defaults across-the-board. A change to Rust's semver rules is not a breaking change in the usual sense. It is a notable shift.

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-12-30:

This month I've written some documentation for how Const Generics is implemented in the compiler. This mostly covers the implementation of the stable functionality as the unstable features are quite in flux right now. These docs can be found here: https://rustc-dev-guide.rust-lang.org/const-generics.html

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.