❌

Reading view

There are new articles available, click to refresh the page.

Changes to `impl Trait` in Rust 2024

The default way impl Trait works in return position is changing in Rust 2024. These changes are meant to simplify impl Trait to better match what people want most of the time. We're also adding a flexible syntax that gives you full control when you need it.

TL;DR

Starting in Rust 2024, we are changing the rules for when a generic parameter can be used in the hidden type of a return-position impl Trait:

  • a new default that the hidden types for a return-position impl Trait can use any generic parameter in scope, instead of only types (applicable only in Rust 2024);
  • a syntax to declare explicitly what types may be used (usable in any edition).

The new explicit syntax is called a "use bound": impl Trait + use<'x, T>, for example, would indicate that the hidden type is allowed to use 'x and T (but not any other generic parameters in scope).

Read on for the details!

Background: return-position impl Trait

This blog post concerns return-position impl Trait, such as the following example:

fn process_data(
    data: &[Datum]
) -> impl Iterator<Item = ProcessedDatum> {
    data
        .iter()
        .map(|datum| datum.process())
}

The use of -> impl Iterator in return position here means that the function returns "some kind of iterator". The actual type will be determined by the compiler based on the function body. It is called the "hidden type" because callers do not get to know exactly what it is; they have to code against the Iterator trait. However, at code generation time, the compiler will generate code based on the actual precise type, which ensures that callers are fully optimized.

Although callers don't know the exact type, they do need to know that it will continue to borrow the data argument so that they can ensure that the data reference remains valid while iteration occurs. Further, callers must be able to figure this out based solely on the type signature, without looking at the function body.

Rust's current rules are that a return-position impl Trait value can only use a reference if the lifetime of that reference appears in the impl Trait itself. In this example, impl Iterator<Item = ProcessedDatum> does not reference any lifetimes, and therefore capturing data is illegal. You can see this for yourself on the playground.

The error message ("hidden type captures lifetime") you get in this scenario is not the most intuitive, but it does come with a useful suggestion for how to fix it:

help: to declare that
      `impl Iterator<Item = ProcessedDatum>`
      captures `'_`, you can add an
      explicit `'_` lifetime bound
  |
5 | ) -> impl Iterator<Item = ProcessedDatum> + '_ {
  |                                           ++++

Following a slightly more explicit version of this advice, the function signature becomes:

fn process_data<'d>(
    data: &'d [Datum]
) -> impl Iterator<Item = ProcessedDatum> + 'd {
    data
        .iter()
        .map(|datum| datum.process())
}

In this version, the lifetime 'd of the data is explicitly referenced in the impl Trait type, and so it is allowed to be used. This is also a signal to the caller that the borrow for data must last as long as the iterator is in use, which means that it (correctly) flags an error in an example like this (try it on the playground):

let mut data: Vec<Datum> = vec![Datum::default()];
let iter = process_data(&data);
data.push(Datum::default()); // <-- Error!
iter.next();

Usability problems with this design

The rules for what generic parameters can be used in an impl Trait were decided early on based on a limited set of examples. Over time we have noticed a number of problems with them.

not the right default

Surveys of major codebases (both the compiler and crates on crates.io) found that the vast majority of return-position impl trait values need to use lifetimes, so the default behavior of not capturing is not helpful.

not sufficiently flexible

The current rule is that return-position impl trait always allows using type parameters and sometimes allows using lifetime parameters (if they appear in the bounds). As noted above, this default is wrong because most functions actually DO want their return type to be allowed to use lifetime parameters: that at least has a workaround (modulo some details we'll note below). But the default is also wrong because some functions want to explicitly state that they do NOT use type parameters in the return type, and there is no way to override that right now. The original intention was that type alias impl trait would solve this use case, but that would be a very non-ergonomic solution (and stabilizing type alias impl trait is taking longer than anticipated due to other complications).

hard to explain

Because the defaults are wrong, these errors are encountered by users fairly regularly, and yet they are also subtle and hard to explain (as evidenced by this post!). Adding the compiler hint to suggest + '_ helps, but it's not great that users have to follow a hint they don't fully understand.

incorrect suggestion

Adding a + '_ argument to impl Trait may be confusing, but it's not terribly difficult. Unfortunately, it's often the wrong annotation, leading to unnecessary compiler errors -- and the right fix is either complex or sometimes not even possible. Consider an example like this:

fn process<'c, T> {
    context: &'c Context,
    data: Vec<T>,
) -> impl Iterator<Item = ()> + 'c {
    data
        .into_iter()
        .map(|datum| context.process(datum))
}

Here the process function applies context.process to each of the elements in data (of type T). Because the return value uses context, it is declared as + 'c. Our real goal here is to allow the return type to use 'c; writing + 'c achieves that goal because 'c now appears in the bound listing. However, while writing + 'c is a convenient way to make 'c appear in the bounds, also means that the hidden type must outlive 'c. This requirement is not needed and will in fact lead to a compilation error in this example (try it on the playground).

The reason that this error occurs is a bit subtle. The hidden type is an iterator type based on the result of data.into_iter(), which will include the type T. Because of the + 'c bound, the hidden type must outlive 'c, which in turn means that T must outlive 'c. But T is a generic parameter, so the compiler requires a where-clause like where T: 'c. This where-clause means "it is safe to create a reference with lifetime 'c to the type T". But in fact we don't create any such reference, so the where-clause should not be needed. It is only needed because we used the convenient-but-sometimes-incorrect workaround of adding + 'c to the bounds of our impl Trait.

Just as before, this error is obscure, touching on the more complex aspects of Rust's type system. Unlike before, there is no easy fix! This problem in fact occurred frequently in the compiler, leading to an obscure workaround called the Captures trait. Gross!

We surveyed crates on crates.io and found that the vast majority of cases involving return-position impl trait and generics had bounds that were too strong and which could lead to unnecessary errors (though often they were used in simple ways that didn't trigger an error).

inconsistencies with other parts of Rust

The current design was also introducing inconsistencies with other parts of Rust.

async fn desugaring

Rust defines an async fn as desugaring to a normal fn that returns -> impl Future. You might therefore expect that a function like process:

async fn process(data: &Data) { .. }

...would be (roughly) desugared to:

fn process(
    data: &Data
) -> impl Future<Output = ()> {
    async move {
        ..
    }
}

In practice, because of the problems with the rules around which lifetimes can be used, this is not the actual desugaring. The actual desugaring is to a special kind of impl Trait that is allowed to use all lifetimes. But that form of impl Trait was not exposed to end-users.

impl trait in traits

As we pursued the design for impl trait in traits (RFC 3425), we encountered a number of challenges related to the capturing of lifetimes. In order to get the symmetries that we wanted to work (e.g., that one can write -> impl Future in a trait and impl with the expected effect), we had to change the rules to allow hidden types to use all generic parameters (type and lifetime) uniformly.

Rust 2024 design

The above problems motivated us to take a new approach in Rust 2024. The approach is a combination of two things:

  • a new default that the hidden types for a return-position impl Trait can use any generic parameter in scope, instead of only types (applicable only in Rust 2024);
  • a syntax to declare explicitly what types may be used (usable in any edition).

The new explicit syntax is called a "use bound": impl Trait + use<'x, T>, for example, would indicate that the hidden type is allowed to use 'x and T (but not any other generic parameters in scope).

Lifetimes can now be used by default

In Rust 2024, the default is that the hidden type for a return-position impl Trait values use any generic parameter that is in scope, whether it is a type or a lifetime. This means that the initial example of this blog post will compile just fine in Rust 2024 (try it yourself by setting the Edition in the Playground to 2024):

fn process_data(
    data: &[Datum]
) -> impl Iterator<Item = ProcessedDatum> {
    data
        .iter()
        .map(|datum| datum.process())
}

Yay!

Impl Traits can include a use<> bound to specify precisely which generic types and lifetimes they use

As a side-effect of this change, if you move code to Rust 2024 by hand (without cargo fix), you may start getting errors in the callers of functions with an impl Trait return type. This is because those impl Trait types are now assumed to potentially use input lifetimes and not only types. To control this, you can use the new use<> bound syntax that explicitly declares what generic parameters can be used by the hidden type. Our experience porting the compiler suggests that it is very rare to need changes -- most code actually works better with the new default.

The exception to the above is when the function takes in a reference parameter that is only used to read values and doesn't get included in the return value. One such example is the following function indices(): it takes in a slice of type &[T] but the only thing it does is read the length, which is used to create an iterator. The slice itself is not needed in the return value:

fn indices<'s, T>(
    slice: &'s [T],
) -> impl Iterator<Item = usize> {
    0 .. slice.len()
}

In Rust 2021, this declaration implicitly says that slice is not used in the return type. But in Rust 2024, the default is the opposite. That means that callers like this will stop compiling in Rust 2024, since they now assume that data is borrowed until iteration completes:

fn main() {
    let mut data = vec![1, 2, 3];
    let i = indices(&data);
    data.push(4); // <-- Error!
    i.next(); // <-- assumed to access `&data`
}

This may actually be what you want! It means you can modify the definition of indices() later so that it actually does include slice in the result. Put another way, the new default continues the impl Trait tradition of retaining flexibility for the function to change its implementation without breaking callers.

But what if it's not what you want? What if you want to guarantee that indices() will not retain a reference to its argument slice in its return value? You now do that by including a use<> bound in the return type to say explicitly which generic parameters may be included in the return type.

In the case of indices(), the return type actually uses none of the generics, so we would ideally write use<>:

fn indices<'s, T>(
    slice: &'s [T],
) -> impl Iterator<Item = usize> + use<> {
    //                             -----
    //             Return type does not use `'s` or `T`
    0 .. slice.len()
}

Implementation limitation. Unfortunately, if you actually try the above example on nightly today, you'll see that it doesn't compile (try it for yourself). That's because use<> bounds have only partially been implemented: currently, they must always include at least the type parameters. This corresponds to the limitations of impl Trait in earlier editions, which always must capture type parameters. In this case, that means we can write the following, which also avoids the compilation error, but is still more conservative than necessary (try it yourself):

fn indices<T>(
    slice: &[T],
) -> impl Iterator<Item = usize> + use<T> {
    0 .. slice.len()
}

This implementation limitation is only temporary and will hopefully be lifted soon! You can follow the current status at tracking issue #130031.

Alternative: 'static bounds. For the special case of capturing no references at all, it is also possible to use a 'static bound, like so (try it yourself):

fn indices<'s, T>(
    slice: &'s [T],
) -> impl Iterator<Item = usize> + 'static {
    //                             -------
    //             Return type does not capture references.
    0 .. slice.len()
}

'static bounds are convenient in this case, particularly given the current implementation limitations around use<> bounds, but use<> bound are more flexible overall, and so we expect them to be used more often. (As an example, the compiler has a variant of indices that returns newtype'd indices I instead of usize values, and it therefore includes a use<I> declaration.)

Conclusion

This example demonstrates the way that editions can help us to remove complexity from Rust. In Rust 2021, the default rules for when lifetime parameters can be used in impl Trait had not aged well. They frequently didn't express what users needed and led to obscure workarounds being required. They led to other inconsistencies, such as between -> impl Future and async fn, or between the semantics of return-position impl Trait in top-level functions and trait functions.

Thanks to editions, we are able to address that without breaking existing code. With the newer rules coming in Rust 2024,

  • most code will "just work" in Rust 2024, avoiding confusing errors;
  • for the code where annotations are required, we now have a more powerful annotation mechanism that can let you say exactly what you need to say.

Appendix: Relevant links

  • Precise capture was proposed in RFC #3617, which left an unresolved question regarding syntax, and its tracking issue was #123432.
  • The unresolved syntax question was resolved in issue #125836, which introduced the + use<> notation used in this post.
  • The implementation limitation is tracked in #130031.

Announcing Rust 1.81.0

The Rust team is happy to announce a new version of Rust, 1.81.0. Rust is a programming language empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup, you can get 1.81.0 with:

$ rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website, and check out the detailed release notes for 1.81.0.

If you'd like to help us out by testing future releases, you might consider updating locally to use the beta channel (rustup default beta) or the nightly channel (rustup default nightly). Please report any bugs you might come across!

What's in 1.81.0 stable

core::error::Error

1.81 stabilizes the Error trait in core, allowing usage of the trait in #![no_std] libraries. This primarily enables the wider Rust ecosystem to standardize on the same Error trait, regardless of what environments the library targets.

New sort implementations

Both the stable and unstable sort implementations in the standard library have been updated to new algorithms, improving their runtime performance and compilation time.

Additionally, both of the new sort algorithms try to detect incorrect implementations of Ord that prevent them from being able to produce a meaningfully sorted result, and will now panic on such cases rather than returning effectively randomly arranged data. Users encountering these panics should audit their ordering implementations to ensure they satisfy the requirements documented in PartialOrd and Ord.

#[expect(lint)]

1.81 stabilizes a new lint level, expect, which allows explicitly noting that a particular lint should occur, and warning if it doesn't. The intended use case for this is temporarily silencing a lint, whether due to lint implementation bugs or ongoing refactoring, while wanting to know when the lint is no longer required.

For example, if you're moving a code base to comply with a new restriction enforced via a Clippy lint like undocumented_unsafe_blocks, you can use #[expect(clippy::undocumented_unsafe_blocks)] as you transition, ensuring that once all unsafe blocks are documented you can opt into denying the lint to enforce it.

Clippy also has two lints to enforce the usage of this feature and help with migrating existing attributes:

Lint reasons

Changing the lint level is often done for some particular reason. For example, if code runs in an environment without floating point support, you could use Clippy to lint on such usage with #![deny(clippy::float_arithmetic)]. However, if a new developer to the project sees this lint fire, they need to look for (hopefully) a comment on the deny explaining why it was added. With Rust 1.81, they can be informed directly in the compiler message:

error: floating-point arithmetic detected
 --> src/lib.rs:4:5
  |
4 |     a + b
  |     ^^^^^
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
  = note: no hardware float support
note: the lint level is defined here
 --> src/lib.rs:1:9
  |
1 | #![deny(clippy::float_arithmetic, reason = "no hardware float support")]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^

Stabilized APIs

These APIs are now stable in const contexts:

Compatibility notes

Split panic hook and panic handler arguments

We have renamed std::panic::PanicInfo to std::panic::PanicHookInfo. The old name will continue to work as an alias, but will result in a deprecation warning starting in Rust 1.82.0.

core::panic::PanicInfo will remain unchanged, however, as this is now a different type.

The reason is that these types have different roles: std::panic::PanicHookInfo is the argument to the panic hook in std context (where panics can have an arbitrary payload), while core::panic::PanicInfo is the argument to the #[panic_handler] in #![no_std] context (where panics always carry a formatted message). Separating these types allows us to add more useful methods to these types, such as std::panic::PanicHookInfo::payload_as_str() and core::panic::PanicInfo::message().

Abort on uncaught panics in extern "C" functions

This completes the transition started in 1.71, which added dedicated "C-unwind" (amongst other -unwind variants) ABIs for when unwinding across the ABI boundary is expected. As of 1.81, the non-unwind ABIs (e.g., "C") will now abort on uncaught unwinds, closing the longstanding soundness problem.

Programs relying on unwinding should transition to using -unwind suffixed ABI variants.

WASI 0.1 target naming changed

Usage of the wasm32-wasi target (which targets WASI 0.1) will now issue a compiler warning and request users switch to the wasm32-wasip1 target instead. Both targets are the same, wasm32-wasi is only being renamed, and this change to the WASI target is being done to enable removing wasm32-wasi in January 2025.

Fixes CVE-2024-43402

std::process::Command now correctly escapes arguments when invoking batch files on Windows in the presence of trailing whitespace or periods (which are ignored and stripped by Windows).

See more details in the previous announcement of this change.

Other changes

Check out everything that changed in Rust, Cargo, and Clippy.

Contributors to 1.81.0

Many people came together to create Rust 1.81.0. We couldn't have done it without all of you. Thanks!

Security advisory for the standard library (CVE-2024-43402)

On April 9th, 2024, the Rust Security Response WG disclosed CVE-2024-24576, where std::process::Command incorrectly escaped arguments when invoking batch files on Windows. We were notified that our fix for the vulnerability was incomplete, and it was possible to bypass the fix when the batch file name had trailing whitespace or periods (which are ignored and stripped by Windows).

The severity of the incomplete fix is low, due to the niche conditions needed to trigger it. Note that calculating the CVSS score might assign a higher severity to this, but that doesn't take into account what is required to trigger the incomplete fix.

The incomplete fix is identified by CVE-2024-43402.

Overview

Refer to the advisory for CVE-2024-24576 for details on the original vulnerability.

To determine whether to apply the cmd.exe escaping rules, the original fix for the vulnerability checked whether the command name ended with .bat or .cmd. At the time that seemed enough, as we refuse to invoke batch scripts with no file extension.

Unfortunately, Windows removes trailing whitespace and periods when parsing file paths. For example, .bat. . is interpreted by Windows as .bat, but our original fix didn't check for that.

Mitigations

If you are affected by this, and you are using Rust 1.77.2 or greater, you can remove the trailing whitespace (ASCII 0x20) and trailing periods (ASCII 0x2E) from the batch file name to bypass the incomplete fix and enable the mitigations.

Rust 1.81.0, due to be released on September 5th 2024, will update the standard library to apply the CVE-2024-24576 mitigations to all batch files invocations, regardless of the trailing chars in the file name.

Affected versions

All Rust versions before 1.81.0 are affected, if your code or one of your dependencies invoke a batch script on Windows with trailing whitespace or trailing periods in the name, and pass untrusted arguments to it.

Acknowledgements

We want to thank Kainan Zhang (@4xpl0r3r) for responsibly disclosing this to us according to the Rust security policy.

We also want to thank the members of the Rust project who helped us disclose the incomplete fix: Chris Denton for developing the fix, Amanieu D'Antras for reviewing the fix; Pietro Albini for writing this advisory; Pietro Albini, Manish Goregaokar and Josh Stone for coordinating this disclosure.

2024 Leadership Council Survey

One of the responsibilities of the leadership council, formed by RFC 3392, is to solicit feedback on a yearly basis from the Project on how we are performing our duties.

Each year, the Council must solicit feedback on whether the Council is serving its purpose effectively from all willing and able Project members and openly discuss this feedback in a forum that allows and encourages active participation from all Project members. To do so, the Council and other Project members consult the high-level duties, expectations, and constraints listed in this RFC and any subsequent revisions thereof to determine if the Council is meeting its duties and obligations.

This is the council's first year, so we are still figuring out the best way to do this. For this year, a short survey was sent out to all@ on June 24th, 2024, ran for two weeks, and we are now presenting aggregated results from the survey. Raw responses will not be shared beyond the leadership council, but the results below reflect sentiments shared in response to each question. We invite feedback and suggestions on actions to take on Zulip or through direct communication to council members.

We want to thank everyone for their feedback! It has been very valuable to hear what people are thinking. As always, if you have thoughts or concerns, please reach out to your council representative any time.

Survey results

We received 53 responses to the survey, representing roughly a 32% response rate (out of 163 current recipients of all@).

Do you feel that the Rust Leadership Council is serving its purpose effectively?

Option Response count
Strongly agree 1
Agree 18
Unsure 30
Disagree 4
Strongly disagree 0

I am aware of the role that the Leadership Council plays in the governance of the Rust Project.

Option Response count
Strongly agree 9
Agree 20
Unsure 14
Disagree 7
Strongly disagree 3

The Rust Project has a solid foundation of Project governance.

Option Response count
Strongly agree 3
Agree 16
Unsure 20
Disagree 11
Strongly disagree 3

Areas that are going well

For the rest of the questions we group responses into rough categories. The number of those responses is also provided; note that some responses may have fallen into more than one of these categories.

  • (5) Less drama
  • (5) More public operations
  • (5) Lack of clarity / knowledge about what it does
    • It's not obvious why this is a "going well" from the responses, but it was given in response to this question.
  • (4) General/inspecific positivity.
  • (2) Improved Foundation/project relations
  • (2) Funding travel/get-togethers of team members
  • (1) Clear representation of members of the Project
  • (1) Turnover while retaining members

Areas that are not going well

  • (15) Knowing what the council is doing
  • (3) Not enough delegation of decisions
  • (2) Finding people interested in being on the council / helping the council
  • (1) What is the role of the project directors? Are they redundant given the council?
  • (2) Too conservative in trying things / decisions/progress is made too slowly.
  • (1) Worry over Foundation not trusting Project

Suggestions for things to do in the responses:

  • (2) Addressing burnout
  • (2) More social time between teams
  • (2) More communication/accountability with/for the Foundation
  • (2) Hiring people, particularly for non-technical roles
  • (1) Helping expand the moderation team
  • (1) Resolving the launching pad issues, e.g., through "Rust Society" work
  • (1) Product management for language/compiler/libraries

Takeaways for future surveys

  • We should structure the survey to specifically ask about high-level duties and/or enumerate areas of interest (e.g., numeric responses on key questions like openness and effectiveness)
  • Consider linking published material/writing 1-year retrospective and that being linked from the survey as pre-reading.
  • We should disambiguate between neutral and "not enough information/knowledge to answer" responses in multiple choice response answers.

Proposed action items

We don't have any concrete proposed actions at this time, though are interested in finding ways to have more visilibity for council activities, as that seems to be one of the key problems called out across all of the questions asked. How exactly to achieve this remains unclear though.

As mentioned earlier, we welcome input from the community on suggestions for both improving this process and for actions to change how the council operates.

Rust Project goals for 2024

With the merging of RFC #3672, the Rust project has selected a slate of 26 Project Goals for the second half of 2024 (2024H2). This is our first time running an experimental new roadmapping process; assuming all goes well, we expect to be running the process roughly every six months. Of these goals, we have designated three of them as our flagship goals, representing our most ambitious and most impactful efforts: (1) finalize preparations for the Rust 2024 edition; (2) bring the Async Rust experience closer to parity with sync Rust; and (3) resolve the biggest blockers to the Linux kernel building on stable Rust. As the year progresses we'll be posting regular updates on these 3 flagship goals along with the 23 others.

Rust’s mission

All the goals selected ultimately further Rust's mission of empowering everyone to build reliable and efficient software. Rust targets programs that prioritize

  • reliability and robustness;
  • performance, memory usage, and resource consumption; and
  • long-term maintenance and extensibility.

We consider "any two out of the three" to be the right heuristic for projects where Rust is a strong contender or possibly the best option, and we chose our goals in part so as to help ensure this is true.

Why these particular flagship goals?

2024 Edition. 2024 will mark the 4th Rust edition, following on the 2015, 2018, and 2021 editions. Similar to the 2021 edition, the 2024 edition is not a "major marketing push" but rather an opportunity to correct small ergonomic issues with Rust that will make it overall much easier to use. The changes planned for the 2024 edition include (1) supporting -> impl Trait and async fn in traits by aligning capture behavior; (2) permitting (async) generators to be added in the future by reserving the gen keyword; and (3) altering fallback for the ! type. The plan is to finalize development of 2024 features this year; the Edition itself is planned for Rust v1.85 (to be released to beta 2025-01-03 and to stable on 2025-02-20).

Async. In 2024 we plan to deliver several critical async Rust building block features, most notably support for async closures and Send bounds. This is part of a multi-year program aiming to raise the experience of authoring "async Rust" to the same level of quality as "sync Rust". Async Rust is widely used, with 52% of the respondents in the 2023 Rust survey indicating that they use Rust to build server-side or backend applications.

Rust for Linux. The experimental support for Rust development in the Linux kernel is a watershed moment for Rust, demonstrating to the world that Rust is indeed capable of targeting all manner of low-level systems applications. And yet today that support rests on a number of unstable features, blocking the effort from ever going beyond experimental status. For 2024H2 we will work to close the largest gaps that block support.

Highlights from the other goals

In addition to the flagship goals, the roadmap defines 23 other goals. Here is a subset to give you a flavor:

Check out the whole list! (Go ahead, we'll wait, but come back here afterwards!)

How to track progress

As the year progresses, we will be posting regular blog posts summarizing the progress on the various goals. If you'd like to see more detail, the 2024h2 milestone on the rust-lang/rust-project-goals repository has tracking issues for each of the goals. Each issue is assigned to the owner(s) of that particular goal. You can subscribe to the issue to receive regular updates, or monitor the #project-goals channel on the rust-lang Zulip. Over time we will likely create other ways to follow along, such as a page on rust-lang.org to visualize progress (if you'd like to help with that, reach out to @nikomatsakis, thanks!).

It's worth stating up front: we don't expect all of these goals to be completed. Many of them were proposed and owned by volunteers, and it's normal and expected that things don't always work out as planned. In the event that a goal seems to stall out, we can either look for a new owner or just consider the goal again in the next round of goal planning.

How we selected project goals

Each project goal began as a PR against the rust-lang/rust-project-goals repository. As each PR came in, the goals were socialized with the teams. This process sometimes resulted in edits to the goals or in breaking up larger goals into smaller chunks (e.g., a far-reaching goal for "higher level Rust" was broken into two specific deliverables, a user-wide build cache and ergonomic ref counting). Finally, the goals were collated into RFC #3672, which listed each goals as well as all the asks from the team. This RFC was approved by all the teams that are being asked for support or other requests.

Conclusion: Project Goals as a "front door" for Rust

To me, the most exciting thing about the Project Goals program has been seeing the goals coming from outside the existing Rust maintainers. My hope is that the Project Goal process can supplement RFCs as an effective "front door" for the project, offering people who have the resources and skill to drive changes a way to float that idea and get feedback from the Rust teams before they begin to work on it.

Project Goals also help ensure the sustainability of the Rust open source community. In the past, it was difficult to tell when starting work on a project whether it would be well-received by the Rust maintainers. This was an obstacle for those who would like to fund efforts to improve Rust, as people don't like to fund work without reasonable confidence it will succeed. Project goals are a way for project maintainers to "bless" a particular project and indicate their belief that it will be helpful to Rust. The Rust Foundation is using project goals as one of their criteria when considering fellowship applications, for example, and I expect over time other grant programs will do the same. But project goals are useful for others, too: having an approved project goal can help someone convince their employer to give them time to work on Rust open source efforts, for example, or give contractors the confidence they need to ensure their customer they'll be able to get the work done.

The next round of goal planning will be targeting 2025H1 and is expected to start in October. We look forward to seeing what great ideas are proposed!

Announcing Rust 1.80.1

The Rust team has published a new point release of Rust, 1.80.1. Rust is a programming language that is empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup, getting Rust 1.80.1 is as easy as:

rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website.

What's in 1.80.1

Rust 1.80.1 fixes two regressions that were recently reported.

Miscompilation when comparing floats

In addition to the existing optimizations performed by LLVM, rustc is growing its own set of optimizations. Rust 1.78.0 added a new one, implementing "jump threading" (merging together two adjacent branches that perform the same comparison).

The optimization was also enabled on branches checking for floating point equality, but it didn't implement the special rules needed for floats comparison (NaN != NaN and 0.0 == -0.0). This caused the optimization to miscompile code performing those checks.

Rust 1.80.1 addresses the problem by preventing the optimization from being applied to float comparisons, while retaining the optimization on other supported types.

False positives in the dead_code lint

Rust 1.80.0 contained refactorings to the dead_code lint. We received multiple reports that the new lint implementation produces false positives, so we are reverting the changes in Rust 1.80.1. We'll continue to experiment on how to improve the accuracy of dead_code in future releases.

Contributors to 1.80.1

Many people came together to create Rust 1.80.1. We couldn't have done it without all of you. Thanks!

crates.io: development update

Since crates.io does not have releases in the classical sense, there are no release notes either. However, the crates.io team still wants to keep you all updated about the ongoing development of crates.io. This blog post is a summary of the most significant changes that we have made to crates.io in the past months.

cargo install

When looking at crates like ripgrep you will notice that the installation instructions now say cargo install ripgrep instead of cargo add ripgrep. We implemented this change to make it easier for users to install crates that have binary targets. cargo add is still the correct command to use when adding a crate as a dependency to your project, but for binary-only crates like ripgrep, cargo install is the way to go.

We achieved this by analyzing the uploaded crate files when they are published to crates.io. If a crate has binary targets, the names of the binaries will now be saved in our database and then conveniently displayed on the crate page:

Dark Mode Screenshot

After shipping this feature we got notified that some library crates use binaries for local development purposes and the author would prefer to not have the binaries listed on the crate page. The cargo team has been working on a solution for this by using the exclude manifest field, which will be shipped soon.

Dark mode

If your operating system is set to dark mode, you may have noticed that crates.io now automatically switches to a dark user interface theme. If you don't like the dark theme, you can still switch back to the light theme by clicking the color theme icon in the top right corner of the page. By default, the theme will be set based on your operating system's theme settings, but you can also override this setting manually.

Dark Mode Screenshot

Similar to GitHub, we now also have dark/light theme support for images in your README.md files:

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://test.crates.io/logo_dark.svg">
  <img src="https://test.crates.io/logo.svg" alt="logo" width="200">
</picture>

RSS feeds

Inspired by our friends at the Python Package Index, we have introduced a couple of experimental RSS feeds for crates.io:

This will allow you to keep track of the latest crate releases and updates in your favorite RSS reader. The original GitHub issue requested a feed for all the crates you "follow" on crates.io, but we decided that per-crate feeds would be more useful for now. If you have any feedback on this feature, please let us know!

API token expiry notifications

Our crates.io team member @hi-rustin has been very active in improving our API tokens user experience. If you create an API token with an expiry date, you will now receive a notification email three days before the token expires. This will help you to remember to renew your token before it expires and your scripts stop working.

Following this change, he also implemented a way to create new API tokens based on the configuration of existing tokens, which will make it much easier to renew tokens without having to reconfigure all the permissions. The user interface on the "API tokens" settings page now shows a "Regenerate" button, which will allow you to copy the permissions of existing tokens. Similarly, the token expiry notifications will now also contain a link that directly fills in the permissions of the expiring token, so you can easily create a new token with the same permissions.

Dark Mode Screenshot

Database performance optimizations

Our latest addition to the crates.io team, @eth3lbert, has been working on optimizing the database queries that power crates.io. He has been working on a couple of pull requests that aim to reduce the load on the database server and make the website faster for everyone. Some of the changes he has made include:

  • #7865: Further speed-up reverse dependencies query
  • #7941: Improve crates endpoint performance
  • #8734: Add partial index on versions table
  • #8737: Improve the performance of reverse dependencies using the default_versions table

In addition to that, we have recently migrated our database servers to a new provider with more memory and faster storage. This has also improved the performance of the website and allowed us to run more complex queries without running into performance issues. It was previously taking multiple seconds to load e.g. https://crates.io/crates/syn/reverse_dependencies, but now the server usually responds in much less than a second.

Another piece of the puzzle was archiving old data that is no longer needed for the website. We have moved the download counts older than 90 days into CSV files that are stored on S3 and will soon be publicly available for download via our CDNs. This has reduced the size of the database significantly and improved the performance of some of our background jobs.

Feedback

We hope you enjoyed this update on the development of crates.io. If you have any feedback or questions, please let us know on Zulip or GitHub. We are always happy to hear from you and are looking forward to your feedback!

Announcing Rust 1.80.0

The Rust team is happy to announce a new version of Rust, 1.80.0. Rust is a programming language empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup, you can get 1.80.0 with:

$ rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website, and check out the detailed release notes for 1.80.0.

If you'd like to help us out by testing future releases, you might consider updating locally to use the beta channel (rustup default beta) or the nightly channel (rustup default nightly). Please report any bugs you might come across!

What's in 1.80.0 stable

LazyCell and LazyLock

These "lazy" types delay the initialization of their data until first access. They are similar to the OnceCell and OnceLock types stabilized in 1.70, but with the initialization function included in the cell. This completes the stabilization of functionality adopted into the standard library from the popular lazy_static and once_cell crates.

LazyLock is the thread-safe option, making it suitable for places like static values. For example, both the spawn thread and the main scope will see the exact same duration below, since LAZY_TIME will be initialized once, by whichever ends up accessing the static first. Neither use has to know how to initialize it, unlike they would with OnceLock::get_or_init().

use std::sync::LazyLock;
use std::time::Instant;

static LAZY_TIME: LazyLock<Instant> = LazyLock::new(Instant::now);

fn main() {
    let start = Instant::now();
    std::thread::scope(|s| {
        s.spawn(|| {
            println!("Thread lazy time is {:?}", LAZY_TIME.duration_since(start));
        });
        println!("Main lazy time is {:?}", LAZY_TIME.duration_since(start));
    });
}

LazyCell does the same thing without thread synchronization, so it doesn't implement Sync, which is needed for static, but it can still be used in thread_local! statics (with distinct initialization per thread). Either type can also be used in other data structures as well, depending on thread-safety needs, so lazy initialization is available everywhere!

Checked cfg names and values

In 1.79, rustc stabilized a --check-cfg flag, and now Cargo 1.80 is enabling those checks for all cfg names and values that it knows (in addition to the well known names and values from rustc). This includes feature names from Cargo.toml as well as new cargo::rustc-check-cfg output from build scripts.

Unexpected cfgs are reported by the warn-by-default unexpected_cfgs lint, which is meant to catch typos or other misconfiguration. For example, in a project with an optional rayon dependency, this code is configured for the wrong feature value:

fn main() {
    println!("Hello, world!");

    #[cfg(feature = "crayon")]
    rayon::join(
        || println!("Hello, Thing One!"),
        || println!("Hello, Thing Two!"),
    );
}
warning: unexpected `cfg` condition value: `crayon`
 --> src/main.rs:4:11
  |
4 |     #[cfg(feature = "crayon")]
  |           ^^^^^^^^^^--------
  |                     |
  |                     help: there is a expected value with a similar name: `"rayon"`
  |
  = note: expected values for `feature` are: `rayon`
  = help: consider adding `crayon` as a feature in `Cargo.toml`
  = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
  = note: `#[warn(unexpected_cfgs)]` on by default

The same warning is reported regardless of whether the actual rayon feature is enabled or not.

The [lints] table in the Cargo.toml manifest can also be used to extend the list of known names and values for custom cfg. rustc automatically provides the syntax to use in the warning.

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(foo, values("bar"))'] }

You can read more about this feature in a previous blog post announcing the availability of the feature on nightly.

Exclusive ranges in patterns

Rust ranged patterns can now use exclusive endpoints, written a..b or ..b similar to the Range and RangeTo expression types. For example, the following patterns can now use the same constants for the end of one pattern and the start of the next:

pub fn size_prefix(n: u32) -> &'static str {
    const K: u32 = 10u32.pow(3);
    const M: u32 = 10u32.pow(6);
    const G: u32 = 10u32.pow(9);
    match n {
        ..K => "",
        K..M => "k",
        M..G => "M",
        G.. => "G",
    }
}

Previously, only inclusive (a..=b or ..=b) or open (a..) ranges were allowed in patterns, so code like this would require separate constants for inclusive endpoints like K - 1.

Exclusive ranges have been implemented as an unstable feature for a long time, but the blocking concern was that they might add confusion and increase the chance of off-by-one errors in patterns. To that end, exhaustiveness checking has been enhanced to better detect gaps in pattern matching, and new lints non_contiguous_range_endpoints and overlapping_range_endpoints will help detect cases where you might want to switch exclusive patterns to inclusive, or vice versa.

Stabilized APIs

These APIs are now stable in const contexts:

Other changes

Check out everything that changed in Rust, Cargo, and Clippy.

Contributors to 1.80.0

Many people came together to create Rust 1.80.0. We couldn't have done it without all of you. Thanks!

Types Team Update and Roadmap

By: lcnr

It has been more than a year since the initial blog post announcing the Types team, and our initial set of goals. For details on what the team is, why it was formed, or our previously-stated overarching goals, go check out that blog post. In short the Types team's purview extends to the parts of the Rust language and compiler that involve the type system, e.g. type checking, trait solving, and borrow checking. Our short and long term goals effectively work to make the type system sound, consistent, extensible, and fast.

Before getting into details, it's worth sharing a quick point: the team over the last year has been very successful. Oftentimes, it's hard to measure impact, particularly when long-term roadmap goals are hard to quantify progress on and various short-term goals either are hit or aren't. But, there is one clear statistic that is somewhat indicative of the team's progress: over the last year or so, more than 50 user-facing changes have landed, each separately approved by Types Team consensus through FCP.

The changes lie at the boundary between language design and implementation, and the Types Team (which is a subteam of both the Language and Compiler Teams) existing means that not only does the Rust Project have the bandwidth to make these decisions but we also have enough people with the knowledge and experience of the type system to make informed decisions that overall make the language better.

The priorities of the types team

To evaluate our progress over the last year and our roadmap going forward, lets start with our main priorities in order of importance. We will refer to them during the remainder of this post. To reach our goals, we need a a healthy group of maintainers which have the expertise and capacity to react to issues and to implement complex changes.

The type system should be Sound

One of the main promises of Rust is that there cannot be undefined behavior when using only safe code. It might surprise you that there are currently known type system bugs which break these guarantees. Most of these issues were found by people familiar with the inner workings of the compiler by explicitly looking for them and we generally do not expect users to encounter these bugs by accident. Regardless, we deeply care about fixing them and are working towards a fully sound and ideally verified type system.

The type system should be Consistent

The type system should be easy to reason about. We should avoid rough edges and special-cases if possible. We want to keep both the implementation and user-facing behavior as simple as possible. Where possible we want to consider the overall design instead of providing local targeted fixes. This is necessary to build trust in the soundness of the type system and allows for a simpler mental model of Rust.

The type system should be Extensible

Rust is still evolving and we will be required to extend the type system to enable new language features going forward. This requires the type system to be extensible and approachable. The design of the language should not be adapted to work around short-comings of its current type system implementation. We should collaborate with other teams and users to make sure we're aware of their problems and consider possible future extensions in our implementation and design.

The type system should be Fast

We care about the compile times of Rust and want to consider the impact on compile times of our designs. We should look for effective approaches to speed up the existing implementation, by improving caching or adding fast paths where applicable. We should also be aware of the compile time impact of future additions to the type system and suggest more performant solutions where possible.

Updates

We have been very active over the last year and made some significant progress. There are also a few non-technical updates we would like to share.

Organizational updates

First, a huge welcome to the two new members to team since the announcement post: @BoxyUwU and @aliemjay. @BoxyUwU has been doing a lot of work on const generics and made significant contributions to the design of the next generation trait solver. @aliemjay has been working on some very subtle improvements to opaque types - impl Trait - and to borrow checking. They are both invaluable additions to the team.

We also organized another in-person Types Team meetup last October, immediately prior to EuroRust. We discussed the state of the team, looked at current implementation challenges and in-progress work, and reviewed and updated the roadmap from the previous meetup. Most of this will be covered in this blog post.

Finally, as discussed in the RFC, we would like to have leads rotate out regularly, largely to help share the burden and experience of leads' work. So with that being said, @nikomatsakis is rotating out and @lcnr is joining to co-lead alongside @jackh726.

Roadmap progress and major milestones

The next-generation trait solver

There has been a lot of work on the next-generation trait solver. The initiative posted a separate update at the end of last year. While we would have liked to stabilize its use in coherence a few months ago, this surfaced additional small behavior regressions and hangs, causing delays. We are working on fixing these issues and intend to merge the stabilization PR soon. We are getting close to compiling the standard library and the compiler with the new solver enabled everywhere, after which will be able to run crater to figure out the remaining issues. We expect there to be a long tail of minor issues and behavioral differences from the existing implementation, so there's still a lot to do here. There are also open design questions which we will have to resolve before stabilizing the new implementation.

Async and impl Trait

We stabilized async-fn in traits (AFIT) and return-position impl Trait in traits (RPITIT) in version 1.75 thanks to a significant effort by @compiler-errors and @spastorino. @cjgillot greatly improved the way generators, and therefore async functions, are represented in the type system1. This allowed us to support recursive async-functions without too much additional work2.

Designing the next-generation trait solver surfaced issues and future-compatibility challenges of our type-alias impl Trait (TAIT) implementation using the old trait solver. We are currently reworking the design and implementation. @oli-obk is spear-heading this effort. This also impacts RPIT edge-cases, forcing us to be careful to avoid accidental breakage. There are some open language design questions for TAIT, so we plan to stabilize associated type position impl Trait (ATPIT) as it avoids these language design questions while still closing the expressiveness gap.

a-mir-formality

We made limited progress on a-mir-formality over the last year, mostly because we were able to allocate less time than expected towards this work. We have used it as the foundation towards an intuitive approach to coinductive traits which are necessary for many of the remaining unsound issues.

Fixing soundness issues

We fixed multiple long-standing unsound issues, see the full list of closed issues. The most most notable of which was #80176. This subtle issue caused us to accept methods in trait implementations whose function signature had outlives requirements not present in the trait definition. These requirements were then never proven when calling the trait method. As there were some crates which relied on this pattern by accident, even if it their usages didn't exploit this unsoundness, we first merged a future-compatibility lint which we then moved to a hard error after a few versions.

We've also spent time on categorizing the remaining open issues and integrating them into our longterm planning. Most of the remaining ones are blocked on the next-generation trait solver as fixing them relies on coinductive trait semantics and improvements to implied bounds. There are some remaining issues which can be at least partially fixed right now, and we intend to work through them as we go. Finally, there are some issues for which we still haven't figured out the best approach and which require some further considerations.

Going forward

We made significant progress during the last year but we are not done! This section covers our goals for the rest of 2024. For each item we also link to the project goals that we have proposed as part of the Rust Project's experimental new roadmap process.

-Znext-solver

Our biggest goal is to use the next-generation trait solver everywhere by default and to fully replace the existing implementation. We are currently finalizing the stabilization of its use in coherence checking. This should already fix multiple unsound issues and fix a lot of smaller issues and inconsistencies of the current implementation. See the stabilization report for more details.

We are also working on extracting its implementation into a separate library outside of the compiler itself. We would like to share the trait solver with rust-analyzer by the end of this year. They currently use chalk which is no longer actively maintained. Using the next-generation trait solver in rust-analyzer should result in a lot of additional testing for the solver while also improving the IDE experience by positively impacting performance and correctness.

We intend to slowly roll out the solver in other areas of the compiler until we're able to fully remove the existing implementation by the end of 2025. This switch will fix multiple unsound issues by itself and will unblock a significant amount of future work. It will generally cleanup many rough edges of the type system, such as associated types in higher-ranked types. There are many unsound issues which can only be fixed once we exclusively use the new implementation.

a-mir-formality

We intend to more actively develop a-mir-formality this year to use it in our design process. Using it to model parts of the type system has already been incredibly impactful and we want to build on that. We are working on more effective testing of a-mir-formality by enabling its use for actual Rust code snippets and by adding fuzzing support. This will allow us to gain additional confidence in our model of the type system and will guide its future development.

We plan to fully formalize some components of the type system this year. Coherence is fairly self-contained, very subtle, and soundness-critical. This has prevented us from making significant improvements to it in the past. We also intend to formalize coinductive trait semantics, which are difficult to reason about and necessary to fix many longstanding soundness issues.

Language changes and polonius

We intend to get the internal implementation of opaque types ready for the stabilization of TAIT and ATPIT this year. We are also hoping to land significant improvements to our handling of associated types in coherence checking this year.

Our other goal is to get Polonius, the next generation borrow checker, available on nightly, which would put us in a position to stabilize in 2025 once we have time to do more optimization and testing.

We also intend to support the development of other language features, such as async-closures, which are part of the async project goal, and dyn-trait upcasting, which will hopefully get stabilized in the near future.

Roadmap

EOY 2024

  • next-generation trait solver
    • stable in coherence
    • used by rust-analyzer
  • ATPIT stabilized
  • a-mir-formality
    • support for fuzzing and testing Rust snippets
    • complete model of coherence and coinductive trait semantics
  • full polonius implementation available on nightly

EOY 2025

  • next-generation trait solver used everywhere by default
  • TAIT stabilized
  • polonius stabilized

EOY 2027

  • next-generation trait solver
    • support for coinduction and (implicit) where-bounds on for<'a>
    • enable perfect derive
  • a-mir-formality fully model soundness critical parts of Rust
  • all known type system unsoundnesses fixed
  1. stabilized in https://github.com/rust-lang/rust/issues/107421 ↩

  2. stabilized in https://github.com/rust-lang/rust/issues/117703 ↩

Announcing Rust 1.79.0

The Rust team is happy to announce a new version of Rust, 1.79.0. Rust is a programming language empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup, you can get 1.79.0 with:

$ rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website, and check out the detailed release notes for 1.79.0.

If you'd like to help us out by testing future releases, you might consider updating locally to use the beta channel (rustup default beta) or the nightly channel (rustup default nightly). Please report any bugs you might come across!

What's in 1.79.0 stable

Inline const expressions

const { ... } blocks are now stable in expression position, permitting explicitly entering a const context without requiring extra declarations (e.g., defining const items or associated constants on a trait).

Unlike const items (const ITEM: ... = ...), inline consts are able to make use of in-scope generics, and have their type inferred rather than written explicitly, making them particularly useful for inline code snippets. For example, a pattern like:

const EMPTY: Option<Vec<u8>> = None;
let foo = [EMPTY; 100];

can now be written like this:

let foo = [const { None }; 100];

Notably, this is also true of generic contexts, where previously a verbose trait declaration with an associated constant would be required:

fn create_none_array<T, const N: usize>() -> [Option<T>; N] {
    [const { None::<T> }; N]
}

This makes this code much more succinct and easier to read.

See the reference documentation for details.

Bounds in associated type position

Rust 1.79 stabilizes the associated item bounds syntax, which allows us to put bounds in associated type position within other bounds, i.e. T: Trait<Assoc: Bounds...>. This avoids the need to provide an extra, explicit generic type just to constrain the associated type.

This feature allows specifying bounds in a few places that previously either were not possible or imposed extra, unnecessary constraints on usage:

  • where clauses - in this position, this is equivalent to breaking up the bound into two (or more) where clauses. For example, where T: Trait<Assoc: Bound> is equivalent to where T: Trait, <T as Trait>::Assoc: Bound.
  • Supertraits - a bound specified via the new syntax is implied when the trait is used, unlike where clauses. Sample syntax: trait CopyIterator: Iterator<Item: Copy> {}.
  • Associated type item bounds - This allows constraining the nested rigid projections that are associated with a trait's associated types. e.g. trait Trait { type Assoc: Trait2<Assoc2: Copy>; }.
  • opaque type bounds (RPIT, TAIT) - This allows constraining associated types that are associated with the opaque type without having to name the opaque type. For example, impl Iterator<Item: Copy> defines an iterator whose item is Copy without having to actually name that item bound.

See the stabilization report for more details.

Extending automatic temporary lifetime extension

Temporaries which are immediately referenced in construction are now automatically lifetime extended in match and if constructs. This has the same behavior as lifetime extension for temporaries in block constructs.

For example:

let a = if true {
    ..;
    &temp() // used to error, but now gets lifetime extended
} else {
    ..;
    &temp() // used to error, but now gets lifetime extended
};

and

let a = match () {
    _ => {
        ..;
        &temp() // used to error, but now gets lifetime extended
    }
};

are now consistent with prior behavior:

let a = {
    ..;
    &temp() // lifetime is extended
};

This behavior is backwards compatible since these programs used to fail compilation.

Frame pointers enabled in standard library builds

The standard library distributed by the Rust project is now compiled with -Cforce-frame-pointers=yes, enabling downstream users to more easily profile their programs. Note that the standard library also continues to come up with line-level debug info (e.g., DWARF), though that is stripped by default in Cargo's release profiles.

Stabilized APIs

These APIs are now stable in const contexts:

Other changes

Check out everything that changed in Rust, Cargo, and Clippy.

Contributors to 1.79.0

Many people came together to create Rust 1.79.0. We couldn't have done it without all of you. Thanks!

Faster linking times on nightly on Linux using `rust-lld`

TL;DR: rustc will use rust-lld by default on x86_64-unknown-linux-gnu on nightly to significantly reduce linking times.

Some context

Linking time is often a big part of compilation time. When rustc needs to build a binary or a shared library, it will usually call the default linker installed on the system to do that (this can be changed on the command-line or by the target for which the code is compiled).

The linkers do an important job, with concerns about stability, backwards-compatibility and so on. For these and other reasons, on the most popular operating systems they usually are older programs, designed when computers only had a single core. So, they usually tend to be slow on a modern machine. For example, when building ripgrep 13 in debug mode on Linux, roughly half of the time is actually spent in the linker.

There are different linkers, however, and the usual advice to improve linking times is to use one of these newer and faster linkers, like LLVM's lld or Rui Ueyama's mold.

Some of Rust's wasm and aarch64 targets already use lld by default. When using rustup, rustc ships with a version of lld for this purpose. When CI builds LLVM to use in the compiler, it also builds the linker and packages it. It's referred to as rust-lld to avoid colliding with any lld already installed on the user's machine.

Since improvements to linking times are substantial, it would be a good default to use in the most popular targets. This has been discussed for a long time, for example in issues #39915 and #71515, and rustc already offers nightly flags to use rust-lld.

By now, we believe we've done all the internal testing that we could, on CI, crater, and our benchmarking infrastructure. We would now like to expand testing and gather real-world feedback and use-cases. Therefore, we will enable rust-lld to be the linker used by default on x86_64-unknown-linux-gnu for nightly builds.

Benefits

While this also enables the compiler to use more linker features in the future, the most immediate benefit is much improved linking times.

Here are more details from the ripgrep example mentioned above: linking is reduced 7x, resulting in a 40% reduction in end-to-end compilation times.

Before/after comparison of a ripgrep debug build

Most binaries should see some improvements here, but it's especially significant with e.g. bigger binaries, or when involving debuginfo. These usually see bottlenecks in the linker.

Here's a link to the complete results from our benchmarks.

If testing goes well, we can then stabilize using this faster linker by default for x86_64-unknown-linux-gnu users, before maybe looking at other targets.

Possible drawbacks

From our prior testing, we don't really expect issues to happen in practice. It is a drop-in replacement for the vast majority of cases, but lld is not bug-for-bug compatible with GNU ld.

In any case, using rust-lld can be disabled if any problem occurs: use the -Z linker-features=-lld flag to revert to using the system's default linker.

Some crates somehow relying on these differences could need additional link args. For example, we saw <20 crates in the crater run failing to link because of a different default about encapsulation symbols: these could require -Clink-arg=-Wl,-z,nostart-stop-gc to match the legacy GNU ld behavior.

Some of the big gains in performance come from parallelism, which could be undesirable in resource-constrained environments.

Summary

rustc will use rust-lld on x86_64-unknown-linux-gnu nightlies, for much improved linking times, starting in tomorrow's rustup nightly (nightly-2024-05-18). Let us know if you encounter problems, by opening an issue on GitHub.

If that happens, you can revert to the default linker with the -Z linker-features=-lld flag. Either by adding it to the usual RUSTFLAGS environment variable, or to a project's .cargo/config.toml configuration file, like so:

[target.x86_64-unknown-linux-gnu]
rustflags = ["-Zlinker-features=-lld"]

Rust participates in OSPP 2024

Similar to our previous announcements of the Rust Project's participation in Google Summer of Code (GSoC), we are now announcing our participation in Open Source Promotion Plan (OSPP) 2024.

OSPP is a program organized in large part by The Institute of Software Chinese Academy of Sciences. Its goal is to encourage college students to participate in developing and maintaining open source software. The Rust Project is already registered and has a number of projects available for mentorship:

Eligibility is limited to students and there is a guide for potential participants. Student registration ends on the 3rd of June with the project application deadline a day later.

Unlike GSoC which allows students to propose their own projects, OSPP requires that students only apply for one of the registered projects. We do have an #ospp Zulip stream and potential contributors are encouraged to join and discuss details about the projects and connect with mentors.

After the project application window closes on June 4th, we will review and select participants, which will be announced on June 26th. From there, students will participate through to the end of September.

As with GSoC, this is our first year participating in this program. We are incredibly excited for this opportunity to further expand into new open source communities and we're hopeful for a productive and educational summer.

Automatic checking of cfgs at compile-time

By: Urgau

The Cargo and Compiler team are delighted to announce that starting with Rust 1.80 (or nightly-2024-05-05) every reachable #[cfg] will be automatically checked that they match the expected config names and values.

This can help with verifying that the crate is correctly handling conditional compilation for different target platforms or features. It ensures that the cfg settings are consistent between what is intended and what is used, helping to catch potential bugs or errors early in the development process.

This addresses a common pitfall for new and advanced users.

This is another step to our commitment to provide user-focused tooling and we are eager and excited to finally see it fixed, after more than two years since the original RFC 30131.

A look at the feature

Every time a Cargo feature is declared that feature is transformed into a config that is passed to rustc (the Rust compiler) so it can verify with it along with well known cfgs if any of the #[cfg], #![cfg_attr] and cfg! have unexpected configs and report a warning with the unexpected_cfgs lint.

Cargo.toml:

[package]
name = "foo"

[features]
lasers = []
zapping = []

src/lib.rs:

#[cfg(feature = "lasers")]  // This condition is expected
                            // as "lasers" is an expected value
                            // of the `feature` cfg
fn shoot_lasers() {}

#[cfg(feature = "monkeys")] // This condition is UNEXPECTED
                            // as "monkeys" is NOT an expected
                            // value of the `feature` cfg
fn write_shakespeare() {}

#[cfg(windosw)]             // This condition is UNEXPECTED
                            // it's supposed to be `windows`
fn win() {}

cargo check:

cargo-check

Expecting custom cfgs

UPDATE: This section was added with the release of nightly-2024-05-19.

In Cargo point-of-view: a custom cfg is one that is neither defined by rustc nor by a Cargo feature. Think of tokio_unstable, has_foo, ... but not feature = "lasers", unix or debug_assertions

Some crates might use custom cfgs, like loom, fuzzing or tokio_unstable that they expected from the environment (RUSTFLAGS or other means) and which are always statically known at compile time. For those cases, Cargo provides via the [lints] table a way to statically declare those cfgs as expected.

Defining those custom cfgs as expected is done through the special check-cfg config under [lints.rust.unexpected_cfgs]:

Cargo.toml

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(loom)', 'cfg(fuzzing)'] }

Custom cfgs in build scripts

On the other hand some crates use custom cfgs that are enabled by some logic in the crate build.rs. For those crates Cargo provides a new instruction: cargo::rustc-check-cfg2 (or cargo:rustc-check-cfg for older Cargo version).

The syntax to use is described in the rustc book section checking configuration, but in a nutshell the basic syntax of --check-cfg is:

cfg(name, values("value1", "value2", ..., "valueN"))

Note that every custom cfgs must always be expected, regardless if the cfg is active or not!

build.rs example

build.rs:

fn main() {
    println!("cargo::rustc-check-cfg=cfg(has_foo)");
    //        ^^^^^^^^^^^^^^^^^^^^^^ new with Cargo 1.80
    if has_foo() {
        println!("cargo::rustc-cfg=has_foo");
    }
}

Each cargo::rustc-cfg should have an accompanying unconditional cargo::rustc-check-cfg directive to avoid warnings like this: unexpected cfg condition name: has_foo.

Equivalence table

cargo::rustc-cfg cargo::rustc-check-cfg
foo cfg(foo) or cfg(foo, values(none()))
foo="" cfg(foo, values(""))
foo="bar" cfg(foo, values("bar"))
foo="1" and foo="2" cfg(foo, values("1", "2"))
foo="1" and bar="2" cfg(foo, values("1")) and cfg(bar, values("2"))
foo and foo="bar" cfg(foo, values(none(), "bar"))

More details can be found in the rustc book.

Frequently asked questions

Can it be disabled?

For Cargo users, the feature is always on and cannot be disabled, but like any other lints it can be controlled: #![warn(unexpected_cfgs)].

Does the lint affect dependencies?

No, like most lints, unexpected_cfgs will only be reported for local packages thanks to cap-lints.

How does it interact with the RUSTFLAGS env?

You should be able to use the RUSTFLAGS environment variable like it was before. Currently --cfg arguments are not checked, only usage in code are.

This means that doing RUSTFLAGS="--cfg tokio_unstable" cargo check will not report any warnings, unless tokio_unstable is used within your local crates, in which case crate author will need to make sure that that custom cfg is expected with cargo::rustc-check-cfg in the build.rs of that crate.

How to expect custom cfgs without a build.rs?

UPDATE: Cargo with nightly-2024-05-19 now provides the [lints.rust.unexpected_cfgs.check-cfg] config to address the statically known custom cfgs.

There is currently no way to expect a custom cfg other than with cargo::rustc-check-cfg in a build.rs.

Crate authors that don't want to use a build.rs and cannot use [lints.rust.unexpected_cfgs.check-cfg], are encouraged to use Cargo features instead.

How does it interact with other build systems?

Non-Cargo based build systems are not affected by the lint by default. Build system authors that wish to have the same functionality should look at the rustc documentation for the --check-cfg flag for a detailed explanation of how to achieve the same functionality.

  1. The stabilized implementation and RFC 3013 diverge significantly, in particular there is only one form for --check-cfg: cfg() (instead of values() and names() being incomplete and subtlety incompatible with each other). ↩

  2. cargo::rustc-check-cfg will start working in Rust 1.80 (or nightly-2024-05-05). From Rust 1.77 to Rust 1.79 (inclusive) it is silently ignored. In Rust 1.76 and below a warning is emitted when used without the unstable Cargo flag -Zcheck-cfg. ↩

Announcing Rustup 1.27.1

The Rustup team is happy to announce the release of Rustup version 1.27.1. Rustup is the recommended tool to install Rust, a programming language that is empowering everyone to build reliable and efficient software.

If you have a previous version of Rustup installed, getting Rustup 1.27.1 is as easy as stopping any programs which may be using Rustup (e.g. closing your IDE) and running:

$ rustup self update

Rustup will also automatically update itself at the end of a normal toolchain update:

$ rustup update

If you don't have it already, you can get Rustup from the appropriate page on our website.

What's new in Rustup 1.27.1

This new Rustup release involves some minor bug fixes.

The headlines for this release are:

  1. Prebuilt Rustup binaries should be working on older macOS versions again.
  2. rustup-init will no longer fail when fish is installed but ~/.config/fish/conf.d hasn't been created.
  3. Regressions regarding symlinked RUSTUP_HOME/(toolchains|downloads|tmp) have been addressed.

Full details are available in the changelog!

Rustup's documentation is also available in the Rustup Book.

Thanks

Thanks again to all the contributors who made Rustup 1.27.1 possible!

  • Anas (0x61nas)
  • cuiyourong (cuiyourong)
  • Dirkjan Ochtman (djc)
  • Eric Huss (ehuss)
  • eth3lbert (eth3lbert)
  • hev (heiher)
  • klensy (klensy)
  • Chih Wang (ongchi)
  • Adam (pie-flavor)
  • rami3l (rami3l)
  • Robert (rben01)
  • Robert Collins (rbtcollins)
  • Sun Bin (shandongbinzhou)
  • Samuel Moelius (smoelius)
  • vpochapuis (vpochapuis)
  • Renovate Bot (renovate)

Announcing Rust 1.78.0

The Rust team is happy to announce a new version of Rust, 1.78.0. Rust is a programming language empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup, you can get 1.78.0 with:

$ rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website, and check out the detailed release notes for 1.78.0.

If you'd like to help us out by testing future releases, you might consider updating locally to use the beta channel (rustup default beta) or the nightly channel (rustup default nightly). Please report any bugs you might come across!

What's in 1.78.0 stable

Diagnostic attributes

Rust now supports a #[diagnostic] attribute namespace to influence compiler error messages. These are treated as hints which the compiler is not required to use, and it is also not an error to provide a diagnostic that the compiler doesn't recognize. This flexibility allows source code to provide diagnostics even when they're not supported by all compilers, whether those are different versions or entirely different implementations.

With this namespace comes the first supported attribute, #[diagnostic::on_unimplemented], which can be placed on a trait to customize the message when that trait is required but hasn't been implemented on a type. Consider the example given in the stabilization pull request:

#[diagnostic::on_unimplemented(
    message = "My Message for `ImportantTrait<{A}>` is not implemented for `{Self}`",
    label = "My Label",
    note = "Note 1",
    note = "Note 2"
)]
trait ImportantTrait<A> {}

fn use_my_trait(_: impl ImportantTrait<i32>) {}

fn main() {
    use_my_trait(String::new());
}

Previously, the compiler would give a builtin error like this:

error[E0277]: the trait bound `String: ImportantTrait<i32>` is not satisfied
  --> src/main.rs:12:18
   |
12 |     use_my_trait(String::new());
   |     ------------ ^^^^^^^^^^^^^ the trait `ImportantTrait<i32>` is not implemented for `String`
   |     |
   |     required by a bound introduced by this call
   |

With #[diagnostic::on_unimplemented], its custom message fills the primary error line, and its custom label is placed on the source output. The original label is still written as help output, and any custom notes are written as well. (These exact details are subject to change.)

error[E0277]: My Message for `ImportantTrait<i32>` is not implemented for `String`
  --> src/main.rs:12:18
   |
12 |     use_my_trait(String::new());
   |     ------------ ^^^^^^^^^^^^^ My Label
   |     |
   |     required by a bound introduced by this call
   |
   = help: the trait `ImportantTrait<i32>` is not implemented for `String`
   = note: Note 1
   = note: Note 2

For trait authors, this kind of diagnostic is more useful if you can provide a better hint than just talking about the missing implementation itself. For example, this is an abridged sample from the standard library:

#[diagnostic::on_unimplemented(
    message = "the size for values of type `{Self}` cannot be known at compilation time",
    label = "doesn't have a size known at compile-time"
)]
pub trait Sized {}

For more information, see the reference section on the diagnostic tool attribute namespace.

Asserting unsafe preconditions

The Rust standard library has a number of assertions for the preconditions of unsafe functions, but historically they have only been enabled in #[cfg(debug_assertions)] builds of the standard library to avoid affecting release performance. However, since the standard library is usually compiled and distributed in release mode, most Rust developers weren't ever executing these checks at all.

Now, the condition for these assertions is delayed until code generation, so they will be checked depending on the user's own setting for debug assertions -- enabled by default in debug and test builds. This change helps users catch undefined behavior in their code, though the details of how much is checked are generally not stable.

For example, slice::from_raw_parts requires an aligned non-null pointer. The following use of a purposely-misaligned pointer has undefined behavior, and while if you were unlucky it may have appeared to "work" in the past, the debug assertion can now catch it:

fn main() {
    let slice: &[u8] = &[1, 2, 3, 4, 5];
    let ptr = slice.as_ptr();

    // Create an offset from `ptr` that will always be one off from `u16`'s correct alignment
    let i = usize::from(ptr as usize & 1 == 0);
    
    let slice16: &[u16] = unsafe { std::slice::from_raw_parts(ptr.add(i).cast::<u16>(), 2) };
    dbg!(slice16);
}
thread 'main' panicked at library/core/src/panicking.rs:220:5:
unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread caused non-unwinding panic. aborting.

Deterministic realignment

The standard library has a few functions that change the alignment of pointers and slices, but they previously had caveats that made them difficult to rely on in practice, if you followed their documentation precisely. Those caveats primarily existed as a hedge against const evaluation, but they're only stable for non-const use anyway. They are now promised to have consistent runtime behavior according to their actual inputs.

  • pointer::align_offset computes the offset needed to change a pointer to the given alignment. It returns usize::MAX if that is not possible, but it was previously permitted to always return usize::MAX, and now that behavior is removed.

  • slice::align_to and slice::align_to_mut both transmute slices to an aligned middle slice and the remaining unaligned head and tail slices. These methods now promise to return the largest possible middle part, rather than allowing the implementation to return something less optimal like returning everything as the head slice.

Stabilized APIs

These APIs are now stable in const contexts:

Compatibility notes

  • As previously announced, Rust 1.78 has increased its minimum requirement to Windows 10 for the following targets:
    • x86_64-pc-windows-msvc
    • i686-pc-windows-msvc
    • x86_64-pc-windows-gnu
    • i686-pc-windows-gnu
    • x86_64-pc-windows-gnullvm
    • i686-pc-windows-gnullvm
  • Rust 1.78 has upgraded its bundled LLVM to version 18, completing the announced u128/i128 ABI change for x86-32 and x86-64 targets. Distributors that use their own LLVM older than 18 may still face the calling convention bugs mentioned in that post.

Other changes

Check out everything that changed in Rust, Cargo, and Clippy.

Contributors to 1.78.0

Many people came together to create Rust 1.78.0. We couldn't have done it without all of you. Thanks!

Announcing Google Summer of Code 2024 selected projects

The Rust Project is participating in Google Summer of Code (GSoC) 2024, a global program organized by Google which is designed to bring new contributors to the world of open-source.

In February, we published a list of GSoC project ideas, and started discussing these projects with potential GSoC applicants on our Zulip. We were pleasantly surprised by the amount of people that wanted to participate in these projects and that led to many fruitful discussions with members of various Rust teams. Some of them even immediately began contributing to various repositories of the Rust Project, even before GSoC officially started!

After the initial discussions, GSoC applicants prepared and submitted their project proposals. We received 65 (!) proposals in total. We are happy to see that there was so much interest, given that this is the first time the Rust Project is participating in GSoC.

A team of mentors primarily composed of Rust Project contributors then thoroughly examined the submitted proposals. GSoC required us to produce a ranked list of the best proposals, which was a challenging task in itself since Rust is a big project with many priorities! We went through many rounds of discussions and had to consider many factors, such as prior conversations with the given applicant, the quality and scope of their proposal, the importance of the proposed project for the Rust Project and its wider community, but also the availability of mentors, who are often volunteers and thus have limited time available for mentoring.

In many cases, we had multiple proposals that aimed to accomplish the same goal. Therefore, we had to pick only one per project topic despite receiving several high-quality proposals from people we'd love to work with. We also often had to choose between great proposals targeting different work within the same Rust component to avoid overloading a single mentor with multiple projects.

In the end, we narrowed the list down to twelve best proposals, which we felt was the maximum amount that we could realistically support with our available mentor pool. We submitted this list and eagerly awaited how many of these twelve proposals would be accepted into GSoC.

Selected projects

On the 1st of May, Google has announced the accepted projects. We are happy to announce that 9 proposals out of the twelve that we have submitted were accepted by Google, and will thus participate in Google Summer of Code 2024! Below you can find the list of accepted proposals (in alphabetical order), along with the names of their authors and the assigned mentor(s):

Congratulations to all applicants whose project was selected! The mentors are looking forward to working with you on these exciting projects to improve the Rust ecosystem. You can expect to hear from us soon, so that we can start coordinating the work on your GSoC projects.

We would also like to thank all the applicants whose proposal was sadly not accepted, for their interactions with the Rust community and contributions to various Rust projects. There were some great proposals that did not make the cut, in large part because of limited review capacity. However, even if your proposal was not accepted, we would be happy if you would consider contributing to the projects that got you interested, even outside GSoC! Our project idea list is still actual, and could serve as a general entry point for contributors that would like to work on projects that would help the Rust Project maintainers and the Rust ecosystem.

Assuming our involvement in GSoC 2024 is successful, there's a good chance we'll participate next year as well (though we can't promise anything yet) and we hope to receive your proposals again in the future! We also are planning to participate in similar programs in the very near future. Those announcements will come in separate blog posts, so make sure to subscribe to this blog so that you don't miss anything.

The accepted GSoC projects will run for several months. After GSoC 2024 finishes (in autumn of 2024), we plan to publish a blog post in which we will summarize the outcome of the accepted projects.

Security advisory for the standard library (CVE-2024-24576)

The Rust Security Response WG was notified that the Rust standard library did not properly escape arguments when invoking batch files (with the bat and cmd extensions) on Windows using the Command API. An attacker able to control the arguments passed to the spawned process could execute arbitrary shell commands by bypassing the escaping.

The severity of this vulnerability is critical if you are invoking batch files on Windows with untrusted arguments. No other platform or use is affected.

This vulnerability is identified by CVE-2024-24576.

Overview

The Command::arg and Command::args APIs state in their documentation that the arguments will be passed to the spawned process as-is, regardless of the content of the arguments, and will not be evaluated by a shell. This means it should be safe to pass untrusted input as an argument.

On Windows, the implementation of this is more complex than other platforms, because the Windows API only provides a single string containing all the arguments to the spawned process, and it's up to the spawned process to split them. Most programs use the standard C run-time argv, which in practice results in a mostly consistent way arguments are splitted.

One exception though is cmd.exe (used among other things to execute batch files), which has its own argument splitting logic. That forces the standard library to implement custom escaping for arguments passed to batch files. Unfortunately it was reported that our escaping logic was not thorough enough, and it was possible to pass malicious arguments that would result in arbitrary shell execution.

Mitigations

Due to the complexity of cmd.exe, we didn't identify a solution that would correctly escape arguments in all cases. To maintain our API guarantees, we improved the robustness of the escaping code, and changed the Command API to return an InvalidInput error when it cannot safely escape an argument. This error will be emitted when spawning the process.

The fix will be included in Rust 1.77.2, to be released later today.

If you implement the escaping yourself or only handle trusted inputs, on Windows you can also use the CommandExt::raw_arg method to bypass the standard library's escaping logic.

Affected Versions

All Rust versions before 1.77.2 on Windows are affected, if your code or one of your dependencies executes batch files with untrusted arguments. Other platforms or other uses on Windows are not affected.

Acknowledgments

We want to thank RyotaK for responsibly disclosing this to us according to the Rust security policy, and Simon Sawicki (Grub4K) for identifying some of the escaping rules we adopted in our fix.

We also want to thank the members of the Rust project who helped us disclose the vulnerability: Chris Denton for developing the fix; Mara Bos for reviewing the fix; Pietro Albini for writing this advisory; Pietro Albini, Manish Goregaokar and Josh Stone for coordinating this disclosure; Amanieu d'Antras for advising during the disclosure.

Changes to Rust's WASI targets

WASI 0.2 was recently stabilized, and Rust has begun implementing first-class support for it in the form of a dedicated new target. Rust 1.78 will introduce new wasm32-wasip1 (tier 2) and wasm32-wasip2 (tier 3) targets. wasm32-wasip1 is an effective rename of the existing wasm32-wasi target, freeing the target name up for an eventual WASI 1.0 release. Starting Rust 1.78 (May 2nd, 2024), users of WASI 0.1 are encouraged to begin migrating to the new wasm32-wasip1 target before the existing wasm32-wasi target is removed in Rust 1.84 (January 5th, 2025).

In this post we'll discuss the introduction of the new targets, the motivation behind it, what that means for the existing WASI targets, and a detailed schedule for these changes. This post is about the WASI targets only; the existing wasm32-unknown-unknown and wasm32-unknown-emscripten targets are unaffected by any changes in this post.

Introducing wasm32-wasip2

After nearly five years of work the WASI 0.2 specification was recently stabilized. This work builds on WebAssembly Components (think: strongly-typed ABI for Wasm), providing standard interfaces for things like asynchronous IO, networking, and HTTP. This will finally make it possible to write asynchronous networked services on top of WASI, something which wasn't possible using WASI 0.1.

People interested in compiling Rust code to WASI 0.2 today are able to do so using the cargo-component tool. This tool is able to take WASI 0.1 binaries, and transform them to WASI 0.2 Components using a shim. It also provides native support for common cargo commands such as cargo build, cargo test, and cargo run. While it introduces some inefficiencies because of the additional translation layer, in practice this already works really well and people should be able to get started with WASI 0.2 development.

We're however keen to begin making that translation layer obsolete. And for that reason we're happy to share that Rust has made its first steps towards that with the introduction of the tier 3 wasm32-wasip2 target landing in Rust 1.78. This will initially miss a lot of expected features such as stdlib support, and we don't recommend people use this target quite yet. But as we fill in those missing features over the coming months, we aim to eventually meet the criteria to become a tier 2 target, at which point the wasm32-wasip2 target would be considered ready for general use. This work will happen through 2024, and we expect for this to land before the end of the calendar year.

Renaming wasm32-wasi to wasm32-wasip1

The original name for what we now call WASI 0.1 was "WebAssembly System Interface, snapshot 1". Rust shipped support for this in 2019, and we did so knowing the target would likely undergo significant changes in the future. With the knowledge we have today though, we would not have chosen to introduce the "WASI, snapshot 1" target as wasm32-wasi. We should have instead chosen to add some suffix to the initial target triple so that the eventual stable WASI 1.0 target can just be called wasm32-wasi.

In anticipation of both an eventual WASI 1.0 target, and to preserve consistency between target names, we'll begin rolling out a name change to the existing WASI 0.1 target. Starting in Rust 1.78 (May 2nd, 2024) a new wasm32-wasip1 target will become available. Starting Rust 1.81 (September 5th, 2024) we will begin warning existing users of wasm32-wasi to migrate to wasm32-wasip1. And finally in Rust 1.84 (January 9th, 2025) the wasm32-wasi target will no longer be shipped on the stable release channel. This will provide an 8 month transition period for projects to switch to the new target name when they update their Rust toolchains.

The name wasip1 can be read as either "WASI (zero) point one" or "WASI preview one". The official specification uses the "preview" moniker, however in most communication the form "WASI 0.1" is now preferred. This target triple was chosen because it not only maps to both terms, but also more closely resembles the target terminology used in other programming languages. This is something the WASI Preview 2 specification also makes note of.

Timeline

This table provides the dates and cut-offs for the target rename from wasm32-wasi to wasm32-wasip1. The dates in this table do not apply to the newly-introduced wasm32-wasi-preview1-threads target; this will be renamed to wasm32-wasip1-threads in Rust 1.78 without going through a transition period. The tier 3 wasm32-wasip2 target will also be made available in Rust 1.78.

date Rust Stable Rust Beta Rust Nightly Notes
2024-02-08 1.76 1.77 1.78 wasm32-wasip1 available on nightly
2024-03-21 1.77 1.78 1.79 wasm32-wasip1 available on beta
2024-05-02 1.78 1.79 1.80 wasm32-wasip1 available on stable
2024-06-13 1.79 1.80 1.81 warn if wasm32-wasi is used on nightly
2024-07-25 1.80 1.81 1.82 warn if wasm32-wasi is used on beta
2024-09-05 1.81 1.82 1.83 warn if wasm32-wasi is used on stable
2024-10-17 1.82 1.83 1.84 wasm32-wasi unavailable on nightly
2024-11-28 1.83 1.84 1.85 wasm32-wasi unavailable on beta
2025-01-09 1.84 1.85 1.86 wasm32-wasi unavailable on stable

Conclusion

In this post we've discussed the upcoming updates to Rust's WASI targets. Come Rust 1.78 the wasm32-wasip1 (tier 2) and wasm32-wasip2 (tier 3) targets will be added. In Rust 1.81 we will begin warning if wasm32-wasi is being used. And in Rust 1.84, the existing wasm32-wasi target will be removed. This will free up wasm32-wasi to eventually be used for a WASI 1.0 target. Users will have 8 months to switch to the new target name when they update their Rust toolchains.

The wasm32-wasip2 target marks the start of native support for WASI 0.2. In order to target it today from Rust, people are encouraged to use cargo-component tool instead. The plan is to eventually graduate wasm32-wasip2 to a tier-2 target, at which point cargo-component will be upgraded to support it natively instead.

With WASI 0.2 finally stable, it's an exciting time for WebAssembly development. We're happy for Rust to begin implementing native support for WASI 0.2, and we're excited about what this will enable people to build.

Announcing Rust 1.77.2

The Rust team has published a new point release of Rust, 1.77.2. Rust is a programming language that is empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup, getting Rust 1.77.2 is as easy as:

rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website.

What's in 1.77.2

This release includes a fix for CVE-2024-24576.

Before this release, the Rust standard library did not properly escape arguments when invoking batch files (with the bat and cmd extensions) on Windows using the Command API. An attacker able to control the arguments passed to the spawned process could execute arbitrary shell commands by bypassing the escaping.

This vulnerability is CRITICAL if you are invoking batch files on Windows with untrusted arguments. No other platform or use is affected.

You can learn more about the vulnerability in the dedicated advisory.

Contributors to 1.77.2

Many people came together to create Rust 1.77.2. We couldn't have done it without all of you. Thanks!

❌