Rust Blog: Posts

Rust Blog

Announcing Rust 1.71.1

The Rust team has published a new point release of Rust, 1.71.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.71.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.71.1 stable

Rust 1.71.1 fixes Cargo not respecting the umask when extracting dependencies, which could allow a local attacker to edit the cache of extracted source code belonging to another local user, potentially executing code as another user. This security vulnerability is tracked as CVE-2023-38497, and you can read more about it on the advisory we published earlier today. We recommend all users to update their toolchain as soon as possible.

Rust 1.71.1 also addresses several regressions introduced in Rust 1.71.0, including bash completion being broken for users of Rustup, and thesuspicious_double_ref_op being emitted when calling borrow() even though it shouldn't.

You can find more detailed information on the specific regressions, and other minor fixes, in the release notes.

Contributors to 1.71.1

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

Continue Reading…

Rust Blog

Security advisory for Cargo (CVE-2023-38497)

This is a cross-post of the official security advisory. The official advisory contains a signed version with our PGP key, as well.

The Rust Security Response WG was notified that Cargo did not respect the umask when extracting crate archives on UNIX-like systems. If the user downloaded a crate containing files writeable by any local user, another local user could exploit this to change the source code compiled and executed by the current user.

This vulnerability has been assigned CVE-2023-38497.

Overview

In UNIX-like systems, each file has three sets of permissions: for the user owning the file, for the group owning the file, and for all other local users. The "umask" is configured on most systems to limit those permissions during file creation, removing dangerous ones. For example, the default umask on macOS and most Linux distributions only allow the user owning a file to write to it, preventing the group owning it or other local users from doing the same.

When a dependency is downloaded by Cargo, its source code has to be extracted on disk to allow the Rust compiler to read as part of the build. To improve performance, this extraction only happens the first time a dependency is used, caching the pre-extracted files for future invocations.

Unfortunately, it was discovered that Cargo did not respect the umask during extraction, and propagated the permissions stored in the crate archive as-is. If an archive contained files writeable by any user on the system (and the system configuration didn't prevent writes through other security measures), another local user on the system could replace or tweak the source code of a dependency, potentially achieving code execution the next time the project is compiled.

Affected Versions

All Rust versions before 1.71.1 on UNIX-like systems (like macOS and Linux) are affected. Note that additional system-dependent security measures configured on the local system might prevent the vulnerability from being exploited.

Users on Windows and other non-UNIX-like systems are not affected.

Mitigations

We recommend all users to update to Rust 1.71.1, which will be released later today, as it fixes the vulnerability by respecting the umask when extracting crate archives. If you build your own toolchain, patches for 1.71.0 source tarballs are available here.

To prevent existing cached extractions from being exploitable, the Cargo binary included in Rust 1.71.1 or later will purge the caches it tries to access if they were generated by older Cargo versions.

If you cannot update to Rust 1.71.1, we recommend configuring your system to prevent other local users from accessing the Cargo directory, usually located in ~/.cargo:

chmod go= ~/.cargo

Acknowledgments

We want to thank Addison Crump 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 vulnerability: Weihang Lo for developing the fix; Eric Huss for reviewing the fix; Pietro Albini for writing this advisory; Pietro Albini, Manish Goregaokar and Josh Stone for coordinating this disclosure; Josh Triplett, Arlo Siemen, Scott Schafer, and Jacob Finkelman for advising during the disclosure.

Continue Reading…

Rust Blog

Announcing Rust 1.71.0

The Rust team is happy to announce a new version of Rust, 1.71.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.71.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.71.0 on GitHub.

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

C-unwind ABI

1.71.0 stabilizes C-unwind (and other -unwind suffixed ABI variants1).

The behavior for unforced unwinding (the typical case) is specified in this table from the RFC which proposed this feature. To summarize:

Each ABI is mostly equivalent to the same ABI without -unwind, except that with -unwind the behavior is defined to be safe when an unwinding operation (panic or C++ style exception) crosses the ABI boundary. For panic=unwind, this is a valid way to let exceptions from one language unwind the stack in another language without terminating the process (as long as the exception is caught in the same language from which it originated); for panic=abort, this will typically abort the process immediately.

For this initial stabilization, no change is made to the existing ABIs (e.g."C"), and unwinding across them remains undefined behavior. A future Rust release will amend these ABIs to match the behavior specified in the RFC as the final part in stabilizing this feature (usually aborting at the boundary). Users are encouraged to start using the new unwind ABI variants in their code to remain future proof if they need to unwind across the ABI boundary.

Debugger visualization attributes

1.71.0 stabilizes support for a new attribute, #[debug_visualizer(natvis_file = "...")] and #[debug_visualizer(gdb_script_file = "...")], which allows embedding Natviz descriptions and GDB scripts into Rust libraries to improve debugger output when inspecting data structures created by those libraries. Rust itself has packaged similar scripts for some time for the standard library, but this feature makes it possible for library authors to provide a similar experience to end users.

See the referencefor details on usage.

raw-dylib linking

On Windows platforms, Rust now supports using functions from dynamic libraries without requiring those libraries to be available at build time, using the new kind="raw-dylib” option for #[link].

This avoids requiring users to install those libraries (particularly difficult for cross-compilation), and avoids having to ship stub versions of libraries in crates to link against. This simplifies crates providing bindings to Windows libraries.

Rust also supports binding to symbols provided by DLLs by ordinal rather than named symbol, using the new #[link_ordinal] attribute.

Upgrade to musl 1.2

As previously announced, Rust 1.71 updates the musl version to 1.2.3. Most users should not be affected by this change.

Const-initialized thread locals

Rust 1.59.0 stabilized const initialized thread local support in the standard library, which allows for more optimal code generation. However, until now this feature was missed in release notes anddocumentation. Note that this stabilization does not make const { ... } a valid expression or syntax in other contexts; that is a separate and currently unstablefeature.

use std::cell::Cell;

thread_local! {
    pub static FOO: Cell<u32> = const { Cell::new(1) };
}

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

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

  1. List of stabilized ABIs can be found in the stabilization report: https://github.com/rust-lang/rust/issues/74990#issuecomment-1363473645

Continue Reading…

Rust Blog

Announcing regex 1.9

The regex sub-team is announcing the release of regex 1.9. The regex crate is maintained by the Rust project and is the recommended way to use regular expressions in Rust. Its defining characteristic is its guarantee of worst case linear time searches with respect to the size of the string being searched.

Releases of the regex crate aren't normally announced on this blog, but since the majority of its internals have been rewritten in version 1.9, this announcement serves to encourage extra scrutiny. If you run into any problems or performance regressions, please report them on the issue tracker or ask questions on the Discussion forum.

Few API additions have been made, but one worth calling out is theCaptures::extract method that should make getting capture groups in some cases more convenient. Otherwise, the main change folks should see is hopefully faster search times.

You can read more in the CHANGELOG and in a more in depth blog post onregex crate internals as a library.

Continue Reading…

Rust Blog

Rustfmt support for let-else statements

Rustfmt will add support for formatting let-else statements starting with the nightly 2023-07-02 toolchain, and then let-else formatting support should come to stable Rust as part of the 1.72 release.

Overview

let-else statements were stabilized back in 2022 as part of the 1.65.0 release. However, the current and previous versions of Rustfmt did not have formatting support for let-else statements. When Rustfmt encountered a let-else statement it would leave it alone and maintain the manual styling originally authored by the developer.

After updating to one of the toolchains with let-else formatting support, you may notice that cargo fmt/rustfmt invocations want to "change" the formatting of your let-else statements. However, this isn't actually a "change" in formatting, but instead is simply Rustfmt applying the let-else formatting rules for the very first time.

Rustfmt support for let-else statements has been a long standing request, and the Project has taken a number of steps to prevent a recurrence of the delay between feature stabilization and formatting support, as well as putting additional procedures in place which should enable more expeditious formatting support for nightly-only syntax.

Background and Context

Rust has an official Style Guide that articulates the default formatting style for Rust code. The Style Guide functions as a specification that defines the default formatting behavior for Rustfmt, and Rustfmt's primary mission is to provide automated formatting capabilities based around that Style Guide specification. Rustfmt is a direct consumer of the Style Guide, but Rustfmt does not unilaterally dictate what the default formatting style of language constructs should be.

The initial Style Guide was developed many years ago (beginning in 2016), and was driven by a Style Team in collaboration with the community through an RFC process. The Style Guide was then made official in 2018 via RFC 2436.

That initial Style Team was more akin to a Project Working Group in today's terms, as they had a fixed scope with a main goal to simply pull together the initial Style Guide. Accordingly that initial Style Team was disbanded once the Guide was made official.

There was subsequently no designated group within the Rust Project that was explicitly responsible for the Style Guide, and no group explicitly focused on determining the official Style for new language constructs.

The absence of a team/group with ownership of the Style Guide didn't really cause problems at first, as the new syntax that came along during the first few years was comparatively non-controversial when it came to default style and formatting. However, over time challenges started to develop when there was increasingly less community consensus and no governing team within the Project to make the final decision about how new language syntax should be styled.

This was certainly the case with let-else statements, with lots of varying perspectives on how they should be styled. Without any team/group to make the decision and update the Style Guide with the official rules for let-else statements, Rustfmt was blocked and was unable to proceed.

These circumstances around let-else statements resulted in a greater understanding across the Project of the need to establish a team to own and maintain the Style Guide. However, it was also well understood that spinning up a new team and respective processes would take some time, and the decision was made to not block the stabilization of features that were otherwise fully ready to be stabilized, like let-else statements, in the nascency of such a new team and new processes.

Accordingly, let-else statements were stabilized and released without formatting support and with an understanding that the new Style Team and then subsequently the Rustfmt Team would later complete the requisite work required to incorporate formatting support.

Steps Taken

A number of steps have been taken to improve matters in this space. This includes steps to address the aforementioned issues and deal with some of the "style debt" that accrued over the years in the absence of a Style Team, and also to establish new processes and mechanisms to bring about other formatting/styling improvements.

  • Launched a new, permanent Style Team that's responsible for the Style Guide.
  • Established a mechanism to evolve the default style while still maintaining stability guarantees (RFC 3338).
  • Developed a nightly-syntax-policy that provides clarity around style rules for unstable/nightly-only syntax, and enables Rustfmt to provide earlier support for such syntax.

Furthermore, the Style Team is also continuing to diligently work through the backlog of those "style debt" items, and the Rustfmt team is in turn actively working on respective formatting implementation. The Rustfmt team is also focused on growing the team in order to improve contributor and review capacity.

Conclusion

We know that many have wanted let-else formatting support for a while, and we're sorry it's taken this long. We also recognize that Rustfmt now starting to format let-else statements may cause some formatting churn, and that's a highly undesirable scenario we strive to avoid.

However, we believe the benefits of delivering let-else formatting support outweigh those drawbacks. While it's possible there may be another future case or two where we have to do something similar as we work through the style backlog, we're hopeful that over time this new team and these new processes will reduce (or eliminate) the possibility of a recurrence by addressing the historical problems that played such an outsize role in the let-else delay, and also bring about various other improvements.

Both the Style and Rustfmt teams hang out on Zulip so if you'd like to get more involved or have any questions please drop by on T-Style and/or T-Rustfmt.

Continue Reading…

Rust Blog

Improved API tokens for crates.io

If you recently generated a new API token on crates.io, you might have noticed our new API token creation page and some of the new features it now supports.

Previously, when clicking the "New Token" button on https://crates.io/settings/tokens, you were only provided with the option to choose a token name, without any additional choices. We knew that we wanted to offer our users more flexibility, but in the previous user interface that would have been difficult, so our first step was to build a proper "New API Token" page.

Our roadmap included two essential features known as "token scopes". The first of them allows you to restrict API tokens to specific operations. For instance, you can configure a token to solely enable the publishing of new versions for existing crates, while disallowing the creation of new crates. The second one offers an optional restriction where tokens can be limited to only work for specific crate names. If you want to read more about how these features were planned and implemented you can take a look at our correspondingtracking issue.

To further enhance the security of crates.io API tokens, we prioritized the implementation of expiration dates. Since we had already touched most of the token-related code this was relatively straight-forward. We are delighted to announce that our "New API Token" page now supports endpoint scopes, crate scopes and expiration dates:

Screenshot of the "New API Token" page

Similar to the API token creation process on github.com, you can choose to not have any expiration date, use one of the presets, or even choose a custom expiration date to suit your requirements.

If you come across any issues or have questions, feel free to reach out to us onZulipor open an issue on GitHub.

Lastly, we, the crates.io team, would like to express our gratitude to theOpenSSF's Alpha-Omega Initiativeand JFrogfor their contributions to the Rust Foundationsecurity initiative. Their support has been instrumental in enabling us to implement these features and undertake extensive security-related work on the crates.io codebase over the past few months.

Continue Reading…

Rust Blog

Introducing the Rust Leadership Council

As of today, RFC 3392 has been merged, forming the new top level governance body of the Rust Project: the Leadership Council. The creation of this Council marks the end of both the Core Team and the interim Leadership Chat.

The Council will assume responsibility for top-level governance concerns while most of the responsibilities of the Rust Project (such as maintenance of the compiler and core tooling, evolution of the language and standard libraries, administration of infrastructure, etc.) remain with the nine top level teams.

Each of these top level teams, as defined in the RFC, has chosen a representative who collectively form the Council:

  • Compiler: Eric Holk
  • Crates.io: Carol (Nichols || Goulding)
  • Dev Tools: Eric Huss
  • Infrastructure: Ryan Levick
  • Language: Jack Huey
  • Launching Pad1: Jonathan Pallant
  • Library: Mara Bos
  • Moderation: Khionu Sybiern
  • Release: Mark Rousskov

First, we want to take a moment to thank the Core Team and interim Leadership Chat for the hard work they've put in over the years. Their efforts have been critical for the Rust Project. However, we do recognize that the governance of the Rust Project has had its shortcomings. We hope to build on the successes and improve upon the failures to ultimately lead to greater transparency and accountability.

We know that there is a lot of work to do and we are eager to get started. In the coming weeks we will be establishing the basic infrastructure for the group, including creating a plan for regular meetings and a process for raising agenda items, setting up a team repository, and ultimately completing the transition from the former Rust leadership structures.

We will post more once this bootstrapping process has been completed.

  1. The RFC defines the launching pad team as a temporary umbrella team to represent subteams that do not currently have a top-level team.

Continue Reading…

Rust Blog

Announcing Rust 1.70.0

The Rust team is happy to announce a new version of Rust, 1.70.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.70.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.70.0 on GitHub.

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

Sparse by default for crates.io

Cargo's "sparse" protocol is now enabled by default for reading the index from crates.io. This feature was previously stabilized with Rust 1.68.0, but still required configuration to use that with crates.io. The announced plan was to make that the default in 1.70.0, and here it is!

You should see substantially improved performance when fetching information from the crates.io index. Users behind a restrictive firewall will need to ensure that access to https://index.crates.io is available. If for some reason you need to stay with the previous default of using the git index hosted by GitHub, the registries.crates-io.protocol config setting can be used to change the default.

One side-effect to note about changing the access method is that this also changes the path to the crate cache, so dependencies will be downloaded anew. Once you have fully committed to using the sparse protocol, you may want to clear out the old $CARGO_HOME/registry/*/github.com-* paths.

OnceCell and OnceLock

Two new types have been stabilized for one-time initialization of shared data, OnceCell and its thread-safe counterpart OnceLock. These can be used anywhere that immediate construction is not wanted, and perhaps not even possible like non-const data in global variables.

use std::sync::OnceLock;

static WINNER: OnceLock<&str> = OnceLock::new();

fn main() {
    let winner = std::thread::scope(|s| {
        s.spawn(|| WINNER.set("thread"));

        std::thread::yield_now(); // give them a chance...

        WINNER.get_or_init(|| "main")
    });

    println!("{winner} wins!");
}

Crates such as lazy_static and once_cell have filled this need in the past, but now these building blocks are part of the standard library, ported from once_cell's unsync and sync modules. There are still more methods that may be stabilized in the future, as well as companion LazyCell and LazyLock types that store their initializing function, but this first step in stabilization should already cover many use cases.

IsTerminal

This newly-stabilized trait has a single method, is_terminal, to determine if a given file descriptor or handle represents a terminal or TTY. This is another case of standardizing functionality that existed in external crates, like atty and is-terminal, using the C library isatty function on Unix targets and similar functionality elsewhere. A common use case is for programs to distinguish between running in scripts or interactive modes, like presenting colors or even a full TUI when interactive.

use std::io::{stdout, IsTerminal};

fn main() {
    let use_color = stdout().is_terminal();
    // if so, add color codes to program output...
}

Named levels of debug information

The -Cdebuginfo compiler option has previously only supported numbers 0..=2 for increasing amounts of debugging information, where Cargo defaults to 2 in dev and test profiles and 0 in release and bench profiles. These debug levels can now be set by name: "none" (0), "limited" (1), and "full" (2), as well as two new levels, "line-directives-only" and "line-tables-only".

The Cargo and rustc documentation both called level 1 "line tables only" before, but it was more than that with information about all functions, just not types and variables. That level is now called "limited", and the new "line-tables-only" level is further reduced to the minimum needed for backtraces with filenames and line numbers. This may eventually become the level used for -Cdebuginfo=1. The other line-directives-only level is intended for NVPTX profiling, and is otherwise not recommended.

Note that these named options are not yet available to be used via Cargo.toml. Support for that will be available in the next release 1.71.

Enforced stability in the test CLI

When #[test] functions are compiled, the executable gets a command-line interface from the test crate. This CLI has a number of options, including some that are not yet stabilized and require specifying -Zunstable-options as well, like many other commands in the Rust toolchain. However, while that's only intended to be allowed in nightly builds, that restriction wasn't active in test -- until now. Starting with 1.70.0, stable and beta builds of Rust will no longer allow unstable test options, making them truly nightly-only as documented.

There are known cases where unstable options may have been used without direct user knowledge, especially --format json used in IntelliJ Rust and other IDE plugins. Those projects are already adjusting to this change, and the status of JSON output can be followed in its tracking issue.

Stabilized APIs

Other changes

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

Contributors to 1.70.0

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

Continue Reading…

Rust Blog

On the RustConf keynote

On May 26th 2023, JeanHeyd Meneide announced they would not speak at RustConf 2023 anymore. They were invited to give a keynote at the conference, only to be told two weeks later the keynote would be demoted to a normal talk, due to a decision made within the Rust project leadership.

That decision was not right, and first off we want to publicly apologize for the harm we caused. We failed you JeanHeyd. The idea of downgrading a talk after the invitation was insulting, and nobody in leadership should have been willing to entertain it.

Everyone in leadership chat is still working to fully figure out everything that went wrong and how we can prevent all of this from happening again. That work is not finished yet. Still, we want to share some steps we are taking to reduce the risk of something like this from happening again.

The primary causes of the failure were the decision-making and communication processes of leadership chat. Leadership chat has been the top-level governance structure created after the previous Moderation Team resigned in late 2021. It’s made of all leads of top-level teams, all members of the Core Team, all project directors on the Rust Foundation board, and all current moderators. This leadership chat was meant as a short-term solution and lacked clear rules and processes for decision making and communication. This left a lot of room for misunderstandings about when a decision had actually been made and when individuals were speaking for the project versus themselves.

In this post we focus on the organizational and process failure, leaving room for individuals to publicly acknowledge their own role. Nonetheless, formal rules or governance processes should not be required to identify that demoting JeanHeyd’s keynote was the wrong thing to do. The fact is that several individuals exercised poor judgment and poor communication. Recognizing their outsized role in the situation, those individuals have opted to step back from top-level governance roles, including leadership chat and the upcoming leadership council.

Organizationally, within leadership chat we will enforce a strict consensus rule for all decision making, so that there is no longer ambiguity of whether something is an individual opinion or a group decision. We are going to launch the new governance council as soon as possible. We’ll assist the remaining teams to select their representatives in a timely manner, so that the new governance council can start and the current leadership chat can disband.

We wish to close the post by reiterating our apology to JeanHeyd, but also the wider Rust community. You deserved better than you got from us.

-- The members of leadership chat

Continue Reading…

Rust Blog

Updating Rust's Linux musl targets

Beginning with Rust 1.71 (slated for stable release on 2023-07-13), the various *-linux-musl targets will ship with musl 1.2.3. These targets currently use musl 1.1.24. While musl 1.2.3 introduces some new features, most notably 64-bit time on all platforms, it is ABI compatible with earlier musl versions.

As such, this change is unlikely to affect you.

Updated targets

The following targets will be updated:

Target

Support Tier

aarch64-unknown-linux-musl

Tier 2 with Host Tools

x86_64-unknown-linux-musl

Tier 2 with Host Tools

arm-unknown-linux-musleabi

Tier 2

arm-unknown-linux-musleabihf

Tier 2

armv5te-unknown-linux-musleabi

Tier 2

armv7-unknown-linux-musleabi

Tier 2

armv7-unknown-linux-musleabihf

Tier 2

i586-unknown-linux-musl

Tier 2

i686-unknown-linux-musl

Tier 2

mips-unknown-linux-musl

Tier 2

mips64-unknown-linux-muslabi64

Tier 2

mips64el-unknown-linux-muslabi64

Tier 2

mipsel-unknown-linux-musl

Tier 2

hexagon-unknown-linux-musl

Tier 3

mips64-openwrt-linux-musl

Tier 3

powerpc-unknown-linux-musl

Tier 3

powerpc64-unknown-linux-musl

Tier 3

powerpc64le-unknown-linux-musl

Tier 3

riscv32gc-unknown-linux-musl

Tier 3

riscv64gc-unknown-linux-musl

Tier 3

s390x-unknown-linux-musl

Tier 3

thumbv7neon-unknown-linux-musleabihf

Tier 3

Note: musl 1.2.3 does not raise the minimum required Linux kernel version for any target.

Will 64-bit time break the libc crate on 32-bit targets?

No, the musl project made this change carefully preserving ABI compatibility. The libc crate will continue to function correctly without modification.

A future version of the libc crate will update the definitions of time-related structures and functions to be 64-bit on all musl targets however this is blocked on the musl targets themselves first being updated. At present, there is no anticipated date when this change will take place and care will be taken to help the Rust ecosystem transition successfully to the updated time-related definitions.

Continue Reading…

Rust Blog

Announcing Rustup 1.26.0

The rustup working group is happy to announce the release of rustup version 1.26.0. 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.26.0 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.26.0

This version of Rustup involves a significant number of internal cleanups, both in terms of the Rustup code and its tests. In addition to a lot of work on the codebase itself, due to the length of time since the last release this one has a record number of contributors and we thank you all for your efforts and time.

The headlines for this release are:

  1. Add rust-analyzer as a proxy of rustup. Now you can call rust-analyzer and it will be proxied to the rust-analyzer component for the current toolchain.
  2. Bump the clap dependency from 2.x to 3.x. It's a major version bump, so there are some help text changes, but the command line interface is unchanged.
  3. Remove experimental GPG signature validation and the rustup show keys command. Due to its experimental status, validating the integrity of downloaded binaries did not rely on it, and there was no option to abort the installation if a signature mismatch happened. Multiple problems with its implementation were discovered in the recent months, which led to the decision to remove the experimental code. The team is working on the design of a new signature validation scheme, which will be implemented in the future.

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.26.0 possible!

  • Daniel Silverstone (kinnison)
  • Sabrina Jewson (SabrinaJewson)
  • Robert Collins (rbtcollins)
  • chansuke (chansuke)
  • Shamil (shamilsan)
  • Oli Lalonde (olalonde)
  • 二手掉包工程师 (hi-rustin)
  • Eric Huss (ehuss)
  • J Balint BIRO (jbalintbiro)
  • Easton Pillay (jedieaston)
  • zhaixiaojuan (zhaixiaojuan)
  • Chris Denton (ChrisDenton)
  • Martin Geisler (mgeisler)
  • Lucio Franco (LucioFranco)
  • Nicholas Bishop (nicholasbishop)
  • SADIK KUZU (sadikkuzu)
  • darkyshiny (darkyshiny)
  • René Dudfield (illume)
  • Noritada Kobayashi (noritada)
  • Mohammad AlSaleh (MoSal)
  • Dustin Martin (dmartin)
  • Ville Skyttä (scop)
  • Tshepang Mbambo (tshepang)
  • Illia Bobyr (ilya-bobyr)
  • Vincent Rischmann (vrischmann)
  • Alexander (Alovchin91)
  • Daniel Brotsky (brotskydotcom)
  • zohnannor (zohnannor)
  • Joshua Nelson (jyn514)
  • Prikshit Gautam (gautamprikshit1)
  • Dylan Thacker-Smith (dylanahsmith)
  • Jan David (jdno)
  • Aurora (lilith13666)
  • Pietro Albini (pietroalbini)
  • Renovate Bot (renovate-bot)

Continue Reading…

Rust Blog

Announcing Rust 1.69.0

The Rust team is happy to announce a nice version of Rust, 1.69.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.69.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.69.0 on GitHub.

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

Rust 1.69.0 introduces no major new features. However, it contains many small improvements, including over 3,000 commits from over 500 contributors.

Cargo now suggests to automatically fix some warnings

Rust 1.29.0 added the cargo fix subcommand to automatically fix some simple compiler warnings. Since then, the number of warnings that can be fixed automatically continues to steadily increase. In addition, support for automatically fixing some simple Clippy warnings has also been added.

In order to draw more attention to these increased capabilities, Cargo will now suggest running cargo fix or cargo clippy --fix when it detects warnings that are automatically fixable:

warning: unused import: `std::hash::Hash`
 --> src/main.rs:1:5
  |
1 | use std::hash::Hash;
  |     ^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: `foo` (bin "foo") generated 1 warning (run `cargo fix --bin "foo"` to apply 1 suggestion)

Note that the full Cargo invocation shown above is only necessary if you want to precisely apply fixes to a single crate. If you want to apply fixes to all the default members of a workspace, then a simple cargo fix (with no additional arguments) will suffice.

Debug information is not included in build scripts by default anymore

To improve compilation speed, Cargo now avoids emitting debug information in build scripts by default. There will be no visible effect when build scripts execute successfully, but backtraces in build scripts will contain less information.

If you want to debug a build script, you can add this snippet to your Cargo.toml to emit debug information again:

[profile.dev.build-override]
debug = true
[profile.release.build-override]
debug = true

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

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

Continue Reading…

Rust Blog

Announcing Rust 1.68.2

The Rust team has published a new point release of Rust, 1.68.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, you can get 1.68.2 with:

rustup update stable

If you don't have it already, you can get rustupfrom the appropriate page on our website, and check out thedetailed release notes for 1.68.2 on GitHub.

What's in 1.68.2 stable

Rust 1.68.2 addresses GitHub's recent rotation of their RSA SSH host key, which happened on March 24th 2023 after their previous key accidentally leaked:

Support for @revoked entries in.ssh/known_hosts (along with a better error message when the unsupported @cert-authority entries are used) is also included in Rust 1.68.2, as that change was a pre-requisite for backporting the hardcoded revocation.

If you cannot upgrade to Rust 1.68.2, we recommend following GitHub's instructionson updating the trusted keys in your system. Note that the keys bundled in Cargo are only used if no trusted key for github.com is found on the system.

Contributors to 1.68.2

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

Continue Reading…

Rust Blog

Announcing Rust 1.68.1

The Rust team has published a new point release of Rust, 1.68.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, you can get 1.68.1 with:

rustup update stable

If you don't have it already, you can get rustupfrom the appropriate page on our website, and check out thedetailed release notes for 1.68.1 on GitHub.

What's in 1.68.1 stable

Rust 1.68.1 stable primarily contains a change to how Rust's CI builds the Windows MSVC compiler, no longer enabling LTO for the Rust code. This led to amiscompilation that the Rust team is debugging, but in the meantime we're reverting the change to enable LTO.

This is currently believed to have no effect on wider usage of ThinLTO. The Rust compiler used an unstable flag as part of the build process to enable ThinLTO despite compiling to a dylib.

There are a few other regression fixes included in the release:

Contributors to 1.68.1

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

Continue Reading…

Rust Blog

Announcing Rust 1.68.0

The Rust team is happy to announce a new version of Rust, 1.68.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.68.0 with:

rustup update stable

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

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). Pleasereport any bugs you might come across!

What's in 1.68.0 stable

Cargo's sparse protocol

Cargo's "sparse" registry protocol has been stabilized for reading the index of crates, along with infrastructure at https://index.crates.io/ for those published in the primary crates.io registry. The prior git protocol (which is still the default) clones a repository that indexes all crates available in the registry, but this has started to hit scaling limitations, with noticeable delays while updating that repository. The new protocol should provide a significant performance improvement when accessing crates.io, as it will only download information about the subset of crates that you actually use.

To use the sparse protocol with crates.io, set the environment variableCARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse, or edit your.cargo/config.toml fileto add:

[registries.crates-io]
protocol = "sparse"

The sparse protocol is currently planned to become the default for crates.io in the 1.70.0 release in a few months. For more information, please see the priorannouncementon the Inside Rust Blog, as well asRFC 2789and the currentdocumentationin the Cargo Book.

Local Pin construction

The new pin! macro constructs a Pin<&mut T> from a T expression, anonymously captured in local state. This is often called stack-pinning, but that "stack" could also be the captured state of an async fn or block. This macro is similar to some crates, like tokio::pin!, but the standard library can take advantage of Pin internals and temporary lifetime extensionfor a more expression-like macro.

/// Runs a future to completion.
fn block_on<F: Future>(future: F) -> F::Output {
    let waker_that_unparks_thread = todo!();
    let mut cx = Context::from_waker(&waker_that_unparks_thread);
    // Pin the future so it can be polled.
    let mut pinned_future = pin!(future);
    loop {
        match pinned_future.as_mut().poll(&mut cx) {
            Poll::Pending => thread::park(),
            Poll::Ready(result) => return result,
        }
    }
}

In this example, the original future will be moved into a temporary local, referenced by the new pinned_future with type Pin<&mut F>, and that pin is subject to the normal borrow checker to make sure it can't outlive that local.

Default alloc error handler

When allocation fails in Rust, APIs like Box::new and Vec::push have no way to indicate that failure, so some divergent execution path needs to be taken. When using the std crate, the program will print to stderr and abort. As of Rust 1.68.0, binaries which include std will continue to have this behavior. Binaries which do not include std, only including alloc, will now panic!on allocation failure, which may be further adjusted via a #[panic_handler] if desired.

In the future, it's likely that the behavior for std will also be changed to match that of alloc-only binaries.

Stabilized APIs

These APIs are now stable in const contexts:

Other changes

  • As previously announced, Android platform support in Rust is now targeting NDK r25, which corresponds to a minimum supported API level of 19 (KitKat).

Check out everything that changed inRust,Cargo, and Clippy.

Contributors to 1.68.0

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

Continue Reading…

Rust Blog

Announcing Rust 1.67.1

The Rust team has published a new point release of Rust, 1.67.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, you can get 1.67.1 with:

rustup update stable

If you don't have it already, you can get rustupfrom the appropriate page on our website, and check out thedetailed release notes for 1.67.1 on GitHub.

What's in 1.67.1 stable

Rust 1.67.1 fixes a regression for projects that link to thin archives (.a files that reference external .o objects). The new archive writer in 1.67.0 could not read thin archives as inputs, leading to the error "Unsupported archive identifier." The compiler now uses LLVM's archive writer again, until that format is supported in the new code.

Additionally, the clippy style lint uninlined_format_args is temporarily downgraded to pedantic -- allowed by default. While the compiler has supported this format since Rust 1.58, rust-analyzer does not support it yet, so it's not necessarily good to use that style everywhere possible.

The final change is a soundness fix in Rust's own bootstrap code. This had no known problematic uses, but it did raise an error when bootstrap was compiled with 1.67 itself, rather than the prior 1.66 release as usual.

Contributors to 1.67.1

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

Continue Reading…

Rust Blog

Announcing Rustup 1.25.2

The rustup working group is announcing the release of rustup version 1.25.2. 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.25.2 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.25.2

This version of rustup fixes a warning incorrectly saying that signature verification failed for Rust releases. The warning was due to a dependency of Rustup including a time-based check preventing the use of SHA-1 from February 1st, 2023 onwards.

Unfortunately Rust's release signing key uses SHA-1 to sign its subkeys, which resulted in all signatures being marked as invalid. Rustup 1.25.2 temporarily fixes the problem by allowing again the use of SHA-1.

Why is signature verification failure only a warning?

Signature verification is currently an experimental and incomplete feature included in rustup, as it's still missing crucial features like key rotation. Until the feature is complete and ready for use, its outcomes are only displayed as warnings without a way to turn them into errors.

This is done to avoid potentially breaking installations of rustup. Signature verification will error out on failure only after the design and implementation of the feature will be finished.

Thanks

Thanks again to all the contributors who made rustup 1.25.2 possible!

  • Daniel Silverstone (kinnison)
  • Pietro Albini (pietroalbini)

Continue Reading…

Rust Blog

Announcing Rust 1.67.0

The Rust team is happy to announce a new version of Rust, 1.67.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.67.0 with:

rustup update stable

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

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). Pleasereport any bugs you might come across!

What's in 1.67.0 stable

#[must_use] effective on async fn

async functions annotated with #[must_use] now apply that attribute to the output of the returned impl Future. The Future trait itself is already annotated with #[must_use], so all types implementing Future are automatically #[must_use], which meant that previously there was no way to indicate that the output of the Future is itself significant and should be used in some way.

With 1.67, the compiler will now warn if the output isn't used in some way.

#[must_use]
async fn bar() -> u32 { 0 }

async fn caller() {
    bar().await;
}

warning: unused output of future returned by `bar` that must be used
 --> src/lib.rs:5:5
  |
5 |     bar().await;
  |     ^^^^^^^^^^^
  |
  = note: `#[warn(unused_must_use)]` on by default

std::sync::mpsc implementation updated

Rust's standard library has had a multi-producer, single-consumer channel since before 1.0, but in this release the implementation is switched out to be based on crossbeam-channel. This release contains no API changes, but the new implementation fixes a number of bugs and improves the performance and maintainability of the implementation.

Users should not notice any significant changes in behavior as of this release.

Stabilized APIs

These APIs are now stable in const contexts:

Check out everything that changed inRust,Cargo, and Clippy.

Contributors to 1.67.0

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

Continue Reading…

Rust Blog

Officially announcing the types team

Oh hey, it's another new team announcement. But I will admit: if you follow the RFCs repository, the Rust zulip, or were particularly observant on the GATs stabilization announcement post, then this might not be a surprise for you. In fact, this "new" team was officially established at the end of May last year.

There are a few reasons why we're sharing this post now (as opposed to months before or...never). First, the team finished a three day in-person/hybrid meetup at the beginning of December and we'd like to share the purpose and outcomes of that meeting. Second, posting this announcement now is just around 7 months of activity and we'd love to share what we've accomplished within this time. Lastly, as we enter into the new year of 2023, it's a great time to share a bit of where we expect to head in this year and beyond.

Background - How did we get here?

Rust has grown significantly in the last several years, in many metrics: users, contributors, features, tooling, documentation, and more. As it has grown, the list of things people want to do with it has grown just as quickly. On top of powerful and ergonomic features, the demand for powerful tools such as IDEs or learning tools for the language has become more and more apparent. New compilers (frontend and backend) are being written. And, to top it off, we want Rust to continue to maintain one of its core design principles: safety.

All of these points highlights some key needs: to be able to know how the Rust language should work, to be able to extend the language and compiler with new features in a relatively painless way, to be able to hook into the compiler and be able to query important information about programs, and finally to be able to maintain the language and compiler in an amenable and robust way. Over the years, considerable effort has been put into these needs, but we haven't quite achieved these key requirements.

To extend a little, and put some numbers to paper, there are currently around 220 open tracking issues for language, compiler, or types features that have been accepted but are not completely implemented, of which about half are at least 3 years old and many are several years older than that. Many of these tracking issues have been open for so long not solely because of bandwidth, but because working on these features is hard, in large part because putting the relevant semantics in context of the larger language properly is hard; it's not easy for anyone to take a look at them and know what needs to be done to finish them. It's clear that we still need better foundations for making changes to the language and compiler.

Another number that might shock you: there are currently 62 open unsoundness issues. This sounds much scarier than it really is: nearly all of these are edges of the compiler and language that have been found by people who specifically poke and prod to find them; in practice these will not pop up in the programs you write. Nevertheless, these are edges we want to iron out.

The Types Team

Moving forward, let's talk about a smaller subset of Rust rather than the entire language and compiler. Specifically, the parts relevant here include the type checker - loosely, defining the semantics and implementation of how variables are assigned their type, trait solving - deciding what traits are defined for which types, and borrow checking - proving that Rust's ownership model always holds. All of these can be thought of cohesively as the "type system".

As of RFC 3254, the above subset of the Rust language and compiler are under the purview of the types team. So, what exactly does this entail?

First, since around 2018, there existed the "traits working group", which had the primary goal of creating a performant and extensible definition and implementation of Rust's trait system (including the Chalk trait-solving library). As time progressed, and particularly in the latter half of 2021 into 2022, the working group's influence and responsibility naturally expanded to the type checker and borrow checker too - they are actually strongly linked and its often hard to disentangle the trait solver from the other two. So, in some ways, the types team essentially subsumes the former traits working group.

Another relevant working group is the polonius working group, which primarily works on the design and implementation of the Polonius borrow-checking library. While the working group itself will remain, it is now also under the purview of the types team.

Now, although the traits working group was essentially folded into the types team, the creation of a team has some benefits. First, like the style team (and many other teams), the types team is not a top level team. It actually, currently uniquely, has two parent teams: the lang and compiler teams. Both teams have decided to delegate decision-making authority covering the type system.

The language team has delegated the part of the design of type system. However, importantly, this design covers less of the "feel" of the features of type system and more of how it "works", with the expectation that the types team will advise and bring concerns about new language extensions where required. (This division is not strongly defined, but the expectation is generally to err on the side of more caution). The compiler team, on the other hand, has delegated the responsibility of defining and maintaining the implementation of the trait system.

One particular responsibility that has traditionally been shared between the language and compiler teams is the assessment and fixing of soundness bugs in the language related to the type system. These often arise from implementation-defined language semantics and have in the past required synchronization and input from both lang and compiler teams. In the majority of cases, the types team now has the authority to assess and implement fixes without the direct input from either parent team. This applies, importantly, for fixes that are technically backwards-incompatible. While fixing safety holes is not covered under Rust's backwards compatibility guarantees, these decisions are not taken lightly and generally require team signoff and are assessed for potential ecosystem breakage with crater. However, this can now be done under one team rather than requiring the coordination of two separate teams, which makes closing these soundness holes easier (I will discuss this more later.)

Formalizing the Rust type system

As mentioned above, a nearly essential element of the growing Rust language is to know how it should work (and to have this well documented). There are relatively recent efforts pushing for a Rust specification (like Ferrocene or this open RFC), but it would be hugely beneficial to have a formalized definition of the type system, regardless of its potential integration into a more general specification. In fact the existence of a formalization would allow a better assessment of potential new features or soundness holes, without the subtle intricacies of the rest of the compiler.

As far back as 2015, not long after the release of Rust 1.0, an experimental Rust trait solver called Chalk began to be written. The core idea of Chalk is to translate the surface syntax and ideas of the Rust trait system (e.g. traits, impls, where clauses) into a set of logic rules that can be solved using a Prolog-like solver. Then, once this set of logic and solving reaches parity with the trait solver within the compiler itself, the plan was to simply replace the existing solver. In the meantime (and continuing forward), this new solver could be used by other tools, such as rust-analyzer, where it is used today.

Now, given Chalk's age and the promises it had been hoped to be able to deliver on, you might be tempted to ask the question "Chalk, when?" - and plenty have. However, we've learned over the years that Chalk is likely not the correct long-term solution for Rust, for a few reasons. First, as mentioned a few times in this post, the trait solver is only but a part of a larger type system; and modeling how the entire type system fits together gives a more complete picture of its details than trying to model the parts separately. Second, the needs of the compiler are quite different than the needs of a formalization: the compiler needs performant code with the ability to track information required for powerful diagnostics; a good formalization is one that is not only complete, but also easy to maintain, read, and understand. Over the years, Chalk has tried to have both and it has so far ended up with neither.

So, what are the plans going forward? Well, first the types team has begun working on a formalization of the Rust typesystem, currently coined a-mir-formality. An initial experimental phase was written using PLT redex, but a Rust port is in-progress. There's lot to do still (including modeling more of the trait system, writing an RFC, and moving it into the rust-lang org), but it's already showing great promise.

Second, we've begun an initiative for writing a new trait solver in-tree. This new trait solver is more limited in scope than a-mir-formality (i.e. not intending to encompass the entire type system). In many ways, it's expected to be quite similar to Chalk, but leverage bits and pieces of the existing compiler and trait solver in order to make the transition as painless as possible. We do expect it to be pulled out-of-tree at some point, so it's being written to be as modular as possible. During out types team meetup earlier this month, we were able to hash out what we expect the structure of the solver to look like, and we've already gotten that merged into the source tree.

Finally, Chalk is no longer going to be a focus of the team. In the short term, it still may remain a useful tool for experimentation. As said before, rust-analyzer uses Chalk as its trait solver. It's also able to be used in rustc under an unstable feature flag. Thus, new ideas currently could be implemented in Chalk and battle-tested in practice. However, this benefit will likely not last long as a-mir-formality and the new in-tree trait solver because more usable and their interfaces becomes more accessible. All this is not to say that Chalk has been a failure. In fact, Chalk has taught us a lot about how to think about the Rust trait solver in a logical way and the current Rust trait solver has evolved over time to more closely model Chalk, even if incompletely. We expect to still support Chalk in some capacity for the time being, for rust-analyzer and potentially for those interested in experimenting with it.

Closing soundness holes

As brought up previously, a big benefit of creating a new types team with delegated authority from both the lang and compiler teams is the authority to assess and fix unsoundness issues mostly independently. However, a secondary benefit has actually just been better procedures and knowledge-sharing that allows the members of the team to get on the same page for what soundness issues there are, why they exist, and what it takes to fix them. For example, during our meetup earlier this month, we were able to go through the full list of soundness issues (focusing on those relevant to the type system), identify their causes, and discuss expected fixes (though most require prerequisite work discussed in the previous section).

Additionally, the team has already made a number of soundness fixes and has a few more in-progress. I won't go into details, but instead am just opting to putting them in list form:

As you can see, we're making progress on closing soundness holes. These sometimes break code, as assessed by crater. However, we do what we can to mitigate this, even when the code being broken is technically unsound.

New features

While it's not technically under the types team purview to propose and design new features (these fall more under lang team proper), there are a few instances where the team is heavily involved (if not driving) feature design.

These can be small additions, which are close to bug fixes. For example, this PR allows more permutations of lifetime outlives bounds than what compiled previously. Or, these PRs can be larger, more impactful changes, that don't fit under a "feature", but instead are tied heavily to the type system. For example, this PR makes the Sized trait coinductive, which effectively makes more cyclic bounds compile (see this test for an example).

There are also a few larger features and feature sets that have been driven by the types team, largely due to the heavy intersection with the type system. Here are a few examples:

  • Generic associated types (GATs) - The feature long predates the types team and is the only one in this list that has actually been stabilized so far. But due to heavy type system interaction, the team was able to navigate the issues that came on its final path to stabilization. See this blog post for much more details.
  • Type alias impl trait (TAITs) - Implementing this feature properly requires a thorough understanding of the type checker. This is close to stabilization. For more information, see the tracking issue.
  • Trait upcasting - This one is relatively small, but has some type system interaction. Again, see the tracking issue for an explanation of the feature.
  • Negative impls - This too predates the types team, but has recently been worked on by the team. There are still open bugs and soundness issues, so this is a bit away from stabilization, but you can follow here.
  • Return position impl traits in traits (RPITITs) and async functions in traits (AFITs) - These have only recently been possible with advances made with GATs and TAITs. They are currently tracked under a single tracking issue.

Roadmap

To conclude, let's put all of this onto a roadmap. As always, goals are best when they are specific, measurable, and time-bound. For this, we've decided to split our goals into roughly 4 stages: summer of 2023, end-of-year 2023, end-of-year 2024, and end-of-year 2027 (6 months, 1 year, 2 years, and 5 years). Overall, our goals are to build a platform to maintain a sound, testable, and documented type system that can scale to new features need by the Rust language. Furthermore, we want to cultivate a sustainable and open-source team (the types team) to maintain that platform and type system.

A quick note: some of the things here have not quite been explained in this post, but they've been included in the spirit of completeness. So, without further ado:

6 months

  • The work-in-progress new trait solver should be testable
  • a-mir-formality should be testable against the Rust test suite
  • Both TAITs and RPITITs/AFITs should be stabilized or on the path to stabilization.

EOY 2023

  • New trait solver replaces part of existing trait solver, but not used everywhere
  • We have an onboarding plan (for the team) and documentation for the new trait solver
  • a-mir-formality is integrated into the language design process

EOY 2024

  • New trait solver shared by rustc and rust-analyzer
    • Milestone: Type IR shared
  • We have a clean API for extensible trait errors that is available at least internally
  • "Shiny features"
    • Polonius in a usable state
    • Implied bounds in higher-ranked trait bounds (see this issue for an example of an issue this would fix)
    • Being able to use impl Trait basically anywhere
  • Potential edition boundary changes

EOY 2027

  • (Types) unsound issues resolved
  • Most language extensions are easy to do; large extensions are feasible
  • a-mir-formality passes 99.9% of the Rust test suite

Conclusion

It's an exciting time for Rust. As its userbase and popularity grows, the language does as well. And as the language grows, the need for a sustainable type system to support the language becomes ever more apparent. The project has formed this new types team to address this need and hopefully, in this post, you can see that the team has so far accomplished a lot. And we expect that trend to only continue over the next many years.

As always, if you'd like to get involved or have questions, please drop by the Rust zulip.

Continue Reading…

Rust Blog

Security advisory for Cargo (CVE-2022-46176)

This is a cross-post of the official security advisory. The official advisory contains a signed version with our PGP key, as well.

The Rust Security Response WG was notified that Cargo did not perform SSH host key verification when cloning indexes and dependencies via SSH. An attacker could exploit this to perform man-in-the-middle (MITM) attacks.

This vulnerability has been assigned CVE-2022-46176.

Overview

When an SSH client establishes communication with a server, to prevent MITM attacks the client should check whether it already communicated with that server in the past and what the server's public key was back then. If the key changed since the last connection, the connection must be aborted as a MITM attack is likely taking place.

It was discovered that Cargo never implemented such checks, and performed no validation on the server's public key, leaving Cargo users vulnerable to MITM attacks.

Affected Versions

All Rust versions containing Cargo before 1.66.1 are vulnerable.

Note that even if you don't explicitly use SSH for alternate registry indexes or crate dependencies, you might be affected by this vulnerability if you have configured git to replace HTTPS connections to GitHub with SSH (through git'surl..insteadOf setting), as that'd cause you to clone the crates.io index through SSH.

Mitigations

We will be releasing Rust 1.66.1 today, 2023-01-10, changing Cargo to check the SSH host key and abort the connection if the server's public key is not already trusted. We recommend everyone to upgrade as soon as possible.

Patch files for Rust 1.66.0 are also available here for custom-built toolchains.

For the time being Cargo will not ask the user whether to trust a server's public key during the first connection. Instead, Cargo will show an error message detailing how to add that public key to the list of trusted keys. Note that this might break your automated builds if the hosts you clone dependencies or indexes from are not already trusted.

Acknowledgments

Thanks to the Julia Security Team for disclosing this to us according to oursecurity policy!

We also want to thank the members of the Rust project who contributed to fixing this issue. Thanks to Eric Huss and Weihang Lo for writing and reviewing the patch, Pietro Albini for coordinating the disclosure and writing this advisory, and Josh Stone, Josh Triplett and Jacob Finkelman for advising during the disclosure.

Continue Reading…

Rust Blog

Announcing Rust 1.66.1

The Rust team has published a new point release of Rust, 1.66.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, you can get 1.66.1 with:

rustup update stable

If you don't have it already, you can get rustupfrom the appropriate page on our website, and check out thedetailed release notes for 1.66.1 on GitHub.

What's in 1.66.1 stable

Rust 1.66.1 fixes Cargo not verifying SSH host keys when cloning dependencies or registry indexes with SSH. This security vulnerability is tracked asCVE-2022-46176, and you can find more details in the advisory.

Contributors to 1.66.1

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

Continue Reading…

Rust Blog

Updating the Android NDK in Rust 1.68

We are pleased to announce that Android platform support in Rust will be modernized in Rust 1.68 as we update the target NDK from r17 to r25. As a consequence the minimum supported API level will increase from 15 (Ice Cream Sandwich) to 19 (KitKat).

In NDK r23 Android switched to using LLVM's libunwind for all architectures. This meant that

  1. If a project were to target NDK r23 or newer with previous versions of Rusta workaroundwould be required to redirect attempts to link against libgcc to instead link against libunwind. Following this update this workaround will no longer be necessary.
  2. If a project uses NDK r22 or older it will need to be updated to use r23 or newer. Information about the layout of the NDK's toolchain can be foundhere.

Going forward the Android platform will target the most recent LTS NDK, allowing Rust developers to access platform features sooner. These updates should occur yearly and will be announced in release notes.

Continue Reading…

Rust Blog

Announcing Rust 1.66.0

The Rust team is happy to announce a new version of Rust, 1.66.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.66.0 with:

rustup update stable

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

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). Pleasereport any bugs you might come across!

What's in 1.66.0 stable

Explicit discriminants on enums with fields

Enums with integer representations can now use explicit discriminants, even when they have fields.

#[repr(u8)]
enum Foo {
    A(u8),
    B(i8),
    C(bool) = 42,
}

Previously, you could use explicit discriminants on enums with representations, but only if none of their variants had fields. Explicit discriminants are useful when passing values across language boundaries where the representation of the enum needs to match in both languages. For example,

#[repr(u8)]
enum Bar {
    A,
    B,
    C = 42,
}

Here the Bar enum is guaranteed to have the same layout as u8. Each variant will use either the specified discriminant value or default to starting with 0.

assert_eq!(0, Bar::A as u8);
assert_eq!(1, Bar::B as u8);
assert_eq!(42, Bar::C as u8);

You could even add fields to enums with #[repr(Int)], and they would be laid out in a predictable way. Previously, however, you could not use these features together. That meant that making Foo::C's discriminant equal to 42 as above would be harder to achieve. You would need to add 41 hidden variants in between as a workaround with implicit discriminants!

Starting in Rust 1.66.0, the above example compiles, allowing you to use explicit discriminants on any enum with a #[repr(Int)] attribute.

core::hint::black_box

When benchmarking or examining the machine code produced by a compiler, it's often useful to prevent optimizations from occurring in certain places. In the following example, the function push_cap executes Vec::push 4 times in a loop:

fn push_cap(v: &mut Vec<i32>) {
    for i in 0..4 {
        v.push(i);
    }
}

pub fn bench_push() -> Duration { 
    let mut v = Vec::with_capacity(4);
    let now = Instant::now();
    push_cap(&mut v);
    now.elapsed()
}

If you inspect the optimized output of the compiler on x86_64, you'll notice that it looks rather short:

example::bench_push:
  sub rsp, 24
  call qword ptr [rip + std::time::Instant::now@GOTPCREL]
  lea rdi, [rsp + 8]
  mov qword ptr [rsp + 8], rax
  mov dword ptr [rsp + 16], edx
  call qword ptr [rip + std::time::Instant::elapsed@GOTPCREL]
  add rsp, 24
  ret

In fact, the entire function push_cap we wanted to benchmark has been optimized away!

We can work around this using the newly stabilized black_box function. Functionally, black_box is not very interesting: it takes the value you pass it and passes it right back. Internally, however, the compiler treats black_box as a function that could do anything with its input and return any value (as its name implies).

This is very useful for disabling optimizations like the one we see above. For example, we can hint to the compiler that the vector will actually be used for something after every iteration of the for loop.

use std::hint::black_box;

fn push_cap(v: &mut Vec<i32>) {
    for i in 0..4 {
        v.push(i);
        black_box(v.as_ptr());
    }
}

Now we can find the unrolled for loop in our optimized assembly output:

  mov dword ptr [rbx], 0
  mov qword ptr [rsp + 8], rbx
  mov dword ptr [rbx + 4], 1
  mov qword ptr [rsp + 8], rbx
  mov dword ptr [rbx + 8], 2
  mov qword ptr [rsp + 8], rbx
  mov dword ptr [rbx + 12], 3
  mov qword ptr [rsp + 8], rbx

You can also see a side effect of calling black_box in this assembly output. The instruction mov qword ptr [rsp + 8], rbx is uselessly repeated after every iteration. This instruction writes the address v.as_ptr() as the first argument of the function, which is never actually called.

Notice that the generated code is not at all concerned with the possibility of allocations introduced by the push call. This is because the compiler is still using the fact that we called Vec::with_capacity(4) in the bench_push function. You can play around with the placement of black_box, or try using it in multiple places, to see its effects on compiler optimizations.

cargo remove

In Rust 1.62.0 we introduced cargo add, a command line utility to add dependencies to your project. Now you can use cargo remove to remove dependencies.

Stabilized APIs

Other changes

There are other changes in the Rust 1.66 release, including:

  • You can now use ..=X ranges in patterns.
  • Linux builds now optimize the rustc frontend and LLVM backend with LTO and BOLT, respectively, improving both runtime performance and memory usage.

Check out everything that changed inRust,Cargo, and Clippy.

Contributors to 1.66.0

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

Continue Reading…

Rust Blog

Launching the 2022 State of Rust Survey

The 2022 State of Rust Survey is here!

It's that time again! Time for us to take a look at who the Rust community is composed of, how the Rust project is doing, and how we can improve the Rust programming experience. The Rust Survey working group is pleased to announce our 2022 State of Rust Survey! Whether or not you use Rust today, we want to know your opinions. Your responses will help the project understand its strengths and weaknesses, and establish development priorities for the future.

Completing this survey should take about 5–20 minutes and is anonymous. We will be accepting submissions for the next two weeks (until the 19th of December), and we will share our findings on blog.rust-lang.org sometime in early 2023. You can also check out last year’s results.

We're happy to be offering the survey in the following languages. If you speak multiple languages, please pick one.

Please help us spread the word by sharing the survey link on your social network feeds, at meetups, around your office, and in other communities.

If you have any questions, please see our frequently asked questions.

Finally, we wanted to thank everyone who helped develop, polish, and test the survey.

Continue Reading…

Rust Blog

Announcing Rust 1.65.0

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


Before going into the details of the new Rust release, we'd like to draw attention to the tragic death of Mahsa Amini and the death and violent suppression of many others, by the religious morality police of Iran. See https://en.wikipedia.org/wiki/Mahsa%5FAmini%5Fprotests for more details. We stand in solidarity with the people in Iran struggling for human rights.


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

rustup update stable

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

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). Pleasereport any bugs you might come across!

What's in 1.65.0 stable

Generic associated types (GATs)

Lifetime, type, and const generics can now be defined on associated types, like so:

trait Foo {
    type Bar<'x>;
}

It's hard to put into few words just how useful these can be, so here are a few example traits, to get a sense of their power:

/// An `Iterator`-like trait that can borrow from `Self`
trait LendingIterator {
    type Item<'a> where Self: 'a;

    fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}

/// Can be implemented over smart pointers, like `Rc` or `Arc`,
/// in order to allow being generic over the pointer type
trait PointerFamily {
    type Pointer<T>: Deref<Target = T>;

    fn new<T>(value: T) -> Self::Pointer<T>;
}

/// Allows borrowing an array of items. Useful for
/// `NdArray`-like types that don't necessarily store
/// data contiguously.
trait BorrowArray<T> {
    type Array<'x, const N: usize> where Self: 'x;

    fn borrow_array<'a, const N: usize>(&'a self) -> Self::Array<'a, N>;
}

As you can see, GATs are quite versatile and enable a number of patterns that are not currently able to be written. For more information, check out the post announcing thepush for stabilizationpublished last year or thestabilization announcement postpublished last week. The former goes into a bit more depth of a couple of the examples above, while the latter talks about some of the known limitations of this stabilization.

More in depth reading can be found in the associated types section of the nightly referenceor the original RFC (which was initially opened over 6.5 years ago!).

let-else statements

This introduces a new type of let statement with a refutable pattern and a diverging else block that executes when that pattern doesn't match.

let PATTERN: TYPE = EXPRESSION else {
    DIVERGING_CODE;
};

Normal let statements can only use irrefutable patterns, statically known to always match. That pattern is often just a single variable binding, but may also unpack compound types like structs, tuples, and arrays. However, that was not usable for conditional matches, like pulling out a variant of an enum -- until now! With let-else, a refutable pattern can match and bind variables in the surrounding scope like a normal let, or else diverge (e.g. break,return, panic!) when the pattern doesn't match.

fn get_count_item(s: &str) -> (u64, &str) {
    let mut it = s.split(' ');
    let (Some(count_str), Some(item)) = (it.next(), it.next()) else {
        panic!("Can't segment count item pair: '{s}'");
    };
    let Ok(count) = u64::from_str(count_str) else {
        panic!("Can't parse integer: '{count_str}'");
    };
    (count, item)
}
assert_eq!(get_count_item("3 chairs"), (3, "chairs"));

The scope of name bindings is the main thing that makes this different frommatch or if let-else expressions. You could previously approximate these patterns with an unfortunate bit of repetition and an outer let:

    let (count_str, item) = match (it.next(), it.next()) {
        (Some(count_str), Some(item)) => (count_str, item),
        _ => panic!("Can't segment count item pair: '{s}'"),
    };
    let count = if let Ok(count) = u64::from_str(count_str) {
        count
    } else {
        panic!("Can't parse integer: '{count_str}'");
    };

break from labeled blocks

Plain block expressions can now be labeled as a break target, terminating that block early. This may sound a little like a goto statement, but it's not an arbitrary jump, only from within a block to its end. This was already possible with loop blocks, and you may have seen people write loops that always execute only once, just to get a labeled break.

Now there's a language feature specifically for that! Labeled break may also include an expression value, just as with loops, letting a multi-statement block have an early "return" value.

let result = 'block: {
    do_thing();
    if condition_not_met() {
        break 'block 1;
    }
    do_next_thing();
    if condition_not_met() {
        break 'block 2;
    }
    do_last_thing();
    3
};

Splitting Linux debuginfo

Back in Rust 1.51, the compiler team added support for split debug informationon macOS, and now this option is stable for use on Linux as well.

  • -Csplit-debuginfo=unpacked will split debuginfo out into multiple .dwoDWARF object files.
  • -Csplit-debuginfo=packed will produce a single .dwp DWARF package alongside your output binary with all the debuginfo packaged together.
  • -Csplit-debuginfo=off is still the default behavior, which includes DWARF data in .debug_* ELF sections of the objects and final binary.

Split DWARF lets the linker avoid processing the debuginfo (because it isn't in the object files being linked anymore), which can speed up link times!

Other targets now also accept -Csplit-debuginfo as a stable option with their platform-specific default value, but specifying other values is still unstable.

Stabilized APIs

The following methods and trait implementations are now stabilized:

Of particular note, the Backtrace API allows capturing a stack backtrace at any time, using the same platform-specific implementation that usually serves panic backtraces. This may be useful for adding runtime context to error types, for example.

These APIs are now usable in const contexts:

Compatibility notes

  • As the final step of the RLS deprecation, this release has replaced RLS with a small LSP server showing a deprecation warning, advising users to migrate to rust-analyzer.

Other changes

There are other changes in the Rust 1.65 release, including:

  • MIR inlining is now enabled for optimized compilations. This provides a 3-10% improvement in compiletimes for real world crates.
  • When scheduling builds, Cargo now sorts the queue of pending jobs to improve performance.

Check out everything that changed inRust,Cargo, and Clippy.

Contributors to 1.65.0

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

Continue Reading…

Rust Blog

Generic associated types to be stable in Rust 1.65

As of Rust 1.65, which is set to release on November 3rd, generic associated types (GATs) will be stable — over six and a half years after the original RFC was opened. This is truly a monumental achievement; however, as with a few of the other monumental features of Rust, like async or const generics, there are limitations in the initial stabilization that we plan to remove in the future.

The goal of this post is not to teach about GATs, but rather to briefly introduce them to any readers that might not know what they are and to enumerate a few of the limitations in initial stabilization that users are most likely to run into. More detailed information can be found in the RFC, in the GATs initiative repository, in the previous blog post during the start of the stabilization push, in the associated items section in the nightly reference, or in the open issues on Github for GATs

What are GATs

At its core, generic associated types allow you to have generics (type, lifetime, or const) on associated types. Note that this is really just rounding out the places where you can put generics: for example, you can already have generics on freestanding type aliases and on functions in traits. Now you can just have generics on type aliases in traits (which we just call associated types). Here's an example of what a trait with a GAT would look like:

trait LendingIterator {
    type Item<'a> where Self: 'a;

    fn next<'a>(&'a mut self) -> Self::Item<'a>;
}

Most of this should look familiar; this trait looks very similar to the Iterator trait from the standard library. Fundamentally, this version of the trait allows the next function to return an item that borrows from self. For more detail about the example, as well as some info on what that where Self: 'a is for, check out the push for stabilization post.

In general, GATs provide a foundational basis for a vast range of patterns and APIs. If you really want to get a feel for how many projects how been blocked on GATs being stable, go scroll through either the tracking issue: you will find numerous issues from other projects linking to those threads over the years saying something along the lines of "we want the API to look like X, but for that we need GATs" (or see this comment that has some of these put together already). If you're interested in how GATs enable a library to do zero-copy parsing, resulting in nearly a ten-fold performance increase, you might be interested in checking out a blog post on it by Niko Matsakis.

All in all, even if you won't need to use GATs directly, it's very possible that the libraries you use will use GATs either internally or publically for ergonomics, performance, or just because that's the only way the implementation works.

When GATs go wrong - a few current bugs and limitations

As alluded to before, this stabilization is not without its bugs and limitations. This is not atypical compared to prior large language features. We plan to fix these bugs and remove these limitations as part of ongoing efforts driven by the newly-formed types team. (Stayed tuned for more details in an official announcement soon!)

Here, we'll go over just a couple of the limitations that we've identified that users might run into.

Implied 'static requirement from higher-ranked trait bounds

Consider the following code:

trait LendingIterator {
    type Item<'a> where Self: 'a;
}

pub struct WindowsMut<'x, T> {
    slice: &'x [T],
}

impl<'x, T> LendingIterator for WindowsMut<'x, T> {
    type Item<'a> = &'a mut [T] where Self: 'a;
}

fn print_items<I>(iter: I)
where
    I: LendingIterator,
    for<'a> I::Item<'a>: Debug,
{ ... }

fn main() {
    let mut array = [0; 16];
    let slice = &mut array;
    let windows = WindowsMut { slice };
    print_items::<WindowsMut<'_, usize>>(windows);
}

Here, imagine we wanted to have a LendingIterator where the items are overlapping slices of an array. We also have a function print_items that prints every item of a LendingIterator, as long as they implement Debug. This all seems innocent enough, but the above code doesn't compile — even though it should. Without going into details here, the for<'a> I::Item<'a>: Debug currently implies that I::Item<'a> must outlive 'static.

This is not really a nice bug. And of all the ones we'll mention today, this will likely be the one that is most limiting, annoying, and tough to figure out. This pops up much more often with GATs, but can be found with code that doesn't use GATs at all. Unfortunately, fixing this requires some refactorings to the compiler that isn't a short-term project. It is on the horizon though. The good news is that, in the meantime, we are least working on improving the error message you get from this code. This is what it will look like in the upcoming stabilization:

error[E0597]: `array` does not live long enough
   |
   |     let slice = &mut array;
   |                 ^^^^^^^^^^ borrowed value does not live long enough
   |     let windows = WindowsMut { slice };
   |     print_items::<WindowsMut<'_, usize>>(windows);
   |     -------------------------------------------- argument requires that `array` is borrowed for `'static`
   | }
   | - `array` dropped here while still borrowed
   |
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
   |
   |     for<'a> I::Item<'a>: Debug,
   |                          ^^^^

It's not perfect, but it's something. It might not cover all cases, but if have a for<'a> I::Item<'a>: Trait bound somewhere and get an error that says something doesn't live long enough, you might be running into this bug. We're actively working to fix this. However, this error doesn't actually come up as often as you might expect while reading this (from our experience), so we feel the feature is still immensely useful enough even with it around.

Traits with GATs are not object safe

So, this one is a simple one. Making traits with GATs object safe is going to take a little bit of design work for its implementation. To get an idea of the work left to do here, let's start with a bit of code that you could write on stable today:

fn takes_iter(_: &dyn Iterator) {}

Well, you can write this, but it doesn't compile:

error[E0191]: the value of the associated type `Item` (from trait `Iterator`) must be specified
 --> src/lib.rs:1:23
  |
1 | fn takes_iter(_: &dyn Iterator) {}
  |                       ^^^^^^^^ help: specify the associated type: `Iterator<Item = Type>`

For a trait object to be well-formed, it must specify a value for all associated types. For the same reason, we don't want to accept the following:

fn no_associated_type(_: &dyn LendingIterator) {}

However, GATs introduce an extra bit of complexity. Take this code:

fn not_fully_generic(_: &dyn LendingIterator<Item<'static> = &'static str>) {}

So, we've specified the value of the associated type for one value of of the Item's lifetime ('static), but not for any value, like this:

fn fully_generic(_: &dyn for<'a> LendingIterator<Item<'a> = &'a str>) {}

While we have a solid idea of how to implement requirement in some future iterations of the trait solver (that uses more logical formulations), implementing it in the current trait solver is more difficult. Thus, we've chosen to hold off on this for now.

The borrow checker isn't perfect and it shows

Keeping with the LendingIterator example, let's start by looking at two methods on Iterator: for_each and filter:

trait Iterator {
    type Item;

    fn for_each<F>(self, f: F)
    where
        Self: Sized,
        F: FnMut(Self::Item);
    
    fn filter<P>(self, predicate: P) -> Filter<Self, P>
    where
        Self: Sized,
        P: FnMut(&Self::Item) -> bool;
}

Both of these take a function as an argument. Closures are often used these. Now, let's look at the LendingIterator definitions:

trait LendingIterator {
    type Item<'a> where Self: 'a;

    fn for_each<F>(mut self, mut f: F)
    where
        Self: Sized,
        F: FnMut(Self::Item<'_>);

    fn filter<P>(self, predicate: P) -> Filter<Self, P>
    where
        Self: Sized,
        P: FnMut(&Self::Item<'_>) -> bool;
}

Looks simple enough, but if it really was, would it be here? Let's start by looking at what happens when we try to use for_each:

fn iterate<T, I: for<'a> LendingIterator<Item<'a> = &'a T>>(iter: I) {
    iter.for_each(|_: &T| {})
}

error: `I` does not live long enough
   |
   |     iter.for_each(|_: &T| {})
   |                   ^^^^^^^^^^

Well, that isn't great. Turns out, this is pretty closely related to the first limitation we talked about earlier, even though the borrow checker does play a role here.

On the other hand, let's look at something that's very clearly a borrow checker problem, by looking at an implementation of the Filter struct returned by the filter method:

impl<I: LendingIterator, P> LendingIterator for Filter<I, P>
where
    P: FnMut(&I::Item<'_>) -> bool, // <- the bound from above, a function
{
    type Item<'a> = I::Item<'a> where Self: 'a; // <- Use the underlying type

    fn next(&mut self) -> Option<I::Item<'_>> {
        // Loop through each item in the underlying `LendingIterator`...
        while let Some(item) = self.iter.next() {
            // ...check if the predicate holds for the item...
            if (self.predicate)(&item) {
                // ...and return it if it does
                return Some(item);
            }
        }
        // Return `None` when we're out of items
        return None;
    }
}

Again, the implementation here shouldn't seem surprising. We, of course, run into a borrow checker error:

error[E0499]: cannot borrow `self.iter` as mutable more than once at a time
  --> src/main.rs:28:32
   |
27 |     fn next(&mut self) -> Option<I::Item<'_>> {
   |             - let's call the lifetime of this reference `'1`
28 |         while let Some(item) = self.iter.next() {
   |                                ^^^^^^^^^^^^^^^^ `self.iter` was mutably borrowed here in the previous iteration of the loop
29 |             if (self.predicate)(&item) {
30 |                 return Some(item);
   |                        ---------- returning this value requires that `self.iter` is borrowed for `'1`

This is a known limitation in the current borrow checker and should be solved in some future iteration (like Polonius).

Non-local requirements for where clauses on GATs

The last limitation we'll talk about today is a bit different than the others; it's not a bug and it shouldn't prevent any programs from compiling. But it all comes back to that where Self: 'a clause you've seen in several parts of this post. As mentioned before, if you're interested in digging a bit into why that clause is required, see the push for stabilization post.

There is one not-so-ideal requirement about this clause: you must write it on the trait. Like with where clauses on functions, you cannot add clauses to associated types in impls that aren't there in the trait. However, if you didn't add this clause, a large set of potential impls of the trait would be disallowed.

To help users not fall into the pitfall of accidentally forgetting to add this (or similar clauses that end up with the same effect for a different set of generics), we've implemented a set of rules that must be followed for a trait with GATs to compile. Let's first look at the error without writing the clause:

trait LendingIterator {
    type Item<'a>;

    fn next<'a>(&'a mut self) -> Self::Item<'a>;
}

error: missing required bound on `Item`
 --> src/lib.rs:2:5
  |
2 |     type Item<'a>;
  |     ^^^^^^^^^^^^^-
  |                  |
  |                  help: add the required where clause: `where Self: 'a`
  |
  = note: this bound is currently required to ensure that impls have maximum flexibility
  = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information

This error should hopefully be helpful (you can even cargo fix it!). But, what exactly are these rules? Well, ultimately, they end up being somewhat simple: for methods that use the GAT, any bounds that can be proven must also be present on the GAT itself.

Okay, so how did we end up with the required Self: 'a bound. Well, let's take a look at the next method. It returns Self::Item<'a>, and we have an argument &'a mut self. We're getting a bit into the details of the Rust language, but because of that argument, we know that Self: 'a must hold. So, we require that bound.

We're requiring these bounds now to leave room in the future to potentially imply these automatically (and of course because it should help users write traits with GATs). They shouldn't interfere with any real use-cases, but if you do encounter a problem, check out the issue mentioned in the error above. And if you want to see a fairly comprehensive testing of different scenarios on what bounds are required and when, check out the relevant test file.

Conclusion

Hopefully the limitations brought up here and explanations thereof don't detract from overall excitement of GATs stabilization. Sure, these limitations do, well, limit the number of things you can do with GATs. However, we would not be stabilizing GATs if we didn't feel that GATs are not still very useful. Additionally, we wouldn't be stabilizing GATs if we didn't feel that the limitations weren't solvable (and in a backwards-compatible manner).

To conclude things, all the various people involved in getting this stabilization to happen deserve the utmost thanks. As said before, it's been 6.5 years coming and it couldn't have happened without everyone's support and dedication. Thanks all!

Continue Reading…

Rust Blog

Announcing Rust 1.64.0

The Rust team is happy to announce a new version of Rust, 1.64.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.64.0 with:

rustup update stable

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

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). Pleasereport any bugs you might come across!

What's in 1.64.0 stable

Enhancing .await with IntoFuture

Rust 1.64 stabilizes theIntoFuturetrait. IntoFuture is a trait similar toIntoIterator, but rather than supporting for ... in ... loops, IntoFuture changes how.await works. With IntoFuture, the .await keyword can await more than just futures; it can await anything which can be converted into a Future viaIntoFuture - which can help make your APIs more user-friendly!

Take for example a builder which constructs requests to some storage provider over the network:

pub struct Error { ... }
pub struct StorageResponse { ... }:
pub struct StorageRequest(bool);

impl StorageRequest {
    /// Create a new instance of `StorageRequest`.
    pub fn new() -> Self { ... }
    /// Decide whether debug mode should be enabled.
    pub fn set_debug(self, b: bool) -> Self { ... }
    /// Send the request and receive a response.
    pub async fn send(self) -> Result<StorageResponse, Error> { ... }
}

Typical usage would likely look something like this:

let response = StorageRequest::new()  // 1. create a new instance
    .set_debug(true)                  // 2. set some option
    .send()                           // 3. construct the future
    .await?;                          // 4. run the future + propagate errors

This is not bad, but we can do better here. Using IntoFuture we can combine_"construct the future"_ (line 3) and "run the future" (line 4) into a single step:

let response = StorageRequest::new()  // 1. create a new instance
    .set_debug(true)                  // 2. set some option
    .await?;                          // 3. construct + run the future + propagate errors

We can do this by implementing IntoFuture for StorageRequest. IntoFuturerequires us to have a named future we can return, which we can do by creating a "boxed future" and defining a type alias for it:

// First we must import some new types into the scope.
use std::pin::Pin;
use std::future::{Future, IntoFuture};

pub struct Error { ... }
pub struct StorageResponse { ... }
pub struct StorageRequest(bool);

impl StorageRequest {
    /// Create a new instance of `StorageRequest`.
    pub fn new() -> Self { ... }
    /// Decide whether debug mode should be enabled.
    pub fn set_debug(self, b: bool) -> Self { ... }
    /// Send the request and receive a response.
    pub async fn send(self) -> Result<StorageResponse, Error> { ... }
}

// The new implementations:
// 1. create a new named future type
// 2. implement `IntoFuture` for `StorageRequest`
pub type StorageRequestFuture = Pin<Box<dyn Future<Output = Result<StorageResponse, Error> + Send + 'static>>
impl IntoFuture for StorageRequest {
    type IntoFuture = StorageRequestFuture;
    type Output = <StorageRequestFuture as Future>::Output;
    fn into_future(self) -> Self::IntoFuture {
        Box::pin(self.send())
    }
}

This takes a bit more code to implement, but provides a simpler API for users.

In the future, the Rust Async WG hopes to simplify the creating new named futures by supporting impl Trait in type aliases (Type Alias Impl Trait or TAIT). This should make implementing IntoFuture easier by simplifying the type alias' signature, and make it more performant by removing the Box from the type alias.

C-compatible FFI types in core and alloc

When calling or being called by C ABIs, Rust code can use type aliases likec_uint or c_ulong to match the corresponding types from C on any target, without requiring target-specific code or conditionals.

Previously, these type aliases were only available in std, so code written for embedded targets and other scenarios that could only use core or alloccould not use these types.

Rust 1.64 now provides all of the c_* type aliases incore::ffi, as well ascore::ffi::CStr for working with C strings. Rust 1.64 also providesalloc::ffi::CStringfor working with owned C strings using only the alloc crate, rather than the full std library.

rust-analyzer is now available via rustup

rust-analyzer is now included as part of the collection of tools included with Rust. This makes it easier to download and access rust-analyzer, and makes it available on more platforms. It is available as a rustup component which can be installed with:

rustup component add rust-analyzer

At this time, to run the rustup-installed version, you need to invoke it this way:

rustup run rust-analyzer

The next release of rustup will provide a built-in proxy so that running the executable rust-analyzer will launch the appropriate version.

Most users should continue to use the releases provided by the rust-analyzer team (available on the rust-analyzer releases page), which are published more frequently. Users of the official VSCode extensionare not affected since it automatically downloads and updates releases in the background.

Cargo improvements: workspace inheritance and multi-target builds

When working with collections of related libraries or binary crates in one Cargo workspace, you can now avoid duplication of common field values between crates, such as common version numbers, repository URLs, or rust-version. This also helps keep these values in sync between crates when updating them. For more details, seeworkspace.package,workspace.dependencies, and "inheriting a dependency from a workspace".

When building for multiple targets, you can now pass multiple --targetoptions to cargo build, to build all of those targets at once. You can also setbuild.targetto an array of multiple targets in .cargo/config.toml to build for multiple targets by default.

Stabilized APIs

The following methods and trait implementations are now stabilized:

These types were previously stable in std::ffi, but are now also available incore and alloc:

These types were previously stable in std::os::raw, but are now also available in core::ffi and std::ffi:

We've stabilized some helpers for use with Poll, the low-level implementation underneath futures:

In the future, we hope to provide simpler APIs that require less use of low-level details like Poll and Pin, but in the meantime, these helpers make it easier to write such code.

These APIs are now usable in const contexts:

Compatibility notes

  • As previously announced,linux targets now require at least Linux kernel 3.2 (except for targets which already required a newer kernel), and linux-gnu targets now require glibc 2.17 (except for targets which already required a newer glibc).
  • Rust 1.64.0 changes the memory layout of Ipv4Addr, Ipv6Addr,SocketAddrV4 and SocketAddrV6 to be more compact and memory efficient. This internal representation was never exposed, but some crates relied on it anyway by using std::mem::transmute, resulting in invalid memory accesses. Such internal implementation details of the standard library are_never_ considered a stable interface. To limit the damage, we worked with the authors of all of the still-maintained crates doing so to release fixed versions, which have been out for more than a year. The vast majority of impacted users should be able to mitigate with a cargo update.
  • As part of the RLS deprecation, this is also the last release containing a copy of RLS. Starting from Rust 1.65.0, RLS will be replaced by a small LSP server showing the deprecation warning.

Other changes

There are other changes in the Rust 1.64 release, including:

  • Windows builds of the Rust compiler now use profile-guided optimization, providing performance improvements of 10-20% for compiling Rust code on Windows.
  • If you define a struct containing fields that are never used, rustc will warn about the unused fields. Now, in Rust 1.64, you can enable theunused_tuple_struct_fields lint to get the same warnings about unused fields in a tuple struct. In future versions, we plan to make this lint warn by default. Fields of type unit (()) do not produce this warning, to make it easier to migrate existing code without having to change tuple indices.

Check out everything that changed inRust,Cargo, and Clippy.

Contributors to 1.64.0

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

Continue Reading…

Rust Blog

Const Eval (Un)Safety Rules

In a recent Rust issue (#99923), a developer noted that the upcoming 1.64-beta version of Rust had started signalling errors on their crate,icu4x. The icu4x crate uses unsafe code during const evaluation.Const evaluation, or just "const-eval", runs at compile-time but produces values that may end up embedded in the final object code that executes at runtime.

Rust's const-eval system supports both safe and unsafe Rust, but the rules for what unsafe code is allowed to do during const-eval are even more strict than what is allowed for unsafe code at runtime. This post is going to go into detail about one of those rules.

(Note: If your const code does not use any unsafe blocks or call any const fnwith an unsafe block, then you do not need to worry about this!)

A new diagnostic to watch for

The problem, reduced over the course of the comment thread of #99923, is that certain static initialization expressions (see below) are defined as having undefined behavior (UB) at compile time (playground):

pub static FOO: () = unsafe {
    let illegal_ptr2int: usize = std::mem::transmute(&());
    let _copy = illegal_ptr2int;
};

(Many thanks to @eddyb for the minimal reproduction!)

The code above was accepted by Rust versions 1.63 and earlier, but in the Rust 1.64-beta, it now causes a compile time error with the following message:

error[E0080]: could not evaluate static initializer
 --> demo.rs:3:17
  |
3 |     let _copy = illegal_ptr2int;
  |                 ^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
  |
  = help: this code performed an operation that depends on the underlying bytes representing a pointer
  = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported

As the message says, this operation is not supported: the transmuteabove is trying to reinterpret the memory address &() as an integer of typeusize. The compiler cannot predict what memory address the () would be associated with at execution time, so it refuses to allow that reinterpretation.

When you write safe Rust, then the compiler is responsible for preventing undefined behavior. When you write any unsafe code (be it const or non-const), you are responsible for preventing UB, and during const-eval, the rules about what unsafe code has defined behavior are even more strict than the analogous rules governing Rust's runtime semantics. (In other words, more code is classified as "UB" than you may have otherwise realized.)

If you hit undefined behavior during const-eval, the Rust compiler will protect itself from adverse effects such as the undefined behavior leaking into the type system, but there are few guarantees other than that. For example, compile-time UB could lead to runtime UB. Furthermore, if you have UB at const-eval time, there is no guarantee that your code will be accepted from one compiler version to another.

What is new here

You might be thinking: "it used to be accepted; therefore, there must be some value for the memory address that the previous version of the compiler was using here."

But such reasoning would be based on an imprecise view of what the Rust compiler was doing here.

The const-eval machinery of the Rust compiler is built upon the MIR-interpreterMiri, which uses an abstract model of a hypothetical machine as the foundation for evaluating such expressions. This abstract model doesn't have to represent memory addresses as mere integers; in fact, to support Miri's fine-grained checking for UB, it uses a much richer datatype for the values that are held in the abstract memory store.

The details of Miri's value representation do not matter too much for our discussion here. We merely note that earlier versions of the compiler silently accepted expressions that seemed to transmute memory addresses into integers, copied them around, and then transmuted them back into addresses; but that was not what was acutally happening under the hood. Instead, what was happening was that the Miri values were passed around blindly (after all, the whole point of transmute is that it does no transformation on its input value, so it is a no-op in terms of its operational semantics).

The fact that it was passing a memory address into a context where you would expect there to always be an integer value would only be caught, if at all, at some later point.

For example, the const-eval machinery rejects code that attempts to embed the transmuted pointer into a value that could be used by runtime code, like so (playground):

pub static FOO: usize = unsafe {
    let illegal_ptr2int: usize = std::mem::transmute(&());
    illegal_ptr2int
};

Likewise, it rejects code that attempts to perform arithmetic on that non-integer value, like so (playground):

pub static FOO: () = unsafe {
    let illegal_ptr2int: usize = std::mem::transmute(&());
    let _incremented = illegal_ptr2int + 1;
};

Both of the latter two variants are rejected in stable Rust, and have been for as long as Rust has accepted pointer-to-integer conversions in static initializers (see e.g. Rust 1.52).

More similar than different

In fact, all of the examples provided above are exhibiting undefined behavior according to the semantics of Rust's const-eval system.

The first example with _copy was accepted in Rust versions 1.46 through 1.63 because of Miri implementation artifacts. Miri puts considerable effort into detecting UB, but does not catch all instances of it. Furthermore, by default, Miri's detection can be delayed to a point far after where the actual problematic expression is found.

But with nightly Rust, we can opt into extra checks for UB that Miri provides, by passing the unstable flag -Z extra-const-ub-checks. If we do that, then for_all_ of the above examples we get the same result:

error[E0080]: could not evaluate static initializer
 --> demo.rs:2:34
  |
2 |     let illegal_ptr2int: usize = std::mem::transmute(&());
  |                                  ^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
  |
  = help: this code performed an operation that depends on the underlying bytes representing a pointer
  = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported

The earlier examples had diagnostic output that put the blame in a misleading place. With the more precise checking -Z extra-const-ub-checks enabled, the compiler highlights the expression where we can first witness UB: the original transmute itself! (Which was stated at the outset of this post; here we are just pointing out that these tools can pinpoint the injection point more precisely.)

Why not have these extra const-ub checks on by default? Well, the checks introduce performance overhead upon Rust compilation time, and we do not know if that overhead can be made acceptable. (However, recent debateamong Miri developers indicates that the inherent cost here might not be as bad as they had originally thought. Perhaps a future version of the compiler will have these extra checks on by default.)

Change is hard

You might well be wondering at this point: "Wait, when is it okay to transmute a pointer to a usize during const evaluation?" And the answer is simple: "Never."

Transmuting a pointer to a usize during const-eval has always been undefined behavior, ever since const-eval added support fortransmute and union. You can read more about this in theconst_fn_transmute / const_fn_union stabilization report, specifically the subsection entitled "Pointer-integer-transmutes". (It is also mentioned in the documentation for transmute.)

Thus, we can see that the classification of the above examples as UB during const evaluation is not a new thing at all. The only change here was that Miri had some internal changes that made it start detecting the UB rather than silently ignoring it.

This means the Rust compiler has a shifting notion of what UB it will explicitly catch. We anticipated this: RFC 3016, "const UB", explicitlysays:

[...] there is no guarantee that UB is reliably detected during CTFE. This can change from compiler version to compiler version: CTFE code that causes UB could build fine with one compiler and fail to build with another. (This is in accordance with the general policy that unsound code is not subject to stability guarantees.)

Having said that: So much of Rust's success has been built around the trust that we have earned with our community. Yes, the project has always reserved the right to make breaking changes when resolving soundness bugs; but we have also strived to mitigate such breakage whenever feasible, via things likefuture-incompatible lints.

Today, with our current const-eval architecture layered atop Miri, it is not feasible to ensure that changes such as the one that injected issue#99923 go through a future-incompat warning cycle. The compiler team plans to keep our eye on issues in this space. If we see evidence that these kinds of changes do cause breakage to a non-trivial number of crates, then we will investigate further how we might smooth the transition path between compiler releases. However, we need to balance any such goal against the fact that Miri has very a limited set of developers: the researchers determining how to define the semantics of unsafe languages like Rust. We do not want to slow their work down!

What you can do for safety's sake

If you observe the could not evaluate static initializer message on your crate atop Rust 1.64, and it was compiling with previous versions of Rust, we want you to let us know: file an issue!

We have performed a crater run for the 1.64-beta and that did not find any other instances of this particular problem. If you can test compiling your crate atop the 1.64-beta before the stable release goes out on September 22nd, all the better! One easy way to try the beta is to use rustup's override shortand for it:

$ rustup update beta
$ cargo +beta build

As Rust's const-eval evolves, we may see another case like this arise again. If you want to defend against future instances of const-eval UB, we recommend that you set up a continuous integration service to invoke the nightly rustc with the unstable -Z extra-const-ub-checks flag on your code.

Want to help?

As you might imagine, a lot of us are pretty interested in questions such as "what should be undefined behavior?"

See for example Ralf Jung's excellent blog series on why pointers are complicated (parts I, II, III), which contain some of the details elided above about Miri's representation, and spell out reasons why you might want to be concerned about pointer-to-usize transmutes even _outside_of const-eval.

If you are interested in trying to help us figure out answers to those kinds of questions, please join us in the unsafe code guidelines zulip.

If you are interested in learning more about Miri, or contributing to it, you can say Hello in the miri zulip.

Conclusion

To sum it all up: When you write safe Rust, then the compiler is responsible for preventing undefined behavior. When you write any unsafe code, you are responsible for preventing undefined behavior. Rust's const-eval system has a stricter set of rules governing what unsafe code has defined behavior: specifically, reinterpreting (aka "transmuting") a pointer value as a usize is undefined behavior during const-eval. If you have undefined behavior at const-eval time, there is no guarantee that your code will be accepted from one compiler version to another.

The compiler team is hoping that issue #99923 is an exceptional fluke and that the 1.64 stable release will not encounter any other surprises related to the aforementioned change to the const-eval machinery.

But fluke or not, the issue provided excellent motivation to spend some time exploring facets of Rust's const-eval architecture, and the Miri interpreter that underlies it. We hope you enjoyed reading this as much as we did writing it.

Continue Reading…

Rust Blog

Security advisories for Cargo (CVE-2022-36113, CVE-2022-36114)

This is a cross-post of the official security advisory. The official advisory contains a signed version with our PGP key, as well.

The Rust Security Response WG was notified that Cargo did not prevent extracting some malformed packages downloaded from alternate registries. An attacker able to upload packages to an alternate registry could fill the filesystem or corrupt arbitary files when Cargo downloaded the package.

These issues have been assigned CVE-2022-36113 and CVE-2022-36114. The severity of these vulnerabilities is "low" for users of alternate registries. Users relying on crates.io are not affected.

Note that by design Cargo allows code execution at build time, due to build scripts and procedural macros. The vulnerabilities in this advisory allow performing a subset of the possible damage in a harder to track down way. Your dependencies must still be trusted if you want to be protected from attacks, as it's possible to perform the same attacks with build scripts and procedural macros.

Arbitrary file corruption (CVE-2022-36113)

After a package is downloaded, Cargo extracts its source code in the ~/.cargofolder on disk, making it available to the Rust projects it builds. To record when an extraction is successfull, Cargo writes "ok" to the .cargo-ok file at the root of the extracted source code once it extracted all the files.

It was discovered that Cargo allowed packages to contain a .cargo-ok symbolic link, which Cargo would extract. Then, when Cargo attempted to write "ok" into .cargo-ok, it would actually replace the first two bytes of the file the symlink pointed to with ok. This would allow an attacker to corrupt one file on the machine using Cargo to extract the package.

Disk space exaustion (CVE-2022-36114)

It was discovered that Cargo did not limit the amount of data extracted from compressed archives. An attacker could upload to an alternate registry a specially crafted package that extracts way more data than its size (also known as a "zip bomb"), exhausting the disk space on the machine using Cargo to download the package.

Affected versions

Both vulnerabilities are present in all versions of Cargo. Rust 1.64, to be released on September 22nd, will include fixes for both of them.

Since these vulnerabilities are just a more limited way to accomplish what a malicious build scripts or procedural macros can do, we decided not to publish Rust point releases backporting the security fix. Patch files for Rust 1.63.0 are available in the wg-security-response repository for people building their own toolchains.

Mitigations

We recommend users of alternate registries to excercise care in which package they download, by only including trusted dependencies in their projects. Please note that even with these vulnerabilities fixed, by design Cargo allows arbitrary code execution at build time thanks to build scripts and procedural macros: a malicious dependency will be able to cause damage regardless of these vulnerabilities.

crates.io implemented server-side checks to reject these kinds of packages years ago, and there are no packages on crates.io exploiting these vulnerabilities. crates.io users still need to excercise care in choosing their dependencies though, as the same concerns about build scripts and procedural macros apply here.

Acknowledgements

We want to thank Ori Hollander from JFrog Security Research for responsibly disclosing this to us according to the Rust security policy.

We also want to thank Josh Triplett for developing the fixes, Weihang Lo for developing the tests, and Pietro Albini for writing this advisory. The disclosure was coordinated by Pietro Albini and Josh Stone.

Continue Reading…

Rust Blog

Announcing Rust 1.63.0

The Rust team is happy to announce a new version of Rust, 1.63.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.63.0 with:

rustup update stable

If you don't have it already, you can get rustupfrom the appropriate page on our website, and check out thedetailed release notes for 1.63.0 on GitHub.

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

Scoped threads

Rust code could launch new threads with std::thread::spawn since 1.0, but this function bounds its closure with 'static. Roughly, this means that threads currently must have ownership of any arguments passed into their closure; you can't pass borrowed data into a thread. In cases where the threads are expected to exit by the end of the function (by being join()'d), this isn't strictly necessary and can require workarounds like placing the data in an Arc.

Now, with 1.63.0, the standard library is adding scoped threads, which allow spawning a thread borrowing from the local stack frame. Thestd::thread::scope API provides the necessary guarantee that any spawned threads will have exited prior to itself returning, which allows for safely borrowing data. Here's an example:

let mut a = vec![1, 2, 3];
let mut x = 0;

std::thread::scope(|s| {
    s.spawn(|| {
        println!("hello from the first scoped thread");
        // We can borrow `a` here.
        dbg!(&a);
    });
    s.spawn(|| {
        println!("hello from the second scoped thread");
        // We can even mutably borrow `x` here,
        // because no other threads are using it.
        x += a[0] + a[2];
    });
    println!("hello from the main thread");
});

// After the scope, we can modify and access our variables again:
a.push(4);
assert_eq!(x, a.len());

Rust ownership for raw file descriptors/handles (I/O Safety)

Previously, Rust code working with platform APIs taking raw file descriptors (on unix-style platforms) or handles (on Windows) would typically work directly with a platform-specific representation of the descriptor (for example, a c_int, or the alias RawFd). For Rust bindings to such native APIs, the type system then failed to encode whether the API would take ownership of the file descriptor (e.g., close) or merely borrow it (e.g., dup).

Now, Rust provides wrapper types such as BorrowedFd and OwnedFd, which are marked as#[repr(transparent)], meaning that extern "C" bindings can directly take these types to encode the ownership semantics. See the stabilized APIs section for the full list of wrapper types stabilized in 1.63, currently, they are available on cfg(unix) platforms, Windows, and WASI.

We recommend that new APIs use these types instead of the previous type aliases (like RawFd).

const Mutex, RwLock, Condvar initialization

The Condvar::new, Mutex::new, and RwLock::new functions are now callable in const contexts, which allows avoiding the use of crates likelazy_static for creating global statics with Mutex, RwLock, or Condvarvalues. This builds on the work in 1.62 to enable thinner and faster mutexes on Linux.

Turbofish for generics in functions with impl Trait

For a function signature like fn foo<T>(value: T, f: impl Copy), it was an error to specify the concrete type of T via turbofish: foo::<u32>(3, 3)would fail with:

error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
 --> src/lib.rs:4:11
  |
4 |     foo::<u32>(3, 3);
  |           ^^^ explicit generic argument not allowed
  |
  = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information

In 1.63, this restriction is relaxed, and the explicit type of the generic can be specified. However, the impl Trait parameter, despite desugaring to a generic, remains opaque and cannot be specified via turbofish.

Non-lexical lifetimes migration complete

As detailed in this blog post, we've fully removed the previous lexical borrow checker from rustc across all editions, fully enabling the non-lexical, new, version of the borrow checker. Since the borrow checker doesn't affect the output of rustc, this won't change the behavior of any programs, but it completes a long-running migration (started in the initial stabilization of NLL for the 2018 edition) to deliver the full benefits of the new borrow checker across all editions of Rust. For most users, this change will bring slightly better diagnostics for some borrow checking errors, but will not otherwise impact which code they can write.

You can read more about non-lexical lifetimes in this section of the 2018 edition announcement.

Stabilized APIs

The following methods and trait implementations are now stabilized:

These APIs are now usable in const contexts:

Other changes

There are other changes in the Rust 1.63.0 release. Check out what changed inRust,Cargo, and Clippy.

Contributors to 1.63.0

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

Continue Reading…