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 17 project goals, with 6 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

3 detailed updates available.

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

Status update:

Comment by [Frank King][] posted on 2025-10-22:

Status update:

Regarding the TODO list in the next 6 months, here is the current status:

Introduce &pin mut|const place borrowing syntax

  • [x] parsing: #135731(https://github.com/rust-lang/rust/pull/135731), merged.
  • [ ] lowering and borrowck: not started yet.

I've got some primitive ideas about borrowck, and I probably need to confirm with someone who is familiar with MIR/borrowck before starting to implement.

A pinned borrow consists two MIR statements:

  1. a borrow statement that creates the mutable reference,
  2. and an adt aggregate statement that put the mutable reference into the Pin struct.

I may have to add a new borrow kind so that pinned borrows can be recognized. Then traverse the dataflow graph to make sure that pinned places cannot been moved.

Pattern matching of &pin mut|const T types

In the past few months, I have struggled with the !Unpin stuffs (the original design sketch Alternative A), trying implementing it, refactoring, discussing on zulips, and was constantly confused; luckily, we have finally reached a new agreement of the Alternative B version.

  • [ ] #139751(https://github.com/rust-lang/rust/pull/139751) under review (reimplemented regarding Alternative B).

Support drop(&pin mut self) for structually pinned types

  • [ ] adding a new Drop::pin_drop(&pin mut self) method: draft PR #144537(https://github.com/rust-lang/rust/pull/144537)

Supporting both Drop::drop(&mut self) and Drop::drop(&pin mut self) seems to introduce method-overloading to Rust, which I think might need some more general ways to handle (maybe by a rustc attribute?). So instead, I'd like to implemenent this via a new method Drop::pin_drop(&pin mut self) first.

Introduce &pin pat pattern syntax

Not started yet (I'd prefer doing that when pattern matching of &pin mut|const T types is ready).

Support &pin mut|const T -> &|&mut T coercion (requires T: Unpin of &pin mut T -> &mut T)

Not started yet. (It's quite independent, probably someone else can help with it)

Support auto borrowing of &pin mut|const place in method calls with &pin mut|const self receivers

Seems to be handled by Autoreborrow traits?

Progress
Point of contact

Aapo Alasuutari

Champions

compiler (Oliver Scherer), lang (Tyler Mandry)

Task owners

Aapo Alasuutari

3 detailed updates 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.

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.

Comment by [Aapo Alasuutari][] posted on 2025-10-22:

Initial implementation of a Reborrow trait for types with only lifetimes with exclusive reference semantics is working but not yet upstreamed not in review. CoerceShared implementation is not yet started.

Proper composable implementation will likely require a different tactic than the current one. Safety and validity checks are currently absent as well and will require more work.

"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

3 detailed updates 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.

Comment by [David Wood][] posted on 2025-11-22:

Our first RFC - rust-lang/rfcs#3873 - is in the FCP process, waiting on boxes being checked. rust-lang/rfcs#3874 and rust-lang/rfcs#3875 are receiving feedback which is being addressed.

Comment by [David Wood][] posted on 2025-10-31:

We've now opened our first batch of RFCs: rust-lang/rfcs#3873, rust-lang/rfcs#3874 and rust-lang/rfcs#3875

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.

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

1 detailed update available.

Comment by [Jane Lusby][] posted on 2025-11-21:

linking this here so people know why there hasn't been any progress on this project goal.

#t-compiler > 2025H2 Goal Review @ 💬

"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

3 detailed updates available.

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.

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-10-22:

Update:

There has been more discussion about the Handle trait on Zulip and elsewhere. Some of the notable comments:

  • Downsides of the current name: it's a noun, which doesn't follow Rust naming convention, and the verb handle is very generic and could mean many things.
  • Alternative names proposed: Entangle/entangle or entangled, Share/share, Alias/alias, or Retain/retain. if we want to seriously hardcore on the science names -- Mitose/mitose or Fission/fission.
  • There has been some criticism pointing out that focusing on handles means that other types which might be "cheaply cloneable" don't qualify.

For now I will go on using the term Handle, but I agree with the critique that it should be a verb, and currently prefer Alias/alias as an alternative.


I'm continuing to work my way through the backlog of blog posts about the conversations from Rustconf. The purposes of these blog posts is not just to socialize the ideas more broadly but also to help myself think through them. Here is the latest post:

https://smallcultfollowing.com/babysteps/blog/2025/10/13/ergonomic-explicit-handles/

The point of this post is to argue that, whatever else we do, Rust should have a way to create handles/clones (and closures that work with them) which is at once explicit and ergonomic.

To give a preview of my current thinking, I am working now on the next post which will discuss how we should add an explicit capture clause syntax. This is somewhat orthogonal but not really, in that an explicit syntax would make closures that clone more ergonomic (but only mildly). I don't have a proposal I fully like for this syntax though and there are a lot of interesting questions to work out. As a strawperson, though, you might imagine [this older proposal I wrote up](https://hackmd.io/Niko Matsakis/SyI0eMFXO?type=view), which would mean something like this:

#![allow(unused)]
fn main() {
let actor1 = async move(reply_tx.handle()) {
    reply_tx.send(...);
};
let actor2 = async move(reply_tx.handle()) {
    reply_tx.send(...);
};
}

This is an improvement on

#![allow(unused)]
fn main() {
let actor1 = {
    let reply_tx = reply_tx.handle();
    async move(reply_tx.handle()) {
        reply_tx.send(...);
    }
};
}

but only mildly.

The next post I intend to write would be a variant on "use, use everywhere" that recommends method call syntax and permitting the compiler to elide handle/clone calls, so that the example becomes

#![allow(unused)]
fn main() {
let actor1 = async move {
    reply_tx.handle().send(...);
    //       -------- due to optimizations, this would capture the handle creation to happen only when future is *created*
};
}

This would mean that cloning of strings and things might benefit from the same behavior:

#![allow(unused)]
fn main() {
let actor1 = async move {
    reply_tx.handle().send(some_id.clone());
    //                     -------- the `some_id.clone()` would occur at future creation time
};
}

The rationable that got me here is (a) minimizing perceived complexity and focusing on muscle memory (just add .clone() or .handle() to fix use-after-move errors, no matter when/where they occur). The cost of course is that (a) Handle/Clone become very special; and (b) it blurs the lines on when code execution occurs. Despite the .handle() occurring inside the future (resp. closure) body, it actually executes when the future (resp. closure) is created in this case (in other cases, such as a closure that implements Fn or FnMut and hence executes more than once, it might occur during each execution as well).

Goals looking for help


Other goal updates

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

1 detailed update available.

Comment by [Jon Bauman][] posted on 2025-11-26:

Key developments: What has happened since the last time. It's perfectly ok to list "nothing" if that's the truth, we know people get busy.

Nothing! This is the first update and I have yet to focus attention on the project goal. For context, I am employed by the Rust Foundation leading the C++ Interoperability initiative and so far have been executing against the strategy detailed in the problem statement. Owing to greater than anticipated success and deadlines related to WG21 meetings, I've been focusing on the Social Interoperability strategy recently. I have just reached a point where I can turn more attention to the other strategies and so expect to make progress on this goal soon.

Blockers: List any Rust teams you are waiting on and what you are waiting for.

None; I'm getting excellent support from the Project in everything I'm doing. My successes thus far would not have been possible without them, and there are too many to enumerate in this space. There will be a blog post coming soon detailing the past year of work in the initiative where I intend to go into detail. Watch this space for updates.

Help wanted: Are there places where you are looking for contribution or feedback from the broader community?

I am always interested in contribution and feedback. If you're interested, please reach out via interop@rustfoundation.org or t-lang/interop.

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

4 detailed updates available.

Comment by [Ian McCormack][] posted on 2026-01-09:

Here's our January status update!

  • Yesterday, we posted an MCP for our retag intrinsics. While that's in progress, we'll start adapting our current prototype to remove our dependence on MIR-level retags. Once that's finished, we'll be ready to submit a PR.

  • We published our first monthly blog post about BorrowSanitizer.

  • Our overall goal for 2026 is to transition from a research prototype to a functional tool. Three key features have yet to be implemented: garbage collection, error reporting, and support for atomic memory accesses. Once these are complete, we'll be able to start testing real-world libraries and auditing our results against Miri.

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.

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.

Comment by [Ian McCormack][] posted on 2025-10-25:

Here's our first status update!

  • We've been experimenting with a few different ways of emitting retags in codegen, as well as a few different forms that retags should take at this level. We think we've settled on a set of changes that's worth sending out to the community for feedback, likely as a pre-RFC. You can expect more engagement from us on this level in the next couple of weeks.

  • We've used these changes to create an initial working prototype for BorrowSanitizer that supports finding Tree Borrows violations in tiny, single-threaded Rust programs. We're working on getting Miri's test suite ported over to confirm that everything is working correctly and that we've quashed any false positives or false negatives.

  • This coming Monday, I'll be presenting on BorrowSanitizer and this project goal at the Workshop on Supporting Memory Safety in LLVM. Please reach out if you're attending and would like to chat more in person!

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

4 detailed updates available.

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.

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

Comment by [Manuel Drehwald][] posted on 2025-10-22:

A longer update of the changes over the fall. We had two gsoc contributors and a lot of smaller improvements for std::autodiff. The first two improvements were already mentioned as draft PRs in the previous update, but got merged since. I also upstreamed more std::offload changes.

  1. Marcelo Domínguez refactored the autodiff frontend to be a proper rustc intrinsic, rather than just hackend into the frontend like I first implemented it. This already solved multiple open issues, reduced the code size, and made it generally easier to maintain going forward.
  2. Karan Janthe upstreamed a first implementation of "TypeTrees", which lowers rust type and layout information to Enzyme, our autodiff backend. This makes it more likely that you won't see compilation failures with the error message "Can not deduce type of ". We might refine in the future what information exactly we lower.
  3. Karan Janthe made sure that std::autodiff has support for f16 and and f128 types.
  4. One more of my offload PRs landed. I also figured out why the LLVM-IR generated by the std::offload code needed some manual adjustments in the past. We were inconsistent when communicating with LLVM's offload module, about whether we'd want a magic, extra, dyn_ptr argument, that enables kernels to use some extra features. We don't use these features yet, but for consistency we now always generate and expect the extra pointer. The bugfix is currently under review, once it lands upstream, rustc is able to run code on GPUs (still with a little help of clang).
  5. Marcelo Domínguez refactored my offload frontend, again introducing a proper rustc intrinsic. That code will still need to go through review, but once it lands it will get us a lot closer to a usable frontend. He also started to generate type information for our offload backend to know how many bytes to copy to and from the devices. This is a very simplified version of our autodiff typetrees.
  6. At RustChinaConf, I was lucky to run into the wild linker author David Lattimore, which helped me to create a draft PR that can dlopen Enzyme at runtime. This means we could ship it via rustup for people interested in std::autodiff, and don't have to link it in at build time, which would increase binary size even for those users that are not interested in it. There are some open issues, so please reach out if you have time to get the PR ready!
  7. @sgasho spend a lot of time trying to get Rust into the Enzyme CI. Unfortunately that is a tricky process due to Enzyme's CI requirements, so it's not merged yet.
  8. I tried to simplify building std::autodiff by marking it as compatible with download-llvm-ci. Building LLVM from source was previously the by far slowest part of building rustc with autodiff, so this has a large potential. Unfortunately the CI experiments revealed some issues around this setting. We think we know why Enzyme's Cmake causes issues here and are working on a fix to make it more reliable.
  9. @osamakader and bjorn3 looked into automatically enabling fat-lto when autodiff is enabled. In the past, forgetting to enable fat-lto resulted in incorrect (zero) derivatives. The first approach unfortunately wasn't able to cover all cases, so we need to see whether we can handle it nicely. If that turns out to be too complicated, we will revert it and instead "just" provide a nice error message, rather than returning incorrect derivatives.

All-in-all I spend a lot more time on infra (dlopen, cmake, download-llvm-ci, ...) then I'd like, but on the happy side there are only so many features left that I want to support here so there is an end in sight. I am also about to give a tech-talk at the upcoming LLVM dev meeting about safe GPU programming in Rust.

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)

4 detailed updates 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.

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

Update form the 2025-11-19 meeting:

-Zharden-sls / rust#136597

Andrew addressed the comment and rebased the PR. It's waiting for a review again.

#![register_tool] / rust#66079

Tyler Mandry had an alternative proposal where lints would be defined in an external crate and could be brought in via use or something similar: https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/namespaced.20tool.20attrs.

A concern people had was the overhead of having to define a new crate and the potential difficulty with experimenting on new lints.

Tyler suggested adding this as a future possibility to RFC#3808 and FCPing it.

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

Comment by [Tomas Sedovic][] posted on 2025-10-24:

-Cunsigned-char

We've discussed adding an option analogous to -funsigned-char in GCC and Clang, that would allow you to set whether std::ffi::c_char is represented by i8 or u8. Right now, this is platform-specific and should map onto whatever char is in C on the same platform. However, Linux explicitly sets char to be unsigned and then our Rust code conflicts with that. And isn this case the sign is significant.

Rust for Linux works around this this with their rust::ffi module, but now that they've switched to the standard library's CStr type, they're running into it again with the as_ptr method.

Tyler mentioned https://docs.rs/ffi_11/latest/ffi_11/ which preserves the char / signed char / unsigned char distinction.

Grouping target modifier flags

The proposed unsigned-char option is essentially a target modifier. We have several more of these (e.g. llvm-args, no-redzone) in the Rust compiler and Josh suggested we distinguish them somehow. E.g. by giving them the same prefix or possibly creating a new config option (right now we have -C and -Z, maybe we could add -T for target modifiers) so they're distinct from the e.g. the codegen options.

Josh started a Zulip thread here: https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler/topic/Grouping.20target.20modifier.20options.3F/with/546524232

#![register_tool] / rust#66079 / RFC#3808

Tyler looked at the RFC. The Crubit team started using register_tool but then moved to using an attribute instead. He proposed we could do something similar here, although it would require a new feature and RFC.

The team was open to seeing how it would work.

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 [Eric Holk][] posted on 2025-12-06:

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

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

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

3 detailed updates 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
Comment by [Niko Matsakis][] posted on 2025-11-12:

Another related PR:

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

Comment by [Oliver Scherer][] posted on 2025-10-22:

I implemented an initial MVP supporting only tuples and primitives (tho those are just opaque things you can't interact with further), and getting offsets for the tuple fields as well as the size of the tuple: https://github.com/rust-lang/rust/pull/146923

There are two designs of how to expose this from a libs perspective, but after a sync meeting with scottmcm yesterday we came to the conclusion that neither is objectively better at this stage so we're just going to go with the nice end-user UX version for now. For details see the PR description.

Once the MVP lands, I will mentor various interested contributors who will keep adding fields to the Type struct and variants the TypeKind enum.

The next major step is restricting what information you can get from structs outside of the current module or crate. We want to honor visibility, so an initial step would be to just never show private fields, but we want to explore allowing private fields to be shown either just within the current module or via some opt-in marker trait

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.

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

3 detailed updates 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.

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.

Comment by [Jakub Beránek][] posted on 2025-10-21:

We moved forward with the implementation, and the new job queue system is now being tested in production on a single test pull request. Most things seem to be working, but there are a few things to iron out and some profiling to be done. I expect that within a few weeks we could be ready to switch to the new system fully in production.

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

6 detailed updates available.

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.

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 [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 [David Wood][] posted on 2025-11-22:

No progress since [Niko Matsakis's last comment](https://github.com/rust-lang/rust-project-goals/issues/270#issuecomment-3492255970) - intending to experiment with resolving challenges with Deref::Target and land the SVE infrastructure with unfinished parts for experimentation.

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<T: ?Sized> DoThing for T {
            default fn do_thing() {}
        }
        
        impl<T: Sized> DoThing for T {
            fn do_thing() {}
        }
        
        self.do_thing();
        // ^^^^^^^^^^^^^ error!
        // specialisation case is not an issue because that feature isn't stable, we can adjust core, but is a hazard with expanding trait hierarchies in future if stabilisation is ever stabilised
    }
}
}

The experimental_default_bounds work originally added Self: Trait bounds to default methods but moved away from that because it could cause region errors (source 1 / source 2). We expect the same would apply to us but we are not sure.

We decided not to do much on this, the focus remains on the Deref::Target transition as it has more uncertainty.

Comment by [Niko Matsakis][] posted on 2025-10-22:

Sized hierarchy

The focus right now is on the "non-const" parts of the proposal, as the "const" parts are blocked on the new trait solver (https://github.com/rust-lang/rust-project-goals/issues/113). Now that the types team FCP https://github.com/rust-lang/rust/pull/144064 has completed, work can proceed to land the implementation PRs. David Wood plans to split the RFC to separate out the "non-const" parts of the proposal so it can move independently, which will enable extern types.

To that end, there are three interesting T-lang design questions to be considered.

Naming of the traits

The RFC currently proposes the following names

  • Sized
  • MetaSized
  • PointeeSized

However, these names do not follow the "best practice" of naming the trait after the capability that it provides. As champion Niko is recommending we shift to the following names:

  • Sized -- should righly be called SizeOf, but oh well, not worth changing.
  • SizeOfVal -- named after the method size_of_val that you get access to.
  • Pointee -- the only thing you can do is point at it.

The last trait name is already used by the (unstable) std::ptr::Pointee trait. We do not want to have these literally be the same trait because that trait adds a Metadata associated type which would be backwards incompatible; if existing code uses T::Metadata to mean <T as SomeOtherTrait>::Metadata, it could introduce ambiguity if now T: Pointee due to defaults. My proposal is to rename std::ptr::Pointee to std::ptr::PointeeMetadata for now, since that trait is unstable and the design remains under some discussion. The two traits could either be merged eventually or remain separate.

Note that PointeeMetadata would be implemented automatically by the compiler for anything that implements Pointee.

Syntax opt-in

The RFC proposes that an explicit bound like T: MetaSized disabled the default T: Sized bound. However, this gives no signal that this trait bound is "special" or different than any other trait bound. Naming conventions can help here, signalling to users that these are special traits, but that leads to constraints on naming and may not scale as we consider using this mechanism to relax other defaults as proposed in my recent blog post. One idea is to use some form of syntax, so that T: MetaSized is just a regular bound, but (for example) T: =MetaSized indicates that this bound "disables" the default Sized bound. This gives users some signal that something special is going on. This = syntax is borrowing from semver constraints, although it's not a precise match (it does not mean that T: Sized doesn't hold, after all). Other proposals would be some other sigil (T: ?MetaSized, but it means "opt out from the traits above you"; T: #MetaSized, ...) or a keyword (no idea).

To help us get a feel for it, I'll use T: =Foo throughout this post.

Implicit trait supertrait bounds, edition interaction

In Rust 2024, a trait is implicitly ?Sized which gets mapped to =SizeOfVal:

#![allow(unused)]
fn main() {
trait Marker {} // cannot be implemented by extern types
}

This is not desirable but changing it would be backwards incompatible if traits have default methods that take advantage of this bound:

#![allow(unused)]
fn main() {
trait NotQuiteMarker {
    fn dummy(&self) {
        let s = size_of_val(self);
    }
}
}

We need to decide how to handle this. Options are

  • Just change it, breakage will be small (have to test that).
  • Default to =SizeOfVal but let users explicitly write =Pointee if they want that. Bad because all traits will be incompatible with extern types.
  • Default to =SizeOfVal only if defaulted methods are present. Bad because it's a backwards incompatible change to add a defaulted method now.
  • Default to =Pointee but add where Self: =SizeOfVal implicitly to defaulted methods. Now it's not backwards incompatible to add a new defaulted method, but it is backwards incompatible to change an existing method to have a default.

If we go with one of the latter options, Niko proposes that we should relax this in the next Edition (Rust 2026?) so that the default becomes Pointee (or maybe not even that, if we can).

Relaxing associated type bounds

Under the RFC, existing ?Sized bounds would be equivalent to =SizeOfVal. This is mostly fine but will cause problems in (at least) two specific cases: closure bounds and the Deref trait. For closures, we can adjust the bound since the associated type is unstable and due to the peculiarities of our Fn() -> T syntax. Failure to adjust the Deref bound in particular would prohibit the use of Rc<E> where E is an extern type, etc.

For deref bounds, David Wood is preparing a PR that simply changes the bound in a backwards incompatible way to assess breakage on crater. There is some chance the breakage will be small.

If the breakage proves problematic, or if we find other traits that need to be relaxed in a similar fashion, we do have the option of:

  • In Rust 2024, T: Deref becomes equivalent to T: Deref<Target: SizeOfVal> unless written like T: Deref<Target: =Pointee>. We add that annotation throughout stdlib.
  • In Rust 202X, we change the default, so that T: Deref does not add any special bounds, and existing Rust 2024 T: Deref is rewritten to T: Deref<Target: SizeOfVal> as needed.

Other notes

One topic that came up in discussion is that we may eventually wish to add a level "below" Pointee, perhaps Value, that signifies webassembly external values which cannot be pointed at. That is not currently under consideration but should be backwards compatible.

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.