Freeze
in bounds (RFC 3633)" #277Edit the schedule here: https://github.com/orgs/rust-lang/projects/31/views/7.
(Meeting attendees, feel free to add items here!)
TC: For any guests who are present, please note in this section if you're attending for the purposes of any items on (or off) the agenda in particular.
TC: As we've been doing recently, due to the impressive backlog, I'm going to push the pace a bit. If it's ever too fast or you need a moment before we move on, please raise a hand and we'll pause.
TC: Remember that we have a design/planning meeting that starts half an hour after this call ends.
We're next meeting with RfL on 2024-07-03 to review the status of RfL project goals.
https://github.com/rust-lang/rfcs/pull/3614
On the spec team, we recently adopted and are executing a go-forward plan:
https://github.com/rust-lang/team/pull/1483
Related to that, we're giving +write
on the Reference to the spec team. The ops team asked for lang sign-off on this. If it's without objection, I'm planning to say that lang is fine with this and that it's a spec team / rustdocs matter.
Project board: https://github.com/orgs/rust-lang/projects/43/views/5
None.
TC: We have tracking issues for the Rust 2024 aspects of every item queued for the edition:
https://github.com/rust-lang/rust/issues?q=label%3AA-edition-2024+label%3AC-tracking-issue
For each item, we've identified an owner. Our most recent update for item owners is here:
https://rust-lang.zulipchat.com/#narrow/stream/268952-edition/topic/Owners.20update.202024-04-30
Our motivating priorities are:
The current timeline to be communicated is:
Date | Version | Edition stage |
---|---|---|
2024-06-13 | Release v1.79 | Checking off items… |
2024-07-25 | Release v1.80 | Checking off items… |
2024-09-05 | Release v1.81 | Checking off items… |
2024-10-11 | Branch v1.83 | Go / no go on all items |
2024-10-17 | Release v1.82 | Rust 2024 nightly beta |
2024-11-22 | Branch v1.84 | Prepare to stabilize… |
2024-11-28 | Release v1.83 | Stabilize Rust 2024 on master |
2025-01-03 | Branch v1.85 | Cut Rust 2024 to beta |
2025-01-09 | Release v1.84 | Announce Rust 2024 is pending! |
2025-02-20 | Release v1.85 | Release Rust 2024 |
Link: https://github.com/rust-lang/rust/issues/117587
TC: With the acceptance of RFC 3617, the adoption of + use<..>
syntax, and the great work by CE, this is looking to be in good shape for the edition.
Link: https://github.com/rust-lang/rfcs/pull/3513
TC: With the acceptance of RFC 3513 and the great work by Oli, this is looking to be in good shape for the edition.
!
to a type (RFC 1216) #35121Link: https://github.com/rust-lang/rust/issues/35121
Link: https://github.com/rust-lang/rust/pull/123508
TC: With the acceptance of the plan we FCPed in #123508 and the great work by Waffle, this is looking to be in good shape for the edition.
Link: https://github.com/rust-lang/rust/pull/126762
We decided recently that we considered it a bug fix to start denying 'keyword
lifetimes pre-expansion, in the parser.
CE is asking for FCP, just for consistently. Josh proposed FCP merge. We just decided this, so easy checkbox here.
TC: This will go into FCP.
NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE
a hard error in edition 2024" rust#126881Link: https://github.com/rust-lang/rust/pull/126881
TC: We'll have everything (including documentation) for changing never type fallback crossed off this week (!!!).
There's one, non-blocking, open question we should resolve. The original FCPed plan included this item:
unsafe
function.
deny-by-default
or a hard error in Rust 2024.That is, we had left as an open question strengthening this in Rust 2024, and had marked it as an open question on the tracking issue.
As a reminder, what we're talking about are cases like this:
fn never_type_fallback() { unsafe {
if false { panic!() } else { transmute::<_, _ /* ?0 */>(()) }
// later in fallback: ?0 := ()
// after ! stabilization: ?0 := !
}}
We decided we didn't want people writing this or relying on this sort of thing, and we lint against these now. We have the opportunity to make it deny-by-default or a hard error in Rust 2024, and that's what I'd probably suggest to take these cases off the table entirely.
TC: What do we think?
NM: A hard error feels surprising… why? There are a nunmber of heuristic aspects to it. I see the logic. I'm unsure about deny-by-default versus hard error. Given the discussion about making the rules around never more uniform, that's a consideration.
scottmcm: What I'd ask is whether it makes our language definition simpler to make it a hard error. I'm inclined to deny-by-default here.
pnkfelix: We don't have a machine-applicable fix for this. Maybe that's a consideration.
TC: Revised proposal, let's make it deny-by-default. How do people feel about that?
NM: +1. This lets us tweak the boundaries.
Josh: +1. I'd add that we're open to a hard error if that makes the implementation side easier.
tmandry: I'm aligned on deny-by-default.
scottmcm: +1 on deny-by-default.
pnkfelix: +1 on that.
Link: https://github.com/rust-lang/rust/pull/107251
TC: This PR is about shortening, over an edition, the scope of temporary lifetimes in if-let scrutinees so that they end before the else
block. The current rules are a particular problem for let-chains which we hope to stabilize.
Ding assembled this report based on our request:
https://hackmd.io/@dingxf/rkJXW-0BA
TC: What do we think?
Josh: I'd be good to start an FCP here if needed.
NM: It seems we need an stabilization report here. I'll look into this one.
const_cstr_from_ptr
" rust#113219Link: https://github.com/rust-lang/rust/issues/113219
TC: dtolnay is proposing const stabilization on:
impl CStr {
pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr;
}
The FCP also includes that later stabilization of:
impl CStr {
#[unstable]
pub const fn count_bytes(&self) -> usize;
}
…including const
would not need lang sign-off.
scottmcm analyzed this, noting that this works on stable:
const unsafe fn count_bytes(p: *const u8) -> usize {
let mut i = 0;
loop {
if *p.add(i) == 0 { return i }
i += 1;
}
}
…and so he doesn't have any concerns. tmandry agreed.
TC: Easy checkbox?
NM: Good enough for me.
TC: This will move into FCP.
non_local_definitions
lint fires for impl Trait for NonLocalType<SomeLocalType>
, probably shouldn't" rust#126768Link: https://github.com/rust-lang/rust/issues/126768
In RFC 3373 we decided to lint against "sneaky inner impls", that is, function-local impls of outer traits for outer types. What we had in mind were things like this:
trait Tr {}
struct S {}
fn foo() {
impl Tr for S {}
}
But we specifically wanted to allow people making local impls of local traits on outer types or of outer traits on local types, e.g.:
trait Tr {}
fn foo() {
struct S {}
impl Tr for S {}
}
…or:
struct S {}
fn foo() {
trait Tr {}
impl Tr for S {}
}
So, in that light, it does seem a bit strange that we lint against impls of e.g. outer traits on references to inner types, e.g.:
trait Tr {}
fn foo() {
struct S {};
impl Tr for &S {}
//~^ WARN non-local `impl` definition, `impl` blocks should be
//~| written at the same level as their item
}
There's a type system logic to this, which is that we could write:
fn leak<T: Tr>() {}
fn main() {
leak::<&_>(); // Infers `&S`.
}
But the outcome is a kind of surprising language result. Specifically, people had probably wanted the type or trait to be local, and the only way for them to resolve this warning is to make them both non-local. (The diagnostic for this case is wrong too, because it tells people to put the impl at the same level as the item, which it already is.)
Anyway, it seemed worth confirming that this is what we really meant to do.
TC: What do we think?
Josh: It seems that our reasonable options are to not warn about this, since it doesn't seem like a big deal that it could leak in this way, or go ahead and continue linting against it, since it is technically leaking, or the third option is to reconsider the "only one thing could go here" rule in a future edition.
pnkfelix: I would have thought that one could have implemented this lint as a simple syntactic heuristic rather than being a complicated type system thing.
Josh: I don't think anything stops us from implementing it that way. Right now it's been implemented very technically on the question of "could it leak out at all".
NM: I think I'm in the camp of that this is an unwanted inference result in the language. I don't think, in the program above, that we should infer an inner struct that you can't name. I lean toward the option of not linting for now, then, if we later wanted to move toward a harder error, we could look at making the inference not work this way.
Josh: That would be my inclination as well. I don't think we necessarily need to rip out the "only one thing could go here" rule; we could add a post check for whether that thing is a completely inaccessible type defined inside an inner scope.
NM: I believe we have some precedent here. petrochenkov wrote an RFC revisiting the rules on public and private. Would check after inference whether the type you inferred was public.
TC: It's RFC 2145:
https://github.com/rust-lang/rfcs/pull/2145
Josh: Let's not lint against this now (on that basis that we may later want to stop doing this strange inference anway).
NM: Agreed. I'm concerned about this case leading to subtle bugs in unsafe code along the lines of the problems we've seen with Pin
– i.e., authors assuming the struct is inaccessible outside the function and relying on that. I'd rather we revisit the inference rules and try to address that.
tmandry: I'm aligned on not linting on this case. I'd expect to be able to write the code above. Hopefully we can close the inference loophole here eventually.
scottmcm: I'm excited by the direction of "let's change bigger rules in other places" and so if, for now, we don't lint here, that's good for me.
pnkfleix: +1, let's not lint there.
Link: https://github.com/rust-lang/rfcs/pull/3637
This RFC is about allowing, e.g.:
match x {
(Ok(Some(y)) if y == 10) | (Ok(None)) => todo!(),
_ => todo!(),
}
One effect of this is to allow guards more widely where refutable patterns are allowed, e.g.:
let (x if x == 10) = y else { loop {} };
TC: Josh has proposed FCP, is +1, and has nominated this for us. What do we think?
Josh: I see this as a generalization of patterns.
TC: I ran into cases just recently where this would have been useul.
tmandry: Indeed; I have also. I'm curious how this might interact with the other outstanding proposals.
scottmcm: This, I think, falls in the category of things that make sense to me, and it will have implications on people who have written tricky macros.
Josh: In reading through this myself, I think the author covered the corner cases. So I'd suggest people read and confirm that.
NM: I kind of don't know why we wouldn't do it, and that bothers me a bit. scottmcm just gave one good reason.
scottmcm: TBH I do want it, because I've also hit macros that didn't add the if
support, and where that was annoying.
Link: https://github.com/rust-lang/rust/pull/116863
TC: This PR is about:
Bindgen allows generating
#[non_exhaustive] #[repr(u32)]
enums. This results in nonintuitive nonlocalimproper_ctypes
warnings, even when the types are otherwise perfectly valid in C.Adjust for actual tooling expectations by avoiding warning on simple enums with only unit variants.
This fixes:
https://github.com/rust-lang/rust/issues/116831
However, petrochenkov notes:
When I started reading #116831 my first reaction was "if
NodeTag
is so special, then it's fine to useallow
", but the problem is that you cannot actually applyallow
to the single location where it would be most appropriate -enum NodeTag
definition.From the issue it looks like what you want to express is "this enum is
non_exhaustive
, but I guarantee that no future variant additions will change its ABI, so it's fine to use it in C interfaces andimproper_ctypes
should not be reported".Maybe
non_exhaustive
can be enhanced with some markers describing what we promise not to add, and it would be useful in other situations too, not just inimproper_ctypes
. In the meantime the lint could be relaxed.Warning on
#[repr(C)] #[non_exhaustive]
was an explicit lang team decision, so I'll send this back to lang team for reconsidering.
TC: What do we think?
Link: https://github.com/rust-lang/rust/pull/121270
TC: pnkfelix nominates this for us:
This PR that addresses some ICEs arising for the unstable
feature(unnamed_fields)
, by conservatively mapping the ICE'ing cases to static errors instead.The T-compiler team wants to know the opinion of T-lang of whether
feature(unnamed_fields)
is sufficiently likely, in the near future, to be removed (or significantly reworked) to such a degree that it would make more sense to close this PR rather than have contributors spend further time on it.(See also the context established by https://hackmd.io/7r0i-EWyR8yO6po2LnS2rA#Tracking-issue-for-RFC-2102-Unnamed-fields-of-struct-and-union-type-rust49804 (where I think there was supposed to be an eventual writeup of the concerns people had with
feature(unnamed_fields)
) and #49804 (comment) )
On 2024-05-12, Josh said:
It sounds like, from the minutes, that some folks would like to see this feature designed differently than it was when it was previously accepted. It wouldn't be the first or last feature to need some design adjustments when lang design met compiler reality. Happy to help with that, so that we can find a design that meets the requirements in the original RFC and any new issues that have arisen since then.
This is about RFC 2102:
https://github.com/rust-lang/rfcs/pull/2102
TC: What do we think?
Link: https://github.com/rust-lang/reference/pull/1482
TC: This documents some properties proposed by RalfJ:
- Every type, including unsized types, has a minimal size and a minimal alignment
- For sized types, the minimal size and alignment match their regular size and alignment
- For slices, the minimal size is 0 and the minimal alignment is the alignment of the element type
- For
dyn Trait
, the minimal size is 0 and the minimal alignment is 1- For struct types with an unsized field, the minimal size and alignment is computed using the minimal size and alignment of that field
- The minimal size of all types fits in
isize
TC: scottmcm nominates this for us. What do we think?
Link: https://github.com/rust-lang/reference/pull/1499
TC: RalfJ proposes to update some language in the Reference to say this, after the changes:
- A reference or
Box<T>
that is [dangling], misaligned, or points to an invalid value (using the actual dynamic type of the pointee in case of dynamically sized types).- Invalid metadata in a wide reference,
Box<T>
, or raw pointer. The requirement for the metadata is determined by the type of the unsized tail:
dyn Trait
metadata is invalid if it is not a pointer to a vtable forTrait
.- Slice metadata is invalid if the length is not a valid
usize
(i.e., it must not be read from uninitialized memory). Furthermore, for wide references andBox<T>
, slice metadata is invalid if it makes the total size of the pointed-to value bigger thanisize::MAX
.
TC: What do we think?
Link: https://github.com/rust-lang/reference/pull/1502
TC: RalfJ suggests to add to the Reference:
The bytes owned by an immutable binding or immutable
static
are immutable, unless those bytes are part of an [UnsafeCell<U>
].
(Emphasis added.)
And:
Once Rust code runs, mutating an immutable static (from inside or outside Rust) is UB, except if the mutation happens inside an
UnsafeCell
.
TC: What do we think?
Link: https://github.com/rust-lang/rfcs/pull/3437
TC: We discussed this in the lang planning meeting in June, and it looks like there have been updates since we last looked at this, so it's time for us to have another look since we seemed interested in this happening.
TC: What do we think?
repr(discriminant = ...)
for type aliases" rfcs#3659Link: https://github.com/rust-lang/rfcs/pull/3659
TC: This RFC proposes to allow:
type Byte = u8;
#[repr(self::Byte)]
enum E {
One,
Two,
}
It requires that there be ::
in the path, as above, so that we don't step on the space of valid representations.
TC: Josh proposed FCP merge and nominated. What do we think?
Link: https://github.com/rust-lang/rust/pull/117967
TC: adetaylor proposes to adjust some rules for how elided lifetimes work. This was originally proposed for T-types FCP, but then they decided this was probably a lang matter after all.
TC: What do we think?
#[coverage]
" rust#84605Link: https://github.com/rust-lang/rust/issues/84605
TC: This is about stabilizing a #[coverage(off)]
attribute to exclude items from -Z instrument-coverage
.
Josh proposed FCP merge and nominated this for us.
Let's go ahead and see if we have consensus to stabilize this other than the potential issue of applying it automatically to nested functions or inlined functions.
My proposal would be that
coverage(off)
should automatically apply to functions (and closures) nested inside the function in question, but that it shouldn't automatically apply to inlined functions.Rationale: putting
#[coverage(off)]
on a function should apply to everything inside it for convenience, but things it calls might still want coverage for other reasons. I'd propose that if we want something that recursively disables coverage, that should be an additional attribute.However, this is a loosely held position, and I'd love to see a good argument / use case for also disabling it on inlined functions.
Correspondingly, there are two open questions about applying this automatically to nested functions and to inlined functions.
Checkboxes are here:
https://github.com/rust-lang/rust/issues/84605#issuecomment-1937373497
TC: What do we think?
extended_varargs_abi_support
" rust#116161Link: https://github.com/rust-lang/rust/pull/116161
TC: This stabilization was nominated for us, with pnkfelix commenting:
Just to add on to @cjgillot 's comment above: @wesleywiser and I could not remember earlier today whether T-lang wants to own FCP'ing changes like this that are restricted to extending the set of calling-conventions (i.e. the
conv
inextern "conv" fn foo(...)
), which is largely a detail about what platforms one is interoperating with, and not about changing the expressiveness of the Rust language as a whole in the abstract.(My own gut reaction is that T-compiler is a more natural owner for this than T-lang, but I wasn't certain and so it seems best to let the nomination stand and let the two teams duke it out.)
TC: What do we think about 1) this stabilization, and 2) whether we want to own this?
Link: https://github.com/rust-lang/rust/pull/120221
TC: CE handed this one to us, since it changes the contract of macro matchers.
Here's the code that does not work today that we would make work:
macro_rules! m {
($pat:pat) => {};
($stmt:stmt) => {};
}
macro_rules! m2 {
($stmt:stmt) => {
m! { $stmt }
//~^ ERROR expected pattern
};
}
m2! { let x = 1 }
This code does not work because we consider :stmt
to be a possible :pat
even though we then always reject it later in the process. By saying that :stmt
cannot be a :pat
, we make this code work.
We discussed this in the meeting on 2024-03-27:
CE: Right now the tokens that a macro matcher may begin with is a stable guarantee. We are relaxing the assumption that pattern matchers may begin with statement metavariables ($var whose type is stmt), because when we actually try to parse such a pattern, we are always guaranteed to fail. This only allows more code to compile, and would only break future code if we specifically wanted to begin patterns with statement metavariable.
scottmcm: I agree that it's weird to allow a
:stmt
in a pattern, so am happy to say we won't. Let's see what others think, since this conversation was in a sparsely-attended triage meeting:scottmcm: The other thing we explored was what it would take to make this actually work, since you can actually put an
:expr
into a pattern. But CE argued that we don't actually like that that works, it's just something we're stuck with because people used it before:literal
was available, which seems fair.
TC: What do we think?
Link: https://github.com/rust-lang/rust/pull/120706
TC: This is related to this MCP about a path toward async drop and scoped tasks:
https://github.com/rust-lang/compiler-team/issues/727
TC: petrochenkov gives some background:
So, what are the goals here:
- We want to have a possibility to add new auto traits that are added to all bound lists by default on the current edition. The examples of such traits could be
Leak
,Move
,SyncDrop
or something else, it doesn't matter much right now. The desired behavior is similar to the currentSized
trait. Such behavior is required for introducing!Leak
or!SyncDrop
types in a backward compatible way. (BothLeak
andSyncDrop
are likely necessary for properly supporting libraries for scoped async tasks and structured concurrency.)- It's not clear whether it can be done backward compatibly and without significant perf regressions, but that's exactly what we want to find out. Right now we encounter some cycle errors and exponential blow ups in the trait solver, but there's a chance that they are fixable with the new solver.
- Then we want to land the change into rustc under an option, so it becomes available in bootstrap compiler. Then we'll be able to do standard library experiments with the aforementioned traits without adding hundreds of
#[cfg(not(bootstrap))]
s.- Based on the experiments, we can come up with some scheme for the next edition, in which such bounds are added more conservatively.
- Relevant blog posts - https://without.boats/blog/changing-the-rules-of-rust/, https://without.boats/blog/follow-up-to-changing-the-rules-of-rust/ and https://without.boats/blog/generic-trait-methods-and-new-auto-traits/, https://without.boats/blog/the-scoped-task-trilemma/
- Larger compiler team MCP including this feature - MCP: Low level components for async drop compiler-team#727, it gives some more context
We discussed this in the async WG on 2024-03-25 and commented:
This is interesting work, but there's a lot to review here. We'd be particularly interested in seeing something in the way of a design document here, specifically e.g. with respect to when these bounds are added and when they are not, and how they interact with the
?
bounds. Seeing the algorithm spelled out in words and in theory would definitely help us understand this. The best place to put this may be in the rustc-dev-guide.
The question here is whether we want to charter this as an experiment.
Link: https://github.com/rust-lang/rust/pull/121676
TC: This is related to this MCP about a path toward async drop and scoped tasks:
https://github.com/rust-lang/compiler-team/issues/727
TC: petrochenkov gives some background:
Summary:
- Initial support for auto traits with default bounds #120706 introduces a way to add new auto traits that are appended to all bound lists by default, similarly to existing
Sized
. Such traits may includeLeak
,SyncDrop
or similar, see Initial support for auto traits with default bounds #120706 (comment) for more detailed motivation.- To opt out from bounds added by default the
?Trait
syntax is used, but such "maybe" bounds are not supported in some contexts like supertrait lists anddyn Trait + ...
lists, becauseSized
is not added by default in those context.- This PR adds a feature for supporting
trait Trait1: ?Trait2
,dyn Trait1 + ?Trait2
and also multiple maybe bounds in the same list?Trait1 + ?Trait2
, because the new traits need to be added by default in those contexts too, and?Sized + ?Leak
may also make sense.- We need this to be available in bootstrap compiler, to make experiments on standard library without adding too many
#[cfg(not(bootstrap))]
s- Larger compiler team MCP including this feature - MCP: Low level components for async drop compiler-team#727, it gives some more context
TC: The question here is whether we want to charter this as an experiment.
Link: https://github.com/rust-lang/rust/pull/121965
TC: scottmcm filed this issue and explains:
The length limit on slices is clearly a safety invariant, and I'd like it to also be a validity invariant. With function parameter metadata making progress in LLVM, I'd really like to be able to use it when
&[_]
is passed as a scalar pair, in particular.The documentation for references is cagey about what exactly is a validity invariant, so for now just elaborate on the consequences of the existing safety rules on slices – the length restriction follows from the
size_of_val
restriction – as a way to help discourage people from trying to violate them.I also made the existing warning stronger, since I'm fairly sure it's already UB to violate at least the "references must be non-null" rule, rather than it just being that it "might be UB in the future".
Then joboet nominated this for us with:
Given that
slice::from_raw_parts
already states that "the total sizelen * mem::size_of::<T>()
of the slice must be no larger thanisize::MAX
" and that its behaviour is undefined otherwise, I'd say that this is entirely uncontroversial. Still, I'd appreciate some team sign-off on this, I think this concerns lang?
RalfJ thinks this should probably be a dual T-lang / T-opsem FCP.
TC: What do we think?
#![crate_name = EXPR]
semantically allows EXPR
to be a macro call but otherwise mostly ignores it" rust#122001Link: https://github.com/rust-lang/rust/issues/122001
TC: In previous stable versions of Rust, #![crate_name = EXPR]
worked. That is, within EXPR
we expanded and then used macro calls such as concat
.
However, due to:
https://github.com/rust-lang/rust/pull/117584
…we broke this, and then we shipped it in stable Rust v1.77.
Except, we only half broke it. It doesn't work, but neither is it a hard error. It just quietly ignores the result.
We discussed this in the meeting on 2024-03-27 and agreed this was the worst of all worlds, and so we should at a minimum break it completely, and then we could always later decide to relax the hard error and make it work again by reverting #117584. On that basis, scottmcm proposed FCP merge.
TC: What do we think?
assert!
expression is bool
" rust#122661Link: https://github.com/rust-lang/rust/pull/122661
TC: estebank describes this issue for us:
In the desugaring of
assert!
in 2024 edition, assign the condition expression to abool
biding in order to provide better type errors when passed the wrong thing.The span will point only at the expression, and not the whole
assert!
invocation.
error[E0308]: mismatched types
--> $DIR/issue-14091.rs:2:13
|
LL | assert!(1,1);
| ^ expected `bool`, found integer
We no longer mention the expression needing to implement the
Not
trait.
error[E0308]: mismatched types
--> $DIR/issue-14091-2.rs:15:13
|
LL | assert!(x, x);
| ^ expected `bool`, found `BytePos`
In <=2021 edition, we still accept any type that implements
Not<Output = bool>
.
TC: And pnkfelix nominates this for us:
At the very least, we might need to tie such a change to an edition.
I am not certain whether this decision would be a T-lang matter or a T-libs-api one. I'll nominate for T-lang for now.
(Namely: The question is whether we can start enforcing a rule that the first expression to
assert!
must be of bool type, which is how the macro is documented, but its current behavior is a little bit more general, as demonstrated in my prior comment)…
There is a design space here. E.g. one set of options is:
- (stable Rust behavior): in all editions, support arbitrary
impl Not<Output=bool>
for first parameter toassert!
;- in edition >= 2024, support just
Deref<Target=bool>
for first parameter toassert!
(e.g. by expanding tolet x: &bool = &$expr;
), or- (this PR): in edition >= 2024, support just
bool
for first parameter toassert!
.(And then there's variations thereof about how to handle editions < 2024, but that's a separate debate IMO.)
TC: What do we think?
match
is too complex" rust#122685Link: https://github.com/rust-lang/rust/pull/122685
TC: Nadri nominates this for us and describes the situation:
Dear T-lang, this PR adds a warning that cannot be silenced, triggered when a match takes a really long time to analyze (in the order of seconds). This is to help users figure out what's taking so long and fix it.
We could make the limit configurable or the warning
allow
able. I argue that's not necessary because crater showed zero regressions with the current limit, and it's be pretty easy in general to split up amatch
into smallermatch
es to avoid blowup.We're still figuring out the exact limit, but does the team approve in principle?
(As an aside, awhile back someone showed how to lower SAT to exhaustiveness checking with match
. Probably that would hit this limit.)
TC: What do we think?
count
, ignore
, index
, and length
(macro_metavar_expr
)" rust#122808Link: https://github.com/rust-lang/rust/pull/122808
TC: c410-f3r proposes the following for stabilization:
Stabilization proposal
This PR proposes the stabilization of a subset of
#![feature(macro_metavar_expr)]
or more specifically, the stabilization ofcount
,ignore
,index
andlength
.What is stabilized
Count
The number of times a meta variable repeats in total.
macro_rules! count_idents {
( $( $i:ident ),* ) => {
${count($i)}
};
}
fn main() {
assert_eq!(count_idents!(a, b, c), 3);
}
Ignore
Binds a meta variable for repetition, but expands to nothing.
macro_rules! count {
( $( $i:stmt ),* ) => {{
0 $( + 1 ${ignore($i)} )*
}};
}
fn main() {
assert_eq!(count!(if true {} else {}, let _: () = (), || false), 3);
}
Index
The current index of the inner-most repetition.
trait Foo {
fn bar(&self) -> usize;
}
macro_rules! impl_tuple {
( $( $name:ident ),* ) => {
impl<$( $name, )*> Foo for ($( $name, )*)
where
$( $name: AsRef<[u8]>, )*
{
fn bar(&self) -> usize {
let mut sum: usize = 0;
$({
const $name: () = ();
sum = sum.wrapping_add(self.${index()}.as_ref().len());
})*
sum
}
}
};
}
impl_tuple!(A, B, C, D);
fn main() {
}
Length
The current index starting from the inner-most repetition.
macro_rules! array_3d {
( $( $( $number:literal ),* );* ) => {
[
$(
[
$( $number + ${length()}, )*
],
)*
]
};
}
fn main() {
assert_eq!(array_3d!(0, 1; 2, 3; 4, 5), [[2, 3], [4, 5], [6, 7]]);
}
Motivation
Meta variable expressions not only facilitate the use of macros but also allow things that can't be done today like in the
$index
example.An initial effort to stabilize this feature was made in #111908 but ultimately reverted because of possible obstacles related to syntax and expansion.
Nevertheless, #83527 (comment) tried to address some questions and fortunately the lang team accept #117050 the unblocking suggestions.
Here we are today after ~4 months so everything should be mature enough for wider use.
What isn't stabilized
$$
is not being stabilized due to unresolved concerns.
TC: I asked WG-macros for feedback on this here:
TC: Josh proposed FCP merge on this stabilization.
Link: https://github.com/rust-lang/rfcs/pull/3098
TC: We've at various times discussed that we had earlier decided that if we wanted to use a new keyword within an edition, we would write it as k#keyword
, and for that reason, we prefer to not speculatively reserve keywords ahead of an edition (except, perhaps, when it's clear we plan to use it in the near future).
TC: Somewhat amusingly, however, we never in fact accepted that RFC. Back in 2021, we accepted scottmcm's proposal to cancel:
We discussed this RFC again in the lang team triage meeting today.
For the short-term goal of the reservation for the edition, we'll be moving forward on #3101 instead. As such, we wanted to leave more time for conversations about this one, and maybe use crater results from 3101 to make design changes,
@rfcbot cancel
Instead we accepted RFC 3101 that reserved ident#foo
, ident"foo"
, ident'f'
, and ident#123
starting in the 2023 edition.
Reading through the history, here's what I see:
k#keyword
, but it's another to actually do it in the face of certain criticism about that being e.g. unergonomic. Would we follow through?TC: What do we think?
Link: https://github.com/rust-lang/rfcs/pull/3624
TC: On 2024-04-24, we had discussed (on a gut check basis) a proposal from Amanieu to change method resolution such that when both a subtrait and one of its supertraits are in scope, shadowed methods from the subtrait would be chosen rather than resulting in ambiguity errors.
Most notably, this would allow the standard library to uplift methods from itertools
, which they've been deferring for years due to no way to do so without causing breakage. But there are many other possible uses and reasons to believe this might be a good rule.
After our last discussion, we had asked for an RFC. This is that RFC. What do we think?
start
feature" rust#29633Link: https://github.com/rust-lang/rust/issues/29633
TC: Nils proposes to us that we delete the unstable #[start]
attribute:
I think this issue should be closed and
#[start]
should be deleted. It's nothing but an accidentally leaked implementation detail that's a not very useful mix between "portable" entrypoint logic and bad abstraction.I think the way the stable user-facing entrypoint should work (and works today on stable) is pretty simple:
std
-using cross-platform programs should usefn main()
. the compiler, together withstd
, will then ensure that code ends up atmain
(by having a platform-specific entrypoint that gets directed throughlang_start
instd
tomain
- but that's just an implementation detail)no_std
platform-specific programs should use#![no_main]
and define their own platform-specific entrypoint symbol with#[no_mangle]
, likemain
,_start
,WinMain
ormy_embedded_platform_wants_to_start_here
. most of them only support a single platform anyways, and need cfg for the different platform's ways of passing arguments or other things anyways
#[start]
is in a super weird position of being neither of those two. It tries to pretend that it's cross-platform, but its signature is a total lie. Those arguments are just stubbed out to zero on Windows, for example. It also only handles the platform-specific entrypoints for a few platforms that are supported bystd
, like Windows or Unix-likes.my_embedded_platform_wants_to_start_here
can't use it, and neither could a libc-less Linux program. So we have an attribute that only works in some cases anyways, that has a signature that's a total lie (and a signature that, as I might want to add, has changed recently, and that I definitely would not be comfortable giving any stability guarantees on), and where there's a pretty easy way to get things working without it in the first place.Note that this feature has not been RFCed in the first place.
TC: What do we think?
anonymous_lifetime_in_impl_trait
" rust#107378Link: https://github.com/rust-lang/rust/pull/107378
TC: We unnominated this back in October 2023 as more analysis seemed to be needed. Since then, nikomatsakis and tmandry have posted substantive analysis that it seems we should discuss.
Link: https://github.com/rust-lang/rust/pull/120193
TC: Apparently our unstable likely
and unlikely
intrinsics don't work. There's a proposal to do some work on fixing that and stabilizing a solution here. The nominated question is whether we want to charter this as an experiment.
Link: https://github.com/rust-lang/rfcs/pull/3514
TC: In addition to documenting the current behavior carefully, this RFC (per RalfJ)…
says we should allow float operations in
const fn
, which is currently not stable. This is a somewhat profound decision since it is the first non-deterministic operation we stably allow inconst fn
. (We already allow those operations inconst
/static
initializers.)
TC: What do we think? tmandry proposed this for FCP merge back in October 2023.
Link: https://github.com/rust-lang/rust/issues/116907
TC: nnethercote has implemented most of RFC 3349 ("Mixed UTF-8 literals") and, based on implementation experience, argues that the remainder of the RFC should not be implemented:
I have a partial implementation of this RFC working locally (EDIT: now at #120286). The RFC proposes five changes to literal syntax. I think three of them are good, and two of them aren't necessary.
TC: What do we think?
i128
/u128
from the improper_ctypes
lint" lang-team#255Link: https://github.com/rust-lang/lang-team/issues/255
TC: Trevor Gross describes the situation:
For a while, Rust's 128-bit integer types have been incompatible with those from C. The original issue is here rust-lang/rust#54341, with some more concise background information at the MCP here rust-lang/compiler-team#683
The current Beta of 1.77 will have rust-lang/rust#116672, which manually sets the alignment of
i128
to make it ABI-compliant with any version of LLVM (clang
does something similar now). 1.78 will have LLVM18 as the vendored version which fixes the source of this error.Proposal: now that we are ABI-compliant, do not raise
improper_ctypes
on our 128-bit integers. I did some testing with abi-cafe and a more isolated https://github.com/tgross35/quick-abi-check during the time https://reviews.llvm.org/D86310 was being worked on, and verified everything lines up. (It would be great to have some fork of abi-cafe in tree, but that is a separate discussion.)@joshtriplett mentioned that changing this lint needs a lang FCP https://rust-lang.zulipchat.com/#narrow/stream/187780-t-compiler.2Fwg-llvm/topic/LLVM.20alignment.20of.20i128/near/398422037. cc @maurer
Reference change from when I was testing rust-lang/rust@c742908
TC: Josh nominates this for our discussion. What do we think?
is
operator for pattern-matching and binding" rfcs#3573Link: https://github.com/rust-lang/rfcs/pull/3573
TC: Josh proposes for us that we should accept:
if an_option is Some(x) && x > 3 {
println!("{x}");
}
And:
func(x is Some(y) && y > 3);
TC: The main topic discussed in the issue thread so far has been the degree to which Rust should have "two ways to do things". Probably the more interesting issue is how the binding and drop scopes for this should work.
TC: In the 2024-02-21 meeting (with limited attendance), we discussed how we should prioritize stabilizing let chains, and tmandry suggested we may want to allow those to settle first.
TC: What do we think, as a gut check?
Link: https://github.com/rust-lang/rfcs/pull/3458
TC: Nearly ten years ago, on 2014-10-09, pnkfelix proposed unsafe fields in RFC 381:
https://github.com/rust-lang/rfcs/issues/381
On 2017-05-04, Niko commented:
I am pretty strongly in favor of unsafe fields at this point. The only thing that holds me back is some desire to think a bit more about the "unsafe" model more generally.
Then, in 2023, Jacob Pratt refreshed this proposal with RFC 3458. It proposes that:
Fields may be declared
unsafe
. Unsafe fields may only be mutated (excluding interior mutability) or initialized in an unsafe context. Reading the value of an unsafe field may occur in either safe or unsafe contexts. An unsafe field may be relied upon as a safety invariant in other unsafe code.
E.g.:
struct Foo {
safe_field: u32,
/// Safety: Value must be an odd number.
unsafe unsafe_field: u32,
}
// Unsafe field initialization requires an `unsafe` block.
// Safety: `unsafe_field` is odd.
let mut foo = unsafe {
Foo {
safe_field: 0,
unsafe_field: 1,
}
};
On 2024-05-21, Niko nominated this for us:
I'd like to nominate this RFC for discussion. I've not read the details of the thread but I think the concept of unsafe fields is something that comes up continuously and some version of it is worth doing.
TC: What do we think?
Link: https://github.com/rust-lang/rfcs/pull/3556
TC: This seems to be about making the following work:
// kind is optional if it's been specified elsewhere, e.g. via the `-l` flag to rustc
#[link(name="ext", kind="static")]
extern {
#[no_mangle]
pub fn foo();
#[no_mangle]
pub static bar: std::ffi::c_int;
}
There are apparently use cases for this.
What's interesting is that apparently it already does, but we issue a warning that is wrong:
warning: `#[no_mangle]` has no effect on a foreign function
--> src/lib.rs:21:5
|
21 | #[no_mangle]
| ^^^^^^^^^^^^ help: remove this attribute
22 | pub fn foo_rfc3556_pub_with_no_mangle();
| ---------------------------------------- foreign function
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: symbol names in extern blocks are not mangled
TC: One of the author's asks of us is that we don't make this into a hard error (e.g. with the new edition).
TC: What do we think?
Link: https://github.com/rust-lang/rust/pull/118939
TC: The idea here seems to be to improve some diagnostics around macro_rules
, but this seems to be done by way of reserving the macro_rules
token more widely, which is a breaking change. Petrochenkov has objected to it on that basis, given that reserving macro_rules
minimally has been the intention since we hope it will one day disappear in favor of macro
. What do we think?
clippy::invalid_null_ptr_usage
lint" rust#119220Link: https://github.com/rust-lang/rust/pull/119220
TC: Urgau proposes this for us:
This PR aims at uplifting the
clippy::invalid_null_ptr_usage
lint into rustc, this is similar to theclippy::invalid_utf8_in_unchecked
uplift a few months ago, in the sense that those two lints lint on invalid parameter(s), here a null pointer where it is unexpected and UB to pass one.
invalid_null_ptr_usages
(deny-by-default)
The
invalid_null_ptr_usages
lint checks for invalid usage of null pointers.Example
// Undefined behavior
unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
// Not Undefined behavior
unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
Produces:
error: calling this function with a null pointer is undefined behavior, even if the result of the function is unused, consider using a dangling pointer instead
--> $DIR/invalid_null_ptr_usages.rs:14:23
|
LL | let _: &[usize] = std::slice::from_raw_parts(ptr::null(), 0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^
| |
| help: use a dangling pointer instead: `core::ptr::NonNull::dangling().as_ptr()`
Explanation
Calling methods who's safety invariants requires non-null pointer with a null pointer is undefined behavior.
The lint use a list of functions to know which functions and arguments to checks, this could be improved in the future with a rustc attribute, or maybe even with a
#[diagnostic]
attribute.
TC: What do we think?
Link: https://github.com/rust-lang/rust/pull/122412
TC: Waffle nominates this breaking change for us:
This changes
expr?
's desugaring like so (simplified, see code for more info):// old match expr { Ok(val) => val, Err(err) => return Err(err), } // new match expr { Ok(val) => val, Err(err) => core::convert::absurd(return Err(err)), } // core::convert pub const fn absurd<T>(x: !) -> T { x }
This prevents
!
from thereturn
from skewing inference:// previously: ok (never type spontaneous decay skews inference, `T = ()`) // with this pr: can't infer the type for `T` Err(())?;
We discussed this on 2024-03-20. On the one hand, people were hesitant to block incremental progress, but on the other, people were hesitant to add a special case if we could address a more general case. There was, I would say, appetite for taking a bigger bite here, but people were uncertain if there were any bigger bites that were feasible other than those discussed to support the never type generally, such as disabling fallback to ()
.
In terms of next steps, we wanted to see an answer about the pros and cons of doing this for return
generally, which @WaffleLapkin has now answered:
it made me wonder whether it would be feasible to change return in general to be a free type variable instead of
!
?@scottmcm I'm not sure. I don't think it's unfeasible, but it sure is harder than this.
The issues are:
- Need to add fallback for those type variables too, so that
return;
works{ return; }
(which is currently!
even though there is;
) needs to be special cased in a different way- Will break strictly more things
I'm not sure if this is a good idea or not. It's kinda weird.
…and we wanted to see the results of the crater run that we know that @WaffleLapkin is working to make happen.
When taking this back up, in addition to those details, we wanted to specifically consider how this incremental step may be addressing known footguns with unsafe code such as that in:
https://github.com/rust-lang/rust/issues/51125
TC: What do we think?
Link: https://github.com/rust-lang/rust/issues/123231
TC: RalfJ nominates this for us. Consider this code:
#![feature(c_unwind)]
struct Noise;
impl Drop for Noise {
fn drop(&mut self) {
eprintln!("Noisy Drop");
}
}
extern "C" fn test() {
let _val = Noise;
panic!("heyho");
}
fn main() {
test();
}
It doesn't print anything. Should it?
clippy::double_neg
lint as double_negation
" rust#126604Link: https://github.com/rust-lang/rust/pull/126604
TC: This proposes to lint against cases like this:
fn main() {
let x = 1;
let _b = --x; //~ WARN use of a double negation
}
TC: What do we think?
const {}
blocks, and const { assert!(...) }
" lang-team#251Link: https://github.com/rust-lang/lang-team/issues/251
TC: This issue was raised due to discussion in a T-libs-api call. Josh gives the context:
In discussion of rust-lang/libs-team#325 (a proposal for a compile-time assert macro), the idea came up to allow
const {}
blocks at item level, and then have people useconst { assert!(...) }
.@rust-lang/libs-api would like some guidance from @rust-lang/lang about whether lang is open to toplevel
const { ... }
blocks like this, which would influence whether we want to add a compile-time assert macro, as well as what we want to call it (e.g.static_assert!
vsconst_assert!
vs some other name).Filing this issue to discuss in a lang meeting. This issue is not seeking any hard commitment to add such a construct, just doing a temperature check.
CAD97 noted:
To ensure that it's noted: if both item and expression
const
blocks are valid in the same position (i.e. in statement position), a rule to disambiguate would be needed (like for statement versus expressionif
-else
). IMO it would be quite unfortunate for item-levelconst
blocks to be evaluated pre-mono if that sameconst
block but statement-level would be evaluated post-mono.Additionally: since
const { assert!(...) }
is post-mono (due to using the generic context), it's potentially desirable to push people towards usingconst _: () = assert!(...);
(which is pre-mono) whenever possible (not capturing generics).
TC: What do we think?
Link: https://github.com/rust-lang/rust/pull/118833
TC: In the 2024-01-03 call, we developed a tentative consensus to lint against direct function pointer comparison and to push people toward using ptr::fn_addr_eq
. We decided to ask T-libs-api to add this. There's now an open proposal for that here:
https://github.com/rust-lang/libs-team/issues/323
One question that has come up is whether we would expect this to work like ptr::addr_eq
and have separate generic parameters, e.g.:
/// Compares the *addresses* of the two pointers for equality,
/// ignoring any metadata in fat pointers.
///
/// If the arguments are thin pointers of the same type,
/// then this is the same as [`eq`].
pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool { .. }
Or whether we would prefer that fn_addr_eq
enforced type equality of the function pointers. Since we're the ones asking for this, we probably want to develop a consensus here. We discussed this in the call on 2024-01-10, then we opened a Zulip thread:
TC: On this subject, scottmcm raised this point, with which pnkfelix seemed to concur:
I do feel like if I saw code that had
fn1.addr() == fn2.addr()
(ifFnPtr
were stabilized), I'd write a comment saying "isn't that whatfn_addr_eq
is for?"If the answer ends up being "no, actually, because I have different types", that feels unfortunate even if it's rare.
(Like how
addr_eq(a, b)
is nice even if with strict provenance I could writea.addr() == b.addr()
anyway.)
TC: scottmcm also asserted confidence that allowing mixed-type pointer comparisons is correct for ptr::addr_eq
since comparing the addresses of *const T
, *const [T; N]
, and *const [T]
are all reasonable. I pointed out that, if that's reasonable, then ptr::fn_addr_eq
is the higher-ranked version of that, since for the same use cases, it could be reasonable to compare function pointers that return those three different things or accept them as arguments.
TC: Adding to that, scottmcm noted that comparing addresses despite lifetime differences is also compelling, e.g. comparing fn(Box<T>) -> &'static mut T
with for<'a> fn(Box<T>) -> &'a mut T
.
TC: Other alternatives we considered were not stabilizing ptr::fn_addr_eq
at all and instead stabilizing FnPtr
so people could write ptr::addr_eq(fn1.addr(), fn2.addr())
, or expecting that people would write instead fn1 as *const () == fn2 as *const ()
.
TC: Recently CAD97 raised an interesting alternative:
From the precedent of
ptr::eq
andptr::addr_eq
, I'd expect a "ptr::fn_eq
" to have one generic type and a "ptr::fn_addr_eq
" to have two. Even ifptr::fn_eq
's implementation is just an address comparison, it still serves as a documentation point to call out the potential pitfalls with comparing function pointers.
TC: What do we think?
TC: Separately, on the 2024-01-10 call, we discussed some interest use cases for function pointer comparison, especially when it's indirected through PartialEq
. We had earlier said we didn't want to lint when such comparisons were indirected through generics, but we did address the non-generic case of simply composing such comparisons.
One example of how this is used is in the standard library, in Waker::will_wake
:
https://doc.rust-lang.org/core/task/struct.Waker.html#method.will_wake
It's comparing multiple function pointers via a #[derive(PartialEq)]
on the RawWakerVTable
.
We decided on 2024-01-01 that this case was interesting and we wanted to think about it further. We opened a discussion thread about this:
Since then, another interesting use case in the standard library was raised, in the formatting machinery:
https://doc.rust-lang.org/src/core/fmt/rt.rs.html
What do we think about these, and would we lint on derived PartialEq
cases like these or no?
Link: https://github.com/rust-lang/rust/pull/121364
TC: The proposal is to lint against:
-2.pow(2); // Equals -4.
These would instead be written:
-(2.pow(2)); // Equals -4.
TC: This is a subset of:
https://github.com/rust-lang/rust/pull/117161
…which is also nominated. Whereas the #117161 proposal is to lint on both binary op and unary op cases, this proposal is to lint only on unary op cases. The proposal for this subset came out a discussion with scottmcm.
TC: What do we think?
clippy::precedence
lint" rust#117161Link: https://github.com/rust-lang/rust/pull/117161
TC: The proposal is to lint against:
-2.pow(2); // Equals -4.
1 << 2 + 3; // Equals 32.
These would instead be written:
-(2.pow(2)); // Equals -4.
1 << (2 + 3); // Equals 32.
Prompts for discussion:
rustc
?!
, *
, &
)?Link: https://github.com/rust-lang/rust/issues/62569
TC: Prior to main()
being executed, the Rust startup code makes a syscall to change the handling of SIGPIPE
. Many believe that this is wrong thing for a low-level language like Rust to do, because 1) it makes it impossible to recover what the original value was, and 2) means things like seccomp
filters must be adjusted for this.
It's also just, in a practical sense, wrong for most CLI applications.
This seems to have been added back when Rust had green threads and then forgotten about. But it's been an ongoing footgun.
Making a celebrity appearance, Rich Felker, the author of MUSL libc, notes:
As long as Rust is changing signal dispositions inside init code in a way that the application cannot suppress or undo, it is fundamentally unusable to implement standard unix utilities that run child processes or anything that needs to preserve the signal dispositions it was invoked with and pass them on to children. Changing inheritable process state behind the application's back is just unbelievably bad behavior and does not belong in a language runtime for a serious language…
As an example, if you implement
find
in Rust, the-exec
option will invoke its commands withSIGPIPE
set toSIG_IGN
, so that they will not properly terminate on broken pipe. But if you just made it setSIGPIPE
toSIG_DFL
before invoking the commands, now it would be broken in the case where the invoking user intentionally setSIGPIPE
toSIG_IGN
so that the commands would not die on broken pipe.
There was discussion in 2019 about fixing this over an edition, but nothing came of it.
Are we interested in fixing it over this one?
Strawman (horrible) proposal: We could stop making this pre-main syscall in Rust 2024 and have cargo fix
insert this syscall at the start of every main
function.
(In partial defense of the strawman, it gets us directly to the arguably best end result while having an automatic semantics-preserving edition migration and it avoids the concerns about lang/libs coupling that Mara raised. The edition migration could add a comment above this inserted code telling people under what circumstances they should either keep or delete the added line.)
Link: https://github.com/rust-lang/rust/issues/116557
TC: nikomatsakis nominated this:
We had some discussion about types/lang team interaction. We concluded a few things:
- Pinging the team like @rust-lang/lang is not an effective way to get attention. Nomination is the only official way to get attention.
- It's ok to nominate things in an "advisory" capacity but not block (e.g., landing a PR), particularly as most any action can ultimately be reversed. But right now, triagebot doesn't track closed issues, so that's a bit risky.
Action items:
- We should fix triagebot to track closed issues.
TC: What do we think?
Link: https://github.com/rust-lang/rfcs/pull/3627
TC: In the design meeting on 2024-05-15, we discussed Match Ergonomics 2024. We liked what we heard, and people wanted to see this move forward modulo adopting Option 1 (make mut x
in inherited patterns an error). This change was made, and in the meeting on 2024-05-24, we resolved the concerns about this.and it moved into FCP.
Since then, tmandry has raised a concern to ask what tradeoffs we're making with the no ref mut
behind &
rule. The purpose of this rule is to allow patterns like this:
let &(i, j, [s]) = &(63, 42, &mut [String::from("")]); //~ OK
//~^ i: i32, j: i32, s: &String
One motivation is that there are already cases in patterns where immutability takes precedence over mutability (so it usually works). E.g.:
let [a] = &mut &[42]; // x: &i32
let [a] = &&mut [42]; // x: &i32
As the RFC says,
This change, in addition to being generally useful, makes the match ergonomics rules more consistent by ensuring that immutability always takes precedence over mutability.
The main drawback seems to be that, with this rule, one cannot:
…consistently write a
&mut
pattern that matches an inherited reference regardless of whether the binding mode has been converted toref
by an outer&
so long as there is a&mut
type involved.
That is, this is allowed:
//@ edition: 2024
let [[&mut x]] = [&mut [42]]; //~ OK, x: i32
(Because the ref mut
is not behind an &
.)
But these are not:
//@ edition: 2024
let &[[&mut x]] = &[&mut [42]]; //~ ERROR
let [[&mut x]] = &[&mut [42]]; //~ ERROR
(Because the ref mut
is behind an &
.)
However, one can write, and is intended to write, these instead:
//@ edition: 2024
let [[&x]] = [&mut [42]]; //~ OK
let &[[&x]] = &[&mut [42]]; //~ OK
let [[&x]] = &[&mut [42]]; //~ OK
These take advantage of the fact that &
matches &mut
. The reason that &
matching &mut
was included in this RFC (rather than e.g. being deferred to future work) was for explicitly this reason.
TC: Separately, tmandry writes:
Everything in this RFC, including the migration lint, is either already in nightly under an experimental feature gate, or waiting on PR review.
Fantastic, thanks for your efforts here. Ideally I would like to see this go in as part of the unstable 2024 edition once this RFC lands, i.e. not blocking on a stabilization FCP before that happens.
TC: Does this sound right to us?
core::marker::Freeze
in bounds" rfcs#3633Link: https://github.com/rust-lang/rfcs/pull/3633
TC: There's now a proposal on the table for the stabilization of the Freeze
trait in bounds.
TC: We'll probably need to schedule a design meeting to work through this.
Link: https://github.com/rust-lang/rfcs/pull/3654
TC: Niko has now posted the long-awaited RFC for RTN in bounds and where clauses.
Return type notation (RTN) gives a way to reference or bound the type returned by a trait method. The new bounds look like
T: Trait<method(..): Send>
orT::method(..): Send
. The primary use case is to add bounds such asSend
to the futures returned byasync fn
s in traits and-> impl Future
functions, but they work for any trait function defined with return-position impl trait (e.g.,where T: Factory<widgets(..): DoubleEndedIterator>
would also be valid).This RFC proposes a new kind of type written
<T as Trait>::method(..)
(orT::method(..)
for short). RTN refers to "the type returned by invokingmethod
onT
".To keep this RFC focused, it only covers usage of RTN as the
Self
type of a bound or where-clause. The expectation is that, after accepting this RFC, we will gradually expand RTN usage to other places as covered under Future Possibilities. As a notable example, supporting RTN in struct field types would allow constructing types that store the results of a call to a trait-> impl Trait
method, making them more suitable for use in public APIs.
TC: We'll probably need to schedule a design meeting to work through this.
PartialOrd
and Ord
for Discriminant
" rust#106418Link: https://github.com/rust-lang/rust/pull/106418
TC: We discussed this last in the meeting on 2024-03-13. scottmcm has now raised on concern on the issue and is planning to make a counter-proposal:
I remain concerned about exposing this with no opt-out on an unrestricted generic type @rfcbot concern overly-broad
I'm committing to making an alternative proposal because I shouldn't block without one. Please hold my feet to the fire if that's no up in a week.
Basically, I have an idea for how we might be able to do this, from #106418 (comment)
- Expose the variant ordering privately, only accessible by the type owner/module.
Solution 2. is obviously more desirable, but AFAIK Rust can't do that and there is no proposal to add a feature like that.
https://github.com/rust-lang/rust/pull/106418#issuecomment-1994833151
Link: https://github.com/rust-lang/rust/issues/121708
TC: We discussed this in the meeting on 2024-03-13. The feelings expressed included:
TC: tmandry volunteered to draft a policy proposal.
Link: https://github.com/rust-lang/rust/issues/122301
TC: The8472 asks whether this code, which compiles today, can be relied upon:
const fn panic<T>() {
struct W<T>(T);
impl<T> W<T> {
const C: () = panic!();
}
W::<T>::C
}
struct Invoke<T, const N: usize>(T);
impl<T, const N: usize> Invoke<T, N> {
const C: () = match N {
0 => (),
// Not called for `N == 0`, so not monomorphized.
_ => panic::<T>(),
};
}
fn main() {
let _x = Invoke::<(), 0>::C;
}
The8472 notes that this is a useful property and that there are use cases for this in the compiler and the standard library, at least unless or until we adopt something like const if
:
https://github.com/rust-lang/rfcs/issues/3582
RalfJ has pointed out to The8472 that the current behavior might not be intentional and notes:
It's not opt-dependent, but it's also unclear how we want to resolve the opt-dependent issue. Some proposals involve also walking all items "mentioned" in a const. That would be in direct conflict with your goal here I think. To be clear I think that's a weakness of those proposals. But if that turns out to be the only viable strategy then we'll have to decide what we want more: using
const
tricks to control what gets monomorphized, or not having optimization-dependent errors.One crucial part of this construction is that everything involved is generic. If somewhere in the two "branches" you end up calling a monomorphic function, then that may have its constants evaluated even if it is in the "dead" branch – or it may not, it depends on which functions are deemed cross-crate-inlinable. That's basically what #122814 is about.
TC: The question to us is whether we want to guarantee this behavior. What do we think?
Link: https://github.com/rust-lang/rust/issues/122759
TC: In the call on 2024-03-13, we discussed this issue raised by tmandry:
"Fallout from expansion of redundant import checking"
https://github.com/rust-lang/rust/issues/121708
During the call, the thoughts expressed included:
TC: tmandry volunteered to draft a policy proposal. He's now written up this proposal in this issue.
Background
When a lint is expanded to include many new cases, it adds significant complexity to the rollout of a toolchain to large codebases. Maintainers of these codebases are stuck with the choice of
- Disabling the existing lint while the toolchain is updated and new cases are fixed
- Fixing cases manually and updating the toolchain immediately
Both of these come with the problem of racing with other developers in a codebase who may land new code which triggers the expanded lint in a new compiler, but does not trigger the lint in an old compiler.
While it would be nice to solve this "raciness" once and for all, there are other considerations at play. Instead, we propose to support these users by either providing them with a new lint name to temporarily opt out of OR a machine-applicable fix which eases the pain of any races which might occur.
Note that this requirement only applies to significant lint expansions as measured by crater.
Policy
When an existing lint is expanded to include many new cases, we must provide either:
- A new lint name under the existing group, so that users may opt out of the expansion at least temporarily, or
- A MachineApplicable fix for the lint.
Exceptions to this policy may be made via Language Team FCP.
Here, we define "many new cases" as impacting more than 5% of the top-1000 crates on crates.io. This can be measured by counting the number of regressions from a crater run like the one below.
A crater run is not required before landing for every lint expansion. Reviewers should use their best judgment to decide if one is required. However, if a lint expansion lands that violates this requirement, or is strongly suspected to violate this requirement based on other impact, it should be reverted.
Crater command
To measure the impact of a lint as defined by this policy, you can use the following crater command:
@craterbot run name=<name> start=master#<hash1>+rustflags=-D<lint_name> end=master#<hash2>+rustflags=-D<lint_name> crates=top-1000 mode=check-only p=1
See the crater docs for more information.
TC: What do we think?
Link: https://github.com/rust-lang/rust/issues/125418
TC: We reviewed in triage an RFC for externally implementable functions on 2024-05-22 along with a companion/alternative RFC for externally implementable statics. That discussion produced two more proposals, one from Amanieu and one from tmandry.
TC: We're likely going to need a design meeting to work through these.
None.
Link: https://github.com/rust-lang/lang-team/pull/236
Link: https://github.com/rust-lang/lang-team/pull/237
Link: https://github.com/rust-lang/lang-team/pull/258
Link: https://github.com/rust-lang/lang-team/pull/267
None.
S-waiting-on-team
Link: https://github.com/rust-lang/rust/pull/116863
Link: https://github.com/rust-lang/rust/pull/120221
Link: https://github.com/rust-lang/rust/pull/120706
count
, ignore
, index
, and length
(macro_metavar_expr
)" rust#122808Link: https://github.com/rust-lang/rust/pull/122808
Link: https://github.com/rust-lang/rust/pull/118939
AsyncIterator
back to Stream
, introduce an AFIT-based AsyncIterator
trait" rust#119550Link: https://github.com/rust-lang/rust/pull/119550
#[deny]
inside #[forbid]
as a no-op with a warning" rust#121560Link: https://github.com/rust-lang/rust/pull/121560
include!
macro" rust#125205Link: https://github.com/rust-lang/rust/pull/125205
Check your boxes!
Link: https://github.com/rust-lang/rust/pull/126762
const_cstr_from_ptr
" rust#113219Link: https://github.com/rust-lang/rust/issues/113219
Link: https://github.com/rust-lang/rfcs/pull/3637
elided_lifetimes_in_associated_constant
to deny" rust#124211Link: https://github.com/rust-lang/rust/pull/124211
repr(discriminant = ...)
for type aliases" rfcs#3659Link: https://github.com/rust-lang/rfcs/pull/3659
#[coverage]
" rust#84605Link: https://github.com/rust-lang/rust/issues/84605
Link: https://github.com/rust-lang/rust/pull/120221
count
, ignore
, index
, and length
(macro_metavar_expr
)" rust#122808Link: https://github.com/rust-lang/rust/pull/122808
Link: https://github.com/rust-lang/rfcs/pull/3624
anonymous_lifetime_in_impl_trait
" rust#107378Link: https://github.com/rust-lang/rust/pull/107378
Link: https://github.com/rust-lang/rfcs/pull/3514
Link: https://github.com/rust-lang/rfcs/pull/3632
Link: https://github.com/rust-lang/rfcs/pull/3627
PartialOrd
and Ord
for Discriminant
" rust#106418Link: https://github.com/rust-lang/rust/pull/106418
Link: https://github.com/rust-lang/rust/issues/122759
Link: https://github.com/rust-lang/rfcs/pull/2375
Link: https://github.com/rust-lang/rfcs/pull/3288
Link: https://github.com/rust-lang/rfcs/pull/3379
use Trait::func
" rfcs#3591Link: https://github.com/rust-lang/rfcs/pull/3591
Link: https://github.com/rust-lang/rfcs/pull/3621
#[export_ordinal(n)]
attribute" rfcs#3641Link: https://github.com/rust-lang/rfcs/pull/3641
Link: https://github.com/rust-lang/rfcs/pull/3657
Link: https://github.com/rust-lang/rust/issues/120140
Link: https://github.com/rust-lang/rust/issues/120141
Link: https://github.com/rust-lang/rust/pull/120700
#[deny]
inside #[forbid]
as a no-op with a warning" rust#121560Link: https://github.com/rust-lang/rust/pull/121560
Link: https://github.com/rust-lang/rust/issues/121608
impl Trait + use<..>
" rust#125836Link: https://github.com/rust-lang/rust/issues/125836
#![crate_name = EXPR]
semantically allows EXPR
to be a macro call but otherwise mostly ignores it" rust#122001Link: https://github.com/rust-lang/rust/issues/122001
Link: https://github.com/rust-lang/rfcs/pull/3654
None.