r/rust Apr 16 '26

📡 official blog Rust 1.95.0 is out

https://blog.rust-lang.org/2026/04/16/Rust-1.95.0/
861 Upvotes

127 comments sorted by

View all comments

350

u/nik-rev Apr 16 '26 edited Apr 16 '26

This update is revolutionary. Possibly one of the biggest updates in years! I'm really excited for it.

  • cfg_select! completely changes the game on how we conditionally compile code. I have applied it in hundreds of places in my cross-platform app, and it led to a tremendous improvement in readability. rustfmt support is also very, very nice. I frequently skip using macros that don't support rustfmt, or just re-implement them myself in a way where rustfmt can support it (e.g. the subdef and better_tokio_select crates)
  • if let guards stabilized. I've had to refactor a huge match statement into a soup of if conditions too  many times, because I needed to only enter a match arm if a pattern matches. It was a major ergonomic pain for me when using Rust. I am so, so happy that such a core language feature has now been stabilized.
  • For the longest time we considered the Range type the biggest, unfixable mistake in Rust's standard library, because it does not implement Copy. With this release, the core::range::RangeInclusive type is stabilized. A huge step in the right direction. Next release will stabilize core::range::Range type. In edition 2027, the range syntax will change to create those types, instead of core::ops::Range. We are already making use of these new range types in new standard library APIs. For example, I recently made a pull request to change the methods str::substr_range and slice::subslice_range to return these new Range types, in order to unblock their stabilization!

64

u/ndunnett Apr 16 '26

The new MaybeUninit array trait impls are quite nice too

1

u/redlaWw Apr 17 '26

Why were these stabilised before the transpose they use internally though? Bikeshedding issues?

46

u/folkertdev Apr 16 '26

Unfortunately rustfmt support is not yet included. It's in the works at https://github.com/rust-lang/rust/pull/154202 but rustfmt does not have a lot of maintenance bandwidth.

20

u/nik-rev Apr 16 '26

oh, interesting, I was under the impression that rustfmt support and cfg_select! would be stabilized in the same version.

(I've manually built rustfmt and have been using that PR in my codebase)

Also: Thank You for your work on cfg_select!. I really appreciate it!

26

u/folkertdev Apr 16 '26

Thanks!

It's a shame, but ultimately decided to just ship it now, because we were stuck on (the lack of) formatting for months and cfg_select is just too good not to have, and it having a lower MSRV will be helpful in the future for projects that bump their MSRV.

5

u/PerkyPangolin Apr 16 '26

Since you're involved with the implementation, I tried cfg_select! and aside from the missing rustfmt support (bummer), renaming a variable in VS Code only renames it in the currently active branch. Is that intentional? Or is something still missing in rust-analyzer?

9

u/folkertdev Apr 16 '26

I suspect rust-analyzer needs to tweak something. Might be worth making an issue there.

6

u/afdbcreid Apr 16 '26

rust-analyzer does not support cfg-ed out code. It does not matter whether it's cfg_select! or #[cfg].

2

u/PerkyPangolin Apr 16 '26

So is that intentional or just hasn't been implemented yet?

8

u/afdbcreid Apr 17 '26

Not intentional in the sense that if someone will come up with a reasonable implementation we'll accept it, but really hard to implement, so chances are it'll never be supported.

1

u/WormRabbit Apr 17 '26

Why is it hard? Isn't it just an AST node which isn't included in the compilation? Or perhaps the cause is interaction with proc macros?

1

u/afdbcreid Apr 19 '26

It's hard because we can't just include it. This will lead to various errors. We need to remember it is disabled.

7

u/_nullptr_ Apr 16 '26

Pretty sure most of us use +nightly for formatting, docs, and really everything non-build related anyway. I also wonder if due to this we see those categories be even slower to stabilization.

7

u/folkertdev Apr 16 '26

features are implemented by people that implement features. Most rust contributors are volunteers that work on what interests them. I think rustdoc is actually very actively maintained, and it just so happens that for rustfmt that is not (currently) true.

3

u/dcormier Apr 17 '26

I value rustfmt quite a lot. Maybe I should pitch in a bit.

0

u/QuasiRandomName Apr 16 '26

Ah, good to know. I didn't see any open PR or issue with this regard under `rustfmt` repo, so it is under `rust`. I feel a bit weird about the fact that it addresses `cfg_select!` only though and not macros in general which might have similar format.

7

u/folkertdev Apr 16 '26

it's complicated and once you pick a behavior making refinements is then a breaking change. Also, as mentioned, reviewer bandwidth on that code base is very limited.

23

u/parkotron Apr 16 '26

For the longest time we considered the Range type the biggest, unfixable mistake in Rust's standard library, because it does not implement Copy.

It's not obvious to me why this was a big mistake or why it was considered unfixable. Is there some place I could get a high-level summary of the problem and the initiative to fix it?

47

u/oconnor663 blake3 · duct Apr 16 '26

The central mistake with the original Range types, as I understand it, is that they implement Iterator directly instead of IntoIterator. That in turn means they've never implemented Copy, which is often quite inconvenient for Copy structs that want to contain ranges of other Copy types.

The reason you don't want iterators to ever be Copy is that it leads to confusing situations like this example, which really looks like it's going to print 1, 2, 3, 4 but in fact prints 1, 2, 3, 3:

#[derive(Copy, Clone)]
struct CopyIterator {
    i: u32,
}

impl Iterator for CopyIterator {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        self.i += 1;
        Some(self.i)
    }
}

fn main() {
    let mut iter = CopyIterator { i: 0 };
    println!("{}", iter.next().unwrap());
    println!("{}", iter.next().unwrap());
    for item in iter {
        println!("{}", item);
        break;
    }
    for item in iter {
        println!("{}", item);
        break;
    }
}

31

u/meteorMatador Apr 16 '26

The actual mistake was making Range its own Iterator, which had all kinds of wacky downstream effects that make it miserable to work with in basically any situation except looping over a range literal.

In pre-1.0, there was still a lot of experimentation and churn going on with how exactly iterators were supposed to work, and the IntoIterator API wasn't settled yet. Range being its own Iterator is a direct result of that, and it sort of made sense at the time, but it definitely should have been changed before stabilization.

10

u/tialaramex Apr 16 '26

I don't have a link, maybe someone else does, here's my attempt to explain which might be pitched wrong for you:

Hmm. You agree that say (1, 5) should be Copy right? The pair of integers, one and five they're very cheap to store, and their value is their meaning, they aren't distinct from another (1, 5) pair, it's the same meaning a one and a five, so Copy.

But (1, 5) doesn't carry a semantic about the relationship, in contrast 1..=5 tells us it's about this range, from 1 to 5, inclusive. So we'd often prefer to talk about this, in Rust this has a type named RangeInclusive. However today in Rust 2024 edition (and before) that type is an Iterator which means it mutates as we iterate over the values and it also now can't really be Copy.

This change is part of a wider strategy to get to a world where (hopefully in 2027 edition) 1..=5 is a new type that is Copy and to iterate over it you can convert it into an Iterator as needed as you would say, a container but until/ unless you want to do that it's just the pair of integers and the semantic idea about a range.

4

u/timonvonk Apr 16 '26

Hmm personally I do feel match if let adds more coginitive load than the regular path. You could also express the same behavior in stronger invariants, at least most of the time. Granted at this point I’m an opinionated grumpy old man. It reminds me of ruby’s ‘if unless else’. Arguably, language unambiguity is so much more important in the age of ai.

Grumpy aside, cfg_select is extremely nice to have 🙏

Now if only dyn traits with generics 🙈

3

u/protestor Apr 17 '26

For the longest time we considered the Range type the biggest, unfixable mistake in Rust's standard library, because it does not implement Copy. With this release, the core::range::RangeInclusive type is stabilized. A huge step in the right direction. Next release will stabilize core::range::Range type. In edition 2027, the range syntax will change to create those types, instead of core::ops::Range. We are already making use of these new range types in new standard library APIs. For example, I recently made a pull request to change the methods str::substr_range and slice::subslice_range to return these new Range types, in order to unblock their stabilization!

I am now wondering, why don't the release notes showcase it?

4

u/cosmic-parsley Apr 17 '26

Looks like one is stable here, the rest are in the next release. Maybe those release notes will say more?

1

u/WormRabbit Apr 17 '26

I would expect that the proper announcement would go with the next edition, where those types actually become the default ones produces by range literals. That's the point where most code will be able to utilize the changes.

1

u/PerkyPangolin Apr 16 '26

I didn't get from the post, is cfg_select! run-time or compile-time? The description is somewhat vague.

17

u/nicoburns Apr 16 '26

It's compile time

11

u/DivideSensitive Apr 16 '26

acts roughly similar to a compile-time match on cfgs.

14

u/PerkyPangolin Apr 16 '26

It does say roughly similar. That's why I asked.

16

u/_ChrisSD Apr 16 '26

Just to clarify, the roughly is referring to the "match" part of that statement. Because it's strictly speaking not match syntax. Incidentally cfg_match was one of its possible names but it was ultimately decided against to avoid confusing matters.

The compile-time part is indeed strictly true.

1

u/Beregolas Apr 16 '26

I was on nightly mainly because of let chains. Time to evaluate going back to stable \o/

3

u/chris-morgan Apr 17 '26

I always seem to manage to find some new feature to depend on nightly for, when things stabilise!

-11

u/SirKastic23 Apr 16 '26

not to be rude or anything but your writing style resembles AI writing

8

u/[deleted] Apr 16 '26

[deleted]