Latest in branch 1.63
1.63.0
Released 11 Aug 2022
(3 years ago)
SoftwareRust
Version1.63
Initial release1.63.0
11 Aug 2022
(3 years ago)
Latest release1.63.0
11 Aug 2022
(3 years ago)
Support status23 Sep 2022
(Ended 3 years, 8 months ago)
Release noteshttps://github.com/rust-lang/rust/releases/tag/1.63.0
Source codehttps://github.com/rust-lang/rust/tree/1.63.0
Downloadhttps://github.com/rust-lang/rust/releases/tag/1.63.0
Rust 1.63 ReleasesView full list

What Is New in Rust 1.63

Category Highlights
New Features Scoped threads, BorrowedFd/OwnedFd types, const-initializable Mutex/RwLock/Condvar, turbofish support for functions with impl Trait arguments
Improvements Full migration to non-lexical lifetimes across all editions, assorted minor enhancements

How do scoped threads work in Rust 1.63?

Scoped threads let you spawn threads that can safely borrow data from the surrounding stack frame.

In practice you call std::thread::scope and pass a closure that receives a scope handle. The handle's spawn method creates threads that are guaranteed to finish before the scope returns, so any borrowed references remain valid.

let mut data = vec![1, 2, 3];
std::thread::scope(|s| {
    s.spawn(|_| {
        println!("first: {:?}", &data);
    });
    s.spawn(|_| {
        // mutable borrow is allowed because no other thread uses it
        let mut sum = 0;
        for v in &data { sum += v; }
        println!("sum = {}", sum);
    });
}); // all threads joined here
// data can be used again
data.push(4);

What are BorrowedFd and OwnedFd and why should I use them?

BorrowedFd and OwnedFd are transparent wrapper types that encode whether a raw file descriptor or handle is borrowed or owned.

  • They are marked #[repr(transparent)], so they have the same ABI as the underlying integer or handle.
  • Using them in FFI signatures makes ownership semantics explicit to the Rust type system, reducing bugs around double-close or leaked descriptors.
  • They are available on Unix, Windows, and WASI platforms.

Can I initialize Mutex, RwLock, and Condvar in a const context now?

Yes, the constructors Mutex::new, RwLock::new and Condvar::new are now const, allowing them to be used in static or const definitions without external crates.

use std::sync::{Mutex, RwLock, Condvar};

static GLOBAL_LOCK: Mutex<i32> = Mutex::new(0);
static GLOBAL_RW: RwLock<bool> = RwLock::new(true);
static GLOBAL_CV: Condvar = Condvar::new();

How does the new turbofish support affect functions with impl Trait parameters?

You can now supply explicit generic arguments for the non-impl Trait type parameters of a function, while the impl Trait argument remains opaque.

Example:

fn combine(a: T, b: impl std::fmt::Display) -> String {
    format!("{} {}", a, b)
}

// Explicitly specify T, but not the impl Trait type
let result = combine::(42, "items");

What does the completion of non-lexical lifetimes mean for my code?

The non-lexical borrow checker is now the default for all editions, giving more precise diagnostics without changing program semantics.

  • Borrow checking is performed based on actual usage rather than lexical scopes.
  • This can surface previously hidden lifetime issues earlier in the compile cycle.
  • Existing code continues to compile; only error messages may become clearer.

Frequently Asked Questions

Do I need to rewrite all my existing thread code to use scoped threads?
No, the original std::thread::spawn API remains unchanged and can be used alongside scoped threads.

Is there any runtime overhead when using BorrowedFd instead of RawFd?
No, BorrowedFd is #[repr(transparent)] and compiles to the same representation as a raw file descriptor.

How can I declare a static Mutex without pulling in lazy_static?
You can write static MY_LOCK: Mutex<i32> = Mutex::new(0); because Mutex::new is now const.

Can I still use turbofish on a function that only has impl Trait arguments?
No, turbofish can only specify the explicit generic parameters; impl Trait parameters remain opaque.

Will enabling the full non-lexical lifetime checker change the behavior of my existing programs?
No, it only improves borrow-checking diagnostics without altering program semantics.

What is the simplest way to spawn a scoped thread that borrows a local variable?
You can call std::thread::scope(|s| { s.spawn(|_| { println!("{:?}", &my_var); }); });

Releases In Branch 1.63

VersionRelease date
1.63.011 Aug 2022
(3 years ago)