owned this note
owned this note
Published
Linked with GitHub
---
title: Triage meeting 2024-03-06
tags: ["T-lang", "triage-meeting", "minutes"]
date: 2024-03-06
discussion: https://rust-lang.zulipchat.com/#narrow/stream/410673-t-lang.2Fmeetings/topic/Triage.20meeting.202024-03-06
url: https://hackmd.io/U-CKiZx_RKiaANAPXtWf7g
---
# T-lang meeting agenda
- Meeting date: 2024-03-06
## Attendance
This meeting occurred in two parts. The first part included:
- People: TC, Josh, Santiago, CE, Lukas Wirth, pnkfelix, Xiangfei Ding, Waffle, nikomatsakis, fmease, bstrie, scottmcm
And the second part, continuing during the planning meeting slot, included:
- People: TC, pnkfelix, scottmcm, Josh, nikomatsakis, eholk, Lukas Wirth, Xiangfei Ding, CE
## Meeting roles
- Minutes, driver: TC
## Scheduled meetings
- 2024-03-06: Planning meeting (starting half an hour after end of triage).
Edit the schedule here: https://github.com/orgs/rust-lang/projects/31/views/7.
## Announcements or custom items
### Guest attendee / nominated item correlation
Josh: If we have any guest attendees who are waiting for a particular item to participate in that discussion, we should check for those, and perhaps try to get to those.
### Moving right along
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.
### Planning meeting at 12:30 EST / 09:30 PST
TC: Note that, corresponding to our change for design meetings, our planning meeting has been moved up half an hour, so it will start half an hour after the end of this meeting.
### RTN
TC: We had a call 2024-03-04 to discuss the syntax of RTN. There was no explicit consensus from that meeting, but the general mood was that there were two axes along which we might find consensus:
- Axis 1: Whether to say `()` or `(..)` as sugar for `::Output`.
- Axis 2: Whether and how to distinguish the type namespace from the value namespace.
The next step seemed to be the authoring of an RFC.
nikomatsakis: Next steps from my POV...
* Author the RFC and kick-start public conversation.
* Revise write-up focusing on the final decision space (the axes you mentioned above, for example.
* ...and highlighting the shared values that seemed to be popping up in people's write-ups.
* Niko is mildly curious about gathering up some data -- e.g., doing some interviewing, I'm doing some thinking about this.
## Rust 2024 review
Project board: https://github.com/orgs/rust-lang/projects/43/views/5
### Tracking Issue for Lifetime Capture Rules 2024 (RFC 3498) #117587
**Link:** https://github.com/rust-lang/rust/issues/117587
TC: We accepted the RFC and the implementation has landed for Rust 2024. We do need to stabilize some way of expressing precise capturing. That probably means stabilizing TAIT. We're starting with stabilizing ATPIT.
TC: That stabilization had become blocked on an FCP about "once modulo regions" that itself had become blocked on questions about the handling of the capturing of higher-ranked lifetimes in the new trait solver.
TC: I discussed this with aliemjay, and on the basis of that discussion, aliemjay has now resolved that concern and agrees that we can do here what we did for RPITIT and give a hard error when higher-ranked lifetimes would be captured in an opaque under the RFC 3498 rules (since capturing higher-ranked lifetimes in opaques is not yet supported).
TC: This unblocks ATPIT. However, aliemjay may seek to block the stabilization of the new capture rules for bare RPIT in 2024 on these questions about the implementation direction of the new trait solver, so we'll need to stay on top of this and ensure that the relevant investigations and analyses take place.
TC: As background, we're talking about code like this:
```rust
trait Trait<'a> { type Assoc; }
impl<'a, F: Fn(&'a ())> Trait<'a> for F { type Assoc = (); }
trait Rpitit {
fn foo() -> impl for<'a> Trait<'a, Assoc = impl Sized> {
//~^ ERROR higher ranked lifetime bounds on nested opaque types are not supported yet
|_: &()| ()
}
}
```
NM: For Rust 2024 we are talking about stabilizing new capture rules, which means...
```rust
trait Trait<'a> { type Assoc; }
impl<'a, F: Fn(&'a ())> Trait<'a> for F { type Assoc = (); }
fn foo() -> impl for<'a> Trait<'a, Assoc = impl Sized> {
//~^ Rust 2021: No error
//~| Rust 2024: Gives an error today, consistent with the above.
//
// The concern is that if we are going to stabilize Rust 2024 capture we have
// to reconcile these.
|_: &()| ()
}
```
### Reserve gen keyword in 2024 edition for Iterator generators #3513
**Link:** https://github.com/rust-lang/rfcs/pull/3513
TC: After the call last week, we were doing two things on this RFC:
- Moving `gen fn` to be a future possibility.
- Adding whether to support borrowing across yield points as an unresolved question.
We've done the first. We'll do the second (it's currently listed as a future possibility).
TC: There is a proposed FCP started here.
TC: If you haven't tried these (or async closures) yet in nightly, here's how to do it:
```toml
cargo-features = ["edition2024"]
[package]
edition = "2024"
```
```rust
#![feature(async_closure)]
#![feature(async_iterator)]
#![feature(gen_blocks)]
use core::{async_iter::{AsyncIterator, IntoAsyncIterator},
future::{poll_fn, ready}, pin::pin};
async fn f<F: async Fn() -> u8>(f: F) -> u8 { f().await }
async fn g<G: IntoAsyncIterator<Item = u8>>(g: G) -> Option<u8> {
let mut g = pin!(g.into_async_iter());
poll_fn(|cx| g.as_mut().poll_next(cx)).await
}
fn main() {
f(async || ready(42u8).await);
g(async gen {
yield 42u8;
});
}
```
TC: It came up in the 2024-02-28 meeting that we may want to think about whether to reserve in Rust 2024 the `yields` keyword for generator closures, e.g.:
```rust
let _ = gen |x| yields u8 { todo!() };
```
TC: We'll think about writing that up as a separate RFC.
nikomatsakis: I think we can get away with just adding "to reserve `yields` or not" as an unresolved question and avoid the need to make it a full RFC.
scottmcm: We decided not to reserve keywords because we are "likely to go down this syntactic path".
joshtriplett: Agreed. We can try to decide if this syntax passes the "smell test", because that's not *sufficient* but it is *necessary*.
NM: +1 to scottmcm, if we can't get more alignment around the syntax, perhaps we live with `k#`. We should consider using a similar approach to what we did for RTN syntax to try to drive consensus.
### Tracking issue for promoting `!` to a type (RFC 1216) #35121
**Link:** https://github.com/rust-lang/rust/issues/35121
TC: This is what we had been hoping to lint against:
```rust
fn never_type_fallback() { unsafe {
if false { panic!() } else { transmute::<_, _ /* ?0 */>(()) }
// later in fallback: ?0 := ()
// after ! stabilization: ?0 := !
}}
```
TC: We'd been hoping to use the edition to help push this along. We've discussed that this would be a good topic for a design meeting, both to help push this along and because it seems that many of us each only have a partial understanding, so it would help to try to unify these.
TC: Perhaps let's plan to talk about this in the planning meeting.
nikomatsakis: +1.
## Nominated RFCs, PRs, and issues
### "Split refining_impl_trait lint into _reachable, _internal variants" rust#121720
**Link:** https://github.com/rust-lang/rust/pull/121720
TC: We agreed to do this. tmandry now would like some feedback about the implementation:
> This PR implements that consensus, but I'd like feedback on the lint naming and documentation. See the tests for examples of the lints that are added.
TC: What do we think?
Josh: Is there a specific concern that this may not be the right approach or just a confirmation this is generally right?
TC: The latter, I believe.
Josh: It comes down, I think, to whether we want these warnings.
NM: This looks like what we asked for.
Josh: Let's do FCP here.
*Consensus*: Let's do this via FCP.
FCP link: https://github.com/rust-lang/rust/pull/121720#issuecomment-1981267965
### "`non_local_definitions` common issues: impl for `&Local`, `From<Local> for Global`, ..." rust#121621
**Link:** https://github.com/rust-lang/rust/issues/121621
Josh: Moved this up because they're seeking timely feedback and we may need to revisit a decision we'd made for the edition.
Josh: There are cases where we warn where perhaps we should. There are also cases where we warn where it's technically correct (e.g. `impl Global for &Local` if there's only one impl of `Global` that could match) but strange.
(scott aside: This inference behaviour is annoying for semver.)
Waffle: lcnr has posted a proposal for how to fix the lint. (specifically the false warnings for cases like `From` where information is not actually leaked)
NM: I would like to improve our inference behavior here. I wish we did less inference based on the impls that exist. It's going to take some energy to make changes there. It's going to take an owner. Not sure whether that's on the table. For the lint, the question is how much this supposed to give us a strong guarantee versus not.
Josh: There are two things for which the lint is valuable. One is for humans, the other is for maybe making IDEs more efficient. For the former, it just needs to be helpful. For the latter, it would need to be perfect. Since we're not on track to make this a hard error, we should err on the side of not producing too many false positives here. Or we could have a `_strict` version of the lint that we improve over time.
Josh: But I don't think we should gate on inference changes here, I think we should carve out bits of the lint causing false positives.
Waffle: We should implement what lcnr said, then look at what are the next steps.
Josh: That's what's summarized by lcnr two days ago?
Waffle: Yes. It's here:
https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895
scottmcm: Is there anything this needs to do around `fundamental`?
Waffle: The lint handles fundamental types correctly, I believe. It warns on those things that can technically leak stuff, but may do it in weird ways. We may want to carve this out if the lint is too noisy here.
Josh: `fundamental` may be a good carving point for the lint here if that's feasible.
*Consensus*: Let's let lcnr's proposal move forward then re-evaluate.
### "Arbitrary self types v2" rfcs#3519
**Link:** https://github.com/rust-lang/rfcs/pull/3519
TC: We had a design meeting about this on 2024-02-28. The identified next step was to write up a list of the available options. That document is here:
https://hackmd.io/eXfrzrR7T1-3HVh6w5JMqA
The general mood in the meeting tended in the direction of doing the simpler thing for now (supporting only newtype wrappers) and saving space by giving a hard error on resolution ambiguity, but there were various concerns.
TC: I'm writing up a document to bring these together. So I may reach out to you to set up a call to be sure your views and concerns are faithfully represented.
nikomatsakis: +1
### "Stabilize associated type bounds (RFC 2289)" rust#122055
**Link:** https://github.com/rust-lang/rust/pull/122055
TC: CE is now ready to stabilize associated type bounds. There had been open questions here about the desugaring that he has now answered. As it turns out, the earlier desugarings had been essentially workarounds for limitations in type checking which he has now fixed. This allows the resulting desugaring to be simple and obvious bounds and does not require e.g. adding additional anonymous associated types to traits.
> Associated type bounds are stabilized in four positions:
>
> * **`where` clauses (and APIT)** - This is equivalent to breaking up the bound into two (or more) `where` clauses. For example, `where T: Trait<Assoc: Bound>` is equivalent to `where T: Trait, <T as Trait>::Assoc: Bound`.
> * **Supertraits** - Similar to above, `trait CopyIterator: Iterator<Item: Copy> {}`. This is almost equivalent to breaking up the bound into two (or more) `where` clauses; however, the bound on the associated item is implied whenever the trait is used. See [Should associated type bounds on supertraits be implied? #112573](https://github.com/rust-lang/rust/issues/112573)/[Make associated type bounds in supertrait position implied #112629](https://github.com/rust-lang/rust/pull/112629).
> * **Associated type item bounds** - This allows constraining the _nested_ rigid projections that are associated with a trait's associated types. e.g. `trait Trait { type Assoc: Trait2<Assoc2: Copy>; }`.
> * **opaque item bounds (RPIT, TAIT)** - This allows constraining associated types that are associated with the opaque without having to _name_ the opaque. For example, `impl Iterator<Item: Copy>` defines an iterator whose item is `Copy` without having to actually name that item bound.
>
> The latter three are not expressible in surface Rust (though for associated type item bounds, this will change in #120752, which I don't believe should block this PR), so this does represent a slight expansion of what can be expressed in trait bounds.
TC: What do we think?
scottmcm: It's great to see progress on this especially since RTN was going to use something like this.
JT: I'm so excited to see this happen. People already expect this to work.
CE: Note that this does not stabilize ATB in `dyn`. There are good reasons for this. I think this is solid now.
Josh: I'll start the FCP here.
*Consensus*: Let's do this via FCP.
### "Make casts of pointers to trait objects stricter" rust#120248
**Link:** https://github.com/rust-lang/rust/pull/120248
TC: Waffle nominates this one for us:
> I'm nominating this for discussion in t-lang. I want to confirm if we are OK with the following **breaking changes**.
>
> For context, those are being made to prevent a few different, yet related, unsound issues found while stabilizing trait upcasting. Those issues require either `#![feature(trait_upcasting)]` or `#![feature(arbitrary_self_types)]` and revolve around creating pointers to trait objects with incorrect vtables (which, I believe, we previously decided to forbid).
>
> The issues are #120222 and #120217. There is also an issue found while working on this PR, which has not been opened as a separate issue. This comment will refer to specific issues/comments/examples when they are relevant to the proposed breaking changes.
>
> See also @lcnr's comment [down below](https://github.com/rust-lang/rust/pull/120248#issuecomment-1977297105) for an alternative solution.
>
> ## 1. Generics must match
>
> This prevents casting `*const dyn Trait<A>` to `*const dyn Trait<B>` as such pointers can cause unsoundness when upcasted or used as an receiver (see #120222 and [#120217 (comment)](https://github.com/rust-lang/rust/issues/120217#issuecomment-1902831511) for examples).
>
> There is only one crater failure due to this (and the crate is not dependent on by anyone) (see `minfac` in the crater report above).
>
> As a side-note: we already prevent casting `*const dyn TraitA` to `*const dyn TraitB`. I believe that it's correct to consider traits with different generic arguments as different.
>
> ## 2. Lifetimes must match
>
> This prevents casting `*const dyn Trait<'a>` to `*const dyn Trait<'b>` as such pointers can cause unsoundness with `arbitrary_self_types` (see [#120217 (comment)](https://github.com/rust-lang/rust/issues/120217#issue-2092855174) for an example).
>
> There is only one crater failure (+2 dependants) (see `rsasl` in the crater report above).
>
> Note that casting `*const dyn Trait + 'a` to `*const dyn Trait + 'b` is still allowed. So far there is no known unsoundness problems with that.
>
> ## 3. Auto traits can't be added
> This prevents casting `*const dyn Trait` to `*const dyn Trait + Send` (where `Send` is not `Trait`'s super trait). This causes unsoundness (calling null as a function, I believe) with arbitrary self types:
>
```rust
#![feature(arbitrary_self_types)]
trait Trait {
fn f(self: *const Self)
where
Self: Send;
}
impl Trait for *const () {
fn f(self: *const Self) {
unreachable!()
}
}
fn main() {
let unsend: *const dyn Trait = &(&() as *const ());
let send_bad: *const (dyn Trait + Send) = unsend as _;
send_bad.f(); // f is not actually in the vtable, since `*const (): Send` bound is not satisfied
}
```
>
```
fish: Job 1, './t' terminated by signal SIGSEGV (Address boundary error)
```
>
> This causes the most breakage (see above crater report).
>
> ## Conclusion
>
> I believe 1 and 2 should be done. They don't seem to cause almost any breakage & generally make sense (if we want the "pointer vtables are correct" and stabilize trait upcasting).
>
> I'm not sure what to do with the 3-rd change though. It causes noticeable breakage. Although most of it is in an unmaintained crate last version of which is unsound anyway, so maybe we can still do this change (after writing a replacement for anymap and sending patches to all affected dependents)?
>
> If we want to prevent immediate breakage for the auto trait change we can try downgrading errors to FCWs in sound cases (i.e. where the trait does not have bounds with the autotrait) and marking making them into errors as a blocker for arbitrary self types. However, implementing this seems _tricky_.
>
> We could also decide not not error in sound cases at all (+optionally issue a normal warning), but that would make "adding a method with an auto-trait bound" into a technically breaking change. (I'm not saying this is a bad way)
TC: What do we think?
NM: The unsoundness seems to hinge on the fact that if you have arbitrary self types...
Waffle: That's an important part of some examples, but there are other ways to trigger unsoundness using generics.
Waffle: Trait upcasting allows upcasting raw pointers, so you don't actually have to call any methods to get something that's incorrect.
NM: We made the decision that in safe Rust, your vtables should always be valid. The changes we need to make impact stable code today so that we can't triggle UB once we have arbitrary self types.
Waffle: Yes. I'm not aware of ways for this to cause UB on stable Rust today.
NM: The invariant about the vtable being valid on stable Rust is important. We should uphold our invariants so we can build on solid foundations without having to do such custom analysis each time.
NM: I'm curious about the breakage and about lcnr's counterproposal.
Waffle: The breakage is very small. There is more breakage on the auto traits part. We could try to limit the breakage by limiting the errors to place where it can actually cause unsoundness. If we make this carve out, then it should fix almost all cases.
NM: When and how would you enforce that?
Waffle: On the scast.
CE: We look at the principle of the `dyn`.
NM: There are a number of ways this could be done.
NM: I'd like to make it unsafe or disallowed to do these as-casts. We should move toward disallowing this via future-incompat while dealing with the `anymap` situation.
NM: `anymap` is unmaintained. I wonder how much we should worry about it. It'd be good if we had an alternative here.
NM: I'd like to do something that puts us in a position the next time that there is unsoundness with `anymap`.
NM: I'll start an FCP here.
*Consensus*: Let's FCP doing items 1 and 2 and do a future incompat warning on item 3.
(The first part of the meeting ended here. The second part, after a break, continue below.)
---
### "Allow `#[deny]` inside `#[forbid]` as a no-op with a warning" rust#121560
**Link:** https://github.com/rust-lang/rust/pull/121560
TC: Nils nominates this for us and describes the problem:
> Forbid cannot be overriden. When someome tries to do this anyways, it results in a hard error. That makes sense.
>
> Except it doesn't, because macros. Macros may reasonably use `#[deny]` (or `#[warn]` for an allow-by-default lint) in their expansion to assert that their expanded code follows the lint. This is doesn't work when the output gets expanded into a `forbid()` context. This is pretty silly, since both the macros and the code agree on the lint!
>
> By making it a warning instead, we remove the problem with the macro, which is now nothing as warnings are suppressed in macro expanded code, while still telling users that something is up.
(Pulling forward unfinished discussion from last week...)
TC: What do we think?
NM: It seems clear to me that this is useful. What's unclear to me is whether we'd ever want to let you override a forbid. I'm thinking about macros here. I could imagine wanting to have an hiegenic opt-out from forbid.
scottmcm: If you don't want this to a hard error, why not change `forbid` to `deny`?
pnkfelix: There can be an unexpected interaction here between parties due to macros.
tmandry: I don't understand why we'd need a warning.
Josh: Proposal: allow `deny` inside `forbid` silently but keep the state `forbid`, continue to hard-error on `warn`/`allow` inside `forbid`.
nikomatsakis: +1.
scottmcm: +1 on the proposal. If we come back later with people who want to e.g. `warn` in a macro, then we can talk about that.
Josh: I propose that we FCP that conclusion.
Josh: I'll start an FCP for that proposal.
*Consensus*: We'll FCP the proposal to allow only `deny` here within `forbid`.
nikomatsakis: !@#!@#!$ labels.
### "regression: let-else syntax restriction (right curly brace not allowed)" rust#121608
**Link:** https://github.com/rust-lang/rust/issues/121608
TC: In #119057:
https://github.com/rust-lang/rust/issues/119057
...we decided to disallow `let-else` expressions from ending in a closing curly brace as that aligned with what was specified in the RFC. We did this on the basis of an extensive analysis by dtolnay and a check across `crates.io` that found no breakage. We FCPed this in:
https://github.com/rust-lang/rust/pull/119062
TC: One day after the analysis by dtolnay, an author in the ecosystem committed a change that now breaks due to our change here. This is the one and only know breakage.
TC: The nominated question is whether we want to reconsider our decision now that this has moved from zero known breakages to one known breakage. What do we think?
CE: I think we should break it. It's an Advent of Code repo.
JT: Agreed. And I sent the author a PR to fix this. The author was having other toolchain problems.
Waffle: +1.
JT: I'll start an FCP.
*Consensus*: We'll do this via FCP.
### "regression: encountered mutable pointer in final value" rust#121610
**Link:** https://github.com/rust-lang/rust/issues/121610
TC: Oli nominates this for us:
> I guess we each hate each other's preferred solution, and neither of us love our own preferred solution. So...
>
> @rust-lang/lang We did an accidental breaking change in #119044
>
> The following example does not compile on beta anymore, but does compile on stable:
>
```rust
use std::cell::Cell;
pub enum JsValue {
Undefined,
Object(Cell<bool>),
}
impl ::std::ops::Drop for JsValue {
fn drop(&mut self) {}
}
const UNDEFINED: &JsValue = &JsValue::Undefined;
```
>
> with
>
```
error: encountered mutable pointer in final value of constant
--> src/main.rs:12:1
|
12 | const UNDEFINED: &JsValue = &JsValue::Undefined;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
```
>
> > what happens here is that we don't do promotion because of the `Drop`, but the "outer scope" rule still applies. The reference is created to `JsValue::Undefined` and const checking concludes that this is fine since while the type has interior mutability, the value doesn't. But when we actually evaluate the initializer for `UNDEFINED` we just see a shared reference created to a type that has interior mutability so we mark it as potentially mutable, and then interning sees that and rejects it.
>
> The reason this worked before was that before #119044 we did a value based (not just type based) interning traversal, so we picked up on the fact that the specific value has no interior mutability.
>
> We have come up with two ways to get back the previous behaviour:
>
> 1. we can make const-eval do a type-driven traversal of the x in &x expressions to check whether there's any UnsafeCell anywhere.
> 2. special case promotion to trigger for these values, even though their type is `Drop` and `!Freeze`
>
> The issues with those are respectively:
>
> 1. that would introduce UB into code that should not have UB (when x is not valid at the given type) and it would be (very) terrible for performance...
> 2. terrible extension to an already fragile part of the compiler: promotion.
>
> So we would like to just keep rejecting this code, as it requires special cases to support instead of falling out of a set of simple rules.
TC: What do we think?
scottmcm/TC: We recently decided to stop doing type-based traversal for const promotion:
https://github.com/rust-lang/rust/pull/119044
scottmcm: I think I was thinking about `match`ing on `const`s where the StructuralEq stuff ended up not being entirely type-based, so that `None` constants worked in ways that `Some(…)` ones didn't.
TC: Proposal: I'm going to ask RalfJ to give us a writeup to help us understand this and how it relates to #119044.
NM: +1. This question seems to make value-based traversal subtle.
scottmcm: Would `const` blocks resolve the promotion problems here? I'm more willing to say this is broken if wrapping this with a `const` block is the fix.
### "`c_unwind` full stabilization request: change in `extern "C"` behavior" rust#115285
**Link:** https://github.com/rust-lang/rust/issues/115285
TC: BatmanAoD proposes for stabilization:
> This is a request for _full_ stabilization of the `c_unwind` feature, [RFC-2945](https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md). The behavior of non-`"Rust"`, non-`unwind` ABIs (such as `extern "C"`) will be modified to close soundness holes caused by permitting stack-unwinding to cross FFI boundaries that do not support unwinding.
>
> When using `panic=unwind`, if a Rust function marked `extern "C"` panics (and that panic is not caught), the runtime will now abort.
>
> Previously, the runtime would simply attempt to unwind the caller's stack, but the behavior when doing so was undefined, because `extern "C"` functions are optimized with the assumption that they cannot unwind (i.e. in `rustc`, they are given the LLVM `nounwind` annotation).
>
> This affects existing programs. If a program relies on a Rust panic "escaping" from `extern "C"`:
>
> * It is currently unsound.
> * Once this feature is stabilized, the program will crash when this occurs, whereas previously it may have appeared to work as expected.
> * Replacing `extern "x"` with `extern "x-unwind"` will produce the intended behavior without the unsoundness.
>
> The behavior of function calls using `extern "C"` is unchanged; thus, it is still undefined behavior to call a C++ function that throws an exception using the `extern "C"` ABI, even when compiling with `panic=unwind`.
TC: We had been waiting for a crater run and analysis on this, and that has now been completed:
https://github.com/rust-lang/rust/pull/116088#issuecomment-1870577466
There were no regressions of substance.
From an implementation perspective, this does seem currently blocked on [#113923](https://github.com/rust-lang/rust/pull/113923), which was [reverted](https://github.com/rust-lang/rust/pull/119885), but that probably doesn't need to block our FCP on the language questions.
TC: What do we think?
TC: Niko expressed +1 but did not check his box. With that box, this would move into FCP.
NM: I've checked my box.
*Consensus*: This is now in FCP.
### "Tracking Issue for `core::mem::variant_count`" rust#73662
**Link:** https://github.com/rust-lang/rust/issues/73662
TC: We discussed this back in 2022, per Josh:
> This seems like it fits in with a broader story of enums, including things like `AsRepr`.
>
> In the absence of those, we're not sure if we want to have this function in its current state.
Josh now renominates this for us:
> Nominating this for lang, because empirically we've stalled out on a potentially useful library addition on the basis of proposed lang features, which themselves seem to have stalled out.
>
> I'd love to see `AsRepr` if someone wants to pick that back up and get it over the finish line. But also, this might be a reasonable interim step, and it doesn't seem like it does any _harm_ to have it even if we add better solutions in the future.
Josh: We had, at the time, some other proposals on the table. So our sentiment was to ask that someone would summarize these and propose how to move forward. The result was for everything to stall out. I'm still very enthusiastic about `AsRepr`. We shouldn't block this on future lang items.
Josh: Proposal: we make it clear that this isn't blocked on any future lang work. If we do that, and resolve the lang blocker, then I'll renominate this for T-libs-api.
TC: In the 2024-02-21 meeting, we decided this probably needs scottmcm present to discuss.
TC: What do we think?
scottmcm: Can we use anything from the RTN conversation here? Like if we use some of our syntax space to add `MyEnum::enum#count` or something? Then by it not being a function it can have different visibility rules in a nice way, avoiding any "but what about non_exhaustive" kinds of problems.
Josh: Even if we introduce some syntax for this in the future, it doesn't feel like having some function to do this is too high a price to pay for doing this now. We could always deprecate the function.
scottmcm: To me, the concerns that have led us to not having the function are SemVer concerns, e.g. with respect to `non_exhaustive`. Having syntax can resolve these problems in ways that are difficult to do with the function.
scottmcm: We've run into this before with e.g. `mem::discriminant`. The argument type is an unconstrained `T`.
Waffle: Why don't we use traits here?
Josh: That is part of the issue at hand. The ideal design for this would be some kind of trait or auto trait. The unbounded generic is standing in for that. The constraint here is probably someone doing the work on this language design.
Waffle: Using a trait here would seem to solve many problems here. It would e.g. solve the SemVer questions because you'd need to opt-in to the trait. The counting of variants could be solved e.g. with a proc macro. I'm struggling to see why we'd need a language feature here.
scottmcm: Since we don't have trait impl visibility, something like a magic associated constant has the possibility of being aware of things like `non_exhaustive`, so we can e.g. let things inside the crate do it but disallow things outside the crate from doing it. If we had private enum variants, you wouldn't be able to know the count unless you had visibility into those variants.
TC: What available outcomes are there?
Josh:
- Option 1: Someone can volunteer to do trait design. (Optionally, auto-supply that trait for some enums.)
- Option 2: We keep the magic function that takes a `T` and has magic criteria for when it works. (Optionally, make it more magic to not accept things like `non_exhaustive`.)
- Option 3 (default): If we do nothing, then we continue to stall out and not provide a solution.
scottmcm: I feel strongly enough about this to make a proposal, perhaps a design meeting proposal.
Waffle: Can this be prototyped as a procedural macro?
Josh: I'll volunteer to help scottmcm with this, particularly in terms of swapping in context for what came up around `AsRepr`.
scottmcm: In terms of a proc macro, `variant_count` is a straightforward proc macro to provide.
*Consensus*: We'll wait for scottmcm's proposal.
### "Implement `PartialOrd` and `Ord` for `Discriminant`" rust#106418
**Link:** https://github.com/rust-lang/rust/pull/106418
TC: This has been on and off our radar. @scottmcm in particular has strong concerns about this that he first raised 5 years ago.
scottmcm:
> I remain strongly opposed to anything that makes it *impossible* for a library author to leave open the door to reorder their enum variants later.
https://github.com/rust-lang/rust/pull/106418#pullrequestreview-1594299402
TC: Recently, T-libs-api decided to move forward on this:
> We discussed this PR in today's T-libs-api meeting. Among the team members in the meeting (myself, Amanieu, Josh, Mara), we were still on board with unconditional Ord and PartialOrd impls; no need for a marker trait. Our approvals for the FCP are registered in [#106418 (comment)](https://github.com/rust-lang/rust/pull/106418#issuecomment-1679322224).
>
> Exposing the discriminant order is the intended behavior. The documentation on `mem::discriminant` mentions that changing the definition of the enum can impact the order of discriminant values, and cites the Reference for detail on how discriminant values are assigned. Amanieu summarized the stability contract as being similar to transmute — the extent to which a caller gets to rely on particular properties across library versions is up to a contract between the caller and library author.
TC: tmandry has filed a concern:
> Is it important that the discriminant order remain the same between different versions of the compiler? If not I'd like to document that it could change, and left a suggestion to that effect.
>
> @rfcbot concern stability wrt compiler version
>
> Otherwise this proposal looks good to me. Thanks for pushing it through.
TC: (In addition to tmandry, this one probably needs scottmcm present to discuss.)
TC: What do we think?
(We discussed a number of possibilities here.)
(The meeting ended here.)
---
### "Consider linting against 00B7 aka interpunct aka middle dot" rust#120797
**Link:** https://github.com/rust-lang/rust/issues/120797
TC: In the meeting on 2024-02-21 we proposed to postpone this.
> ...proposing that we not do this in uncommon_codepoints, and that we consider this again after we have the split-out lint that @Manishearth suggests in point 1 of #120228 (a lint about confusables with operator/punctuation).
TC: If others agree, this FCP can move forward.
### "Tracking issue for function attribute `#[coverage]`" rust#84605
**Link:** 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.
There are two open questions about applying this automatically to nested functions and to inlined functions.
TC: What do we think?
### "`is` operator for pattern-matching and binding" rfcs#3573
**Link:** https://github.com/rust-lang/rfcs/pull/3573
TC: Josh proposes for us that we should accept:
```rust
if an_option is Some(x) && x > 3 {
println!("{x}");
}
```
And:
```rust
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: Last week 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?
### "Should Rust still ignore SIGPIPE by default?" rust#62569
**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.
There was discussion in 2019 about fixing this over an edition, but nothing came of it.
TC: Are we interested in fixing it over this one?
### "Stabilize `#[unix_sigpipe = "sig_dfl"]` on `fn main()`" rust#120832
**Link:** https://github.com/rust-lang/rust/pull/120832
TC: This is related to the above, and is a proposal to stabilize an option to have the startup code set `SIGPIPE` to the *other* handler. However, this does not address the problem that the Rust startup code is making this syscall at all, which means that e.g. `seccomp` filters must be correctly adjusted and it's still impossible to recover the original inherited setting of this handler.
There are also the following options to this attribute that are not proposed for stabilization here:
- `sig_ign`: This is the current default behavior.
- `inherent`: This would prevent the startup code from making this syscall at all.
TC: What do we think?
### "offset: allow zero-byte offset on arbitrary pointers" rust#117329
**Link:** https://github.com/rust-lang/rust/pull/117329
TC: RalfJ nominates this for us:
> Nominating for t-lang discussion. This implements the t-opsem consensus from [rust-lang/opsem-team#10](https://github.com/rust-lang/opsem-team/issues/10), [rust-lang/unsafe-code-guidelines#472](https://github.com/rust-lang/unsafe-code-guidelines/issues/472) to generally allow zero-sized accesses on all pointers. Also see the [tracking issue](https://github.com/rust-lang/rust/issues/117945).
>
> * Zero-sized reads and writes are allowed on all sufficiently aligned pointers, including the null pointer
> * Inbounds-offset-by-zero is allowed on all pointers, including the null pointer
> * `offset_from` on two pointers is always allowed when they have the same address (but see the caveat below)
>
> This means the following function is safe to be called on any pointer:
>
```rust
fn test_ptr(ptr: *mut ()) { unsafe {
// Reads and writes.
let mut val = *ptr;
*ptr = val;
ptr.read();
ptr.write(());
// Memory access intrinsics.
// - memcpy (1st and 2nd argument)
ptr.copy_from_nonoverlapping(&(), 1);
ptr.copy_to_nonoverlapping(&mut val, 1);
// - memmove (1st and 2nd argument)
ptr.copy_from(&(), 1);
ptr.copy_to(&mut val, 1);
// - memset
ptr.write_bytes(0u8, 1);
// Offset.
let _ = ptr.offset(0);
let _ = ptr.offset(1); // this is still 0 bytes
// Distance.
let ptr = ptr.cast::<i32>();
ptr.offset_from(ptr);
} }
```
>
> Some specific concerns warrant closer scrutiny.
>
> ## LLVM 16
>
> We currently still support LLVM 16, which does not yet have the patches that make `getelementptr inbounds` always well-defined for offset 0. The function above thus generates LLVM IR with UB. No known miscompilations arise from that, and my attempt at just removing the `inbounds` annotation on old versions of LLVM failed (I got segfaults, and Nikic [suggested](https://github.com/rust-lang/rust/pull/117329#issuecomment-1783925317) that keeping these attribute around is actually less risky than removing them). If we want to avoid this, we have to wait until support for LLVM 16 can be dropped (which apparently is in May).
>
> ## Null pointers
> t-opsem decided to allow zero-sized reads and writes on null pointers. This is mostly for consistency: we definitely want to allow zero-sized offsets on null pointers (`ptr::null::<T>().offset(0)`), since this is allowed in C++ (and a proposal is being made to allow it in C) and there's no reason for us to have more UB than C++ here. But if we allow this, and therefore consider the null pointer to have a zero-sized region of "inbounds" memory, then it would be inconsistent to not allow reading from / writing to that region.
>
> ## `offset_from`
>
> This operation is somewhat special as it takes two pointers. We do want `test_ptr` above to be defined on all pointers, so `offset_from` between two identical pointers without provenance must be allowed. But we also want to achieve this property called "provenance monotonicity", whereby adding arbitrary provenance to any no-provenance pointer must never make the program UB.[1](#user-content-fn-mono-e335860ede81d9f8aeed856dbd25a8e3) From these two it follows that calling `offset_from` with two pointers with the same address but arbitrary different provenance must be allowed. This does have some [minor downsides](https://github.com/rust-lang/unsafe-code-guidelines/issues/472#issuecomment-1921686682). So my proposal (and this goes beyond what t-opsem agreed on) is to define the `ptr_offset_from` intrinsic to satisfy provenance monotonicity, but to document the user-facing `ptr.offset_from(...)` as requiring either two pointers without provenance or two pointers with provenance for the same allocation -- therefore, making the case of provenance mismatch library UB, but not language UB.
>
> ## Footnotes
>
> 1. This property should hopefully make some intuitive sense, and it is also crucial to justify optimizations that make the program have more provenance than before -- such as optimizing away provenance-stripping operations. Specifically, `*ptr = *ptr` where `ptr: *mut usize` is likely going to be a provenance-stripping operation, and so optimizing away this redundant assignment requires provenance monotonicity. [↩](#user-content-fnref-mono-e335860ede81d9f8aeed856dbd25a8e3)
TC: What do we think?
### "Let's `#[expect]` some lints: Stabilize `lint_reasons` (RFC 2383) " rust#120924
**Link:** https://github.com/rust-lang/rust/pull/120924
TC: Since the last time this was proposed for stabilization, various unresolved questions have now been resolved, so this is being proposed again.
> Hey everyone, with the `#[expect]` implementation done, I'd like to propose stabilizing this feature. I've crated two stabilization PRs, one updating the documentation and one removing the feature from rustc:
>
> * [Let's `#[expect]` some lints: Stabilize `lint_reasons` (RFC 2383) #120924](https://github.com/rust-lang/rust/pull/120924)
> * [Document new `#[expect]` attribute and `reasons` parameter (RFC 2383) reference#1237](https://github.com/rust-lang/reference/pull/1237)
>
> The RFC 2383 adds a `reason` parameter to lint attributes and a new `#[expect()]` attribute to expect lint emissions.
>
> * Here is an example how the reason can be added and how it'll be displayed as
> part of the emitted lint message:
>
```rust
#![feature(lint_reasons)]
fn main() {
#[deny(unused_variables, reason = "unused variables, should be removed")]
let unused = "How much wood would a woodchuck chuck?";
}
error: unused variable: `unused`
--> src/main.rs:5:9
|
5 | let unused = "How much wood would a woodchuck chuck?";
| ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
|
= note: unused variables, should be removed
note: the lint level is defined here
--> src/main.rs:4:12
|
4 | #[deny(unused_variables, reason = "unused variables, should be removed")]
| ^^^^^^^^^^^^^^^^
```
>
> * Here is an example, that fulfills the expectation and compiles successfully:
>
```rust
#![feature(lint_reasons)]
fn main() {
#[expect(unused_variables, reason = "WIP, I'll use this value later")]
let message = "How much wood would a woodchuck chuck?";
#[expect(unused_variables, reason = "is this unused?")]
let answer = "about 700 pounds";
println!("A: {answer}")
}
warning: this lint expectation is unfulfilled
--> src/main.rs:4:14
|
6 | #[expect(unused_variables, reason = "is this unused?")]
| ^^^^^^^^^^^^^^^^
|
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
= note: is this unused?
```
> ## Changes from the RFC
>
> As part of my implementation, I renamed the `#[expect]` lint from `expectation_missing` to `unfulfilled_lint_expectations`. I think the name works better with other lint attributes and is more descriptive.
>
> ## Resolutions of unresolved questions
>
> 1. Where should the `reason` parameter be allowed?
>
> * The current implementation only allows it as the last parameter in all lint attributes
> 2. How should `#[expect(unfulfilled_lint_expectations)]` be handled?
>
> * In the RFC, it was suggested that the `unfulfilled_lint_expectations` can be expected by outer attributes. However, it was also questioned how useful this would actually be. The current implementation doesn't allow users to expect this lint. For `#[expect(unfulfilled_lint_expectations)]` the lint will be emitted as usual, with a note saying that `unfulfilled_lint_expectations` can't be expected.
>
> 3. How should `#[expect(XYZ)]` and `--force-warn XYZ` work?
>
> * This implementation, will emit the lint XYZ, as the lint level has been defined by `--force-warn` and also track the expectation as it usually would with only the `#[expect]` attribute.
>
> ## Updates
>
> Since the initial report, a few questions have been discussed by the lang team, here is a quick overview of the questions and resolutions:
>
> 1. Should the attribute really be called `#[expect]` or is the name too generic?
>
> * `#[expect]` is good ([Decision](https://hackmd.io/@xFrednet/rust-lang-team191#Q1-Name))
> 2. What are the semantics of the `#[expect]` attribute?
>
> * Decision: An expectation should count as fulfilled, if a `#[warn]` attribute at the same location would result in a lint emission ([Decision](https://github.com/rust-lang/rust/issues/115980))
>
> ## Open issues
>
> * `#[expect(lint)]` currently doesn't work on macros. This is in line with other lint attributes. This bug is tracked in [Specifying lint levels does not work on macros #87391](https://github.com/rust-lang/rust/issues/87391) and tested in [`expect_lint_from_macro.rs`](https://github.com/rust-lang/rust/blob/a9bf9eaef5165067414b33777a2c924e42aab5aa/src/test/ui/lint/rfc-2383-lint-reason/expect_lint_from_macro.rs#L26)
TC: What do we think?
### "Lang discussion: Item-level `const {}` blocks, and `const { assert!(...) }`" lang-team#251
**Link:** 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](https://github.com/rust-lang/libs-team/issues/325) (a proposal for a compile-time assert macro), the idea came up to allow `const {}` blocks at item level, and then have people use `const { 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!` vs `const_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 expression `if`-`else`). IMO it would be quite unfortunate for item-level `const` blocks to be evaluated pre-mono if that same `const` 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 using `const _: () = assert!(...);` (which is pre-mono) whenever possible (not capturing generics).
TC: What do we think?
### "add float semantics RFC" rfcs#3514
**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 in `const fn`. (We already allow those operations in `const`/`static` initializers.)
TC: What do we think? tmandry proposed this for FCP merge back in October 2023.
### "align_offset, align_to: no longer allow implementations to spuriously fail to align" rust#121201
**Link:** https://github.com/rust-lang/rust/pull/121201
TC: RalfJ nominates this for us:
> For a long time, we have allowed `align_offset` to fail to compute a properly aligned offset, and `align_to` to return a smaller-than-maximal "middle slice". This was done to cover the implementation of `align_offset` in const-eval and Miri. See #62420 for more background. For about the same amount of time, this has caused confusion and surprise, where people didn't realize they have to write their code to be defensive against `align_offset` failures.
>
> Another way to put this is: the specification is effectively non-deterministic, and non-determinism is hard to test for -- in particular if the implementation everyone uses to test always produces the same reliable result, and nobody expects it to be non-deterministic to begin with.
>
> With #117840, Miri has stopped making use of this liberty in the spec; it now always behaves like rustc. That only leaves const-eval as potential motivation for this behavior. I do not think this is sufficient motivation. Currently, none of the relevant functions are stably const: `align_offset` is unstably const, `align_to` is not const at all. I propose that if we ever want to make these const-stable, we just accept the fact that they can behave differently at compile-time vs at run-time. This is not the end of the world, and it seems to be much less surprising to programmers than unexpected non-determinism. (Related: [rust-lang/rfcs#3352](https://github.com/rust-lang/rfcs/pull/3352).)
>
> @thomcc has repeatedly made it clear that they strongly dislike the non-determinism in align_offset, so I expect they will support this. @oli-obk, what do you think? Also, whom else should we involve? The primary team responsible is clearly libs-api, so I will nominate this for them. However, allowing const-evaluated code to behave different from run-time code is t-lang territory. The thing is, this is not stabilizing anything t-lang-worthy immediately, but it still does make a decision we will be bound to: if we accept this change, then
>
> * either `align_offset`/`align_to` can never be called in const fn,
> * or we allow compile-time behavior to differ from run-time behavior.
>
> So I will nominate for t-lang as well, with the question being: are you okay with accepting either of these outcomes (without committing to which one, just accepting that it has to be one of them)? This closes the door to "have `align_offset` and `align_to` at compile-time and also always have compile-time behavior match run-time behavior".
TC: What do we think?
### "Don't make statement nonterminals match pattern nonterminals" rust#120221
**Link:** https://github.com/rust-lang/rust/pull/120221
TC: CE handed this one to us, since it changes the contract of macro matchers:
> Right now, the heuristic we use to check if a token may begin a pattern nonterminal falls back to `may_be_ident`.
>
> This has the unfortunate side effect that a `stmt` nonterminal eagerly matches against a `pat` nonterminal, leading to a parse error:
>
```rust
macro_rules! m {
($pat:pat) => {};
($stmt:stmt) => {};
}
macro_rules! m2 {
($stmt:stmt) => {
m! { $stmt }
};
}
m2! { let x = 1 }
```
>
> This PR fixes it by more accurately reflecting the set of nonterminals that may begin a pattern nonterminal.
>
> As a side-effect, I modified `Token::can_begin_pattern` to work correctly and used that in `Parser::nonterminal_may_begin_with`.
TC: What do we think?
### "RFC: Allow symbol re-export in cdylib crate from linked staticlib" rfcs#3556
**Link:** https://github.com/rust-lang/rfcs/pull/3556
TC: This seems to be about making the following work:
```rust
// 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:
```rust
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?
### "Lint singleton gaps after exclusive ranges" rust#118879
**Link:** https://github.com/rust-lang/rust/pull/118879
TC: Nadri describes the change:
> In the discussion to stabilize exclusive range patterns (#37854), it has often come up that they're likely to cause off-by-one mistakes. We already have the `overlapping_range_endpoints` lint, so I [proposed](https://github.com/rust-lang/rust/issues/37854#issuecomment-1845580712) a lint to catch the complementary mistake.
>
> This PR adds a new `non_contiguous_range_endpoints` lint that catches likely off-by-one errors with exclusive range patterns. Here's the idea (see the test file for more examples):
>
```rust
match x {
0..10 => ..., // WARN: this range doesn't match `10_u8` because `..` is an exclusive range
11..20 => ..., // this could appear to continue range `0_u8..10_u8`, but `10_u8` isn't matched by either of them
_ => ...,
}
// help: use an inclusive range instead: `0_u8..=10_u8`
```
>
> More precisely: for any exclusive range `lo..hi`, if `hi+1` is matched by another range but `hi` isn't, we suggest writing an inclusive range `lo..=hi` instead. We also catch `lo..T::MAX`.
TC: What do we think?
### "Tracking Issue for unicode and escape codes in literals" rust#116907
**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?
### "Better errors with bad/missing identifiers in MBEs" rust#118939
**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?
### "unsafe attributes" rfcs#3325
**Link:** https://github.com/rust-lang/rfcs/pull/3325
TC: tmandry nominated this one for us so that we could finish the bikeshed that we started in time for Rust 2024.
Lokathor laid out these options:
> The three basic proposals are:
>
> * `#[unsafe attr]` ("unsafe space")
> * `#[unsafe(attr)]` ("unsafe parens")
> * `#[unsafe { attr }]` ("unsafe braces")
>
> During the lang meeting on 2023-06-06, it was requested that a summary of how each option actually _looks_ in practice be made,so that hopefully one of the proposals can be selected based on readability.
>
> When using an attribute, the attribute itself can be one of three basic forms:
>
> * lone token: `#[no_mangle]`
>
> * `#[unsafe no_mangle]`
> * `#[unsafe(no_mangle)]`
> * `#[unsafe { no_mangle }]`
>
> * key-val expression: `#[link_section = ".foo"]`
>
> * `#[unsafe link_section = ".foo"]`
> * `#[unsafe(link_section = ".foo")]`
> * `#[unsafe { link_section = ".foo" }]`
>
> * an attribute "call": `#[link_ordinal(15)]`
>
> * `#[unsafe link_ordinal(15)]`
> * `#[unsafe(link_ordinal(15))]`
> * `#[unsafe { link_ordinal(15) }]`
>
> There is also the issue of readability when mixed with `cfg_attr`.
>
> * Interior, around only the attribute:
>
> * `#[cfg_attr(cond, unsafe no_mangle)]`
> * `#[cfg_attr(cond, unsafe(no_mangle)]`
> * `#[cfg_attr(cond, unsafe { no_mangle } )]`
>
> * Exterior, around the `cfg_attr`:
>
> * `#[unsafe cfg_attr(cond, no_mangle)]`
> * `#[unsafe(cfg_attr(cond, no_mangle))]`
> * `#[unsafe { cfg_attr(cond, no_mangle ) }]`
TC: This is an interesting case because we are not *discharging* unsafety, as with `unsafe { expr }` in a function body. Neither does saying `unsafe` here create and push upward a type-checked *obligation*. Instead, the upward obligation exists regardless and there is no means to signal to the compiler that it has been discharged and no enforcement of that.
TC: Another option I've seen discussed is finding some way to make these annotations safe.
TC: What do we think?
TC: A poll was opened about this question here:
https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Unsafe.20attribute.20syntax
TC: While obviously such voting is not dispositive, it is perhaps at least worth noting that sentiment was strongly in favor of `#[unsafe(no_mangle)]`.
### "Add lint against function pointer comparisons" rust#118833
**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.:
```rust
/// 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:
https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Signature.20of.20.60ptr.3A.3Afn_addr_eq.60
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()` (if `FnPtr` were stabilized), I'd write a comment saying "isn't that what `fn_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 write `a.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` and `ptr::addr_eq`, I'd expect a "`ptr::fn_eq`" to have one generic type and a "`ptr::fn_addr_eq`" to have two. Even if `ptr::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:
https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Function.20pointer.20comparison.20and.20.60PartialEq.60
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?
### "RFC: Syntax for embedding cargo-script manifests" rfcs#3503
**Link:** https://github.com/rust-lang/rfcs/pull/3503
TC: This has been changed to use `---` syntax with an optional infostring (that is arbitrary except for forbidding whitespace and commas).
TC: tmandry, Josh, and I are +1. What do we think?
### "Uplift `clippy::invalid_null_ptr_usage` lint" rust#119220
**Link:** 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 the [`clippy::invalid_utf8_in_unchecked` uplift](https://github.com/rust-lang/rust/pull/111543) 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
>
```rust
// 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?
### "#[cold] on match arms" rust#120193
**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.
### "`.await` does not perform autoref or autoderef" rust#111546
**Link:** https://github.com/rust-lang/rust/issues/111546
TC: This was nominated for T-lang by WG-async. @tmandry said:
> We discussed this in a recent wg-async meeting ([notes](https://hackmd.io/G6ULofyXSIS4CK9u-jwYRg)). The consensus was that we thought the change was well-motivated. At the same time, we want to be cautious about introducing problems (namely backwards compatibility).
>
> There should probably be a crater run of this change, and we should also work through any problematic interactions that could be caused by this change. (@rust-lang/types should probably weigh in.)
>
> The main motivation for the change is the analogy to `.method()`, as well as to wanting async and sync to feel similarly convenient in most cases.
>
> Note that there is another analogy that works against this, the analogy to `IntoIterator`, where the lang-effect form (`for _ in foo {}`) does not do autoref/autoderef. However, given that this _looks_ very different from `foo.await`, and taking a reference with that form is significantly more convenient (`for x in &foo` or `for x in foo.iter()` vs `(&foo).await`), it seemed the analogy was stretched pretty thin. So we elected to put more weight on the above two considerations.
>
> That being said, this change would need lang team signoff. You can consider this comment wg-async's official recommendation to the lang team.
TC: There's now been a crater run done for this. The result was that this breaks a small number of crates, but at least one of those crates has a large number of dependents (`aws-smithy-runtime`). It can be fixed in the dependency in such a way that dependent crates do not have to make changes, but those dependent crates would need to update to a fixed version of the dependency.
(See this [discussion](https://rust-lang.zulipchat.com/#narrow/stream/187312-wg-async/topic/Perform.20autoref.2Fautoderef.20on.20.2Eawait.20-.20.23111773).)
TC: What do we think?
### "Add `wasm_c_abi` `future-incompat` lint" rust#117918
**Link:** https://github.com/rust-lang/rust/pull/117918
TC: daxpedda gives the context:
> This is a warning that will tell users to update to `wasm-bindgen` v0.2.88, which supports spec-compliant C ABI.
>
> The idea is to prepare for a future where Rust will switch to the spec-compliant C ABI by default; so not to break everyone's world, this warning is introduced.
>
> Addresses https://github.com/rust-lang/rust/issues/71871
TC: Is this something we want to do?
### "types team / lang team interaction" rust#116557
**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?
### "Uplift `clippy::precedence` lint" rust#117161
**Link:** https://github.com/rust-lang/rust/pull/117161
TC: The proposal is to lint against:
```rust
-2.pow(2); // Equals -4.
1 << 2 + 3; // Equals 32.
```
These would instead be written:
```rust
-(2.pow(2)); // Equals -4.
1 << (2 + 3); // Equals 32.
```
Prompts for discussion:
- Is this an appropriate lint for `rustc`?
- How do other languages handle precedence here?
- Is minus special enough to treat differently than other unary operators (e.g. `!`, `*`, `&`)?
### "Decision on "must define before use" for opaque types" rust#117866
**Link:** https://github.com/rust-lang/rust/issues/117866
TC: The question is whether to adopt the following "must define before use" rule for opaque types:
> If the body of an item that may define the hidden type of some opaque does define that hidden type, it must do so syntactically *before* using the opaque type in a non-defining way.
This is a breaking change to RPIT. Here's an example of code that works today that would break under this rule:
```rust
use core::convert::identity;
struct I;
struct IShow;
impl I { fn show(&self) -> IShow { IShow } }
struct OnIShow;
trait OnI { fn show(&self) -> OnIShow { OnIShow } }
impl OnI for I {}
fn test(n: bool) -> impl OnI {
let true = n else { loop {} };
let x = test(!n); //~ NOTE this is the opaque type
let _: OnIShow = x.show(); //~ NOTE this is a non-defining use
//~^ ERROR if the body registers a hidden type for the opaque, it
// must do so *before* using it opaquely
let _: IShow = identity::<I>(x).show();
//~^ NOTE this registers a hidden type for the opaque, but does so
// too late
loop {}
}
fn main() {}
```
This rule has relevance to the new trait solver.
TC: What do we think?
### "TAIT decision on whether nested inner items may define" rust#117860
**Link:** https://github.com/rust-lang/rust/issues/117860
TC: The question is whether this should be true:
> Unless and until [RFC PR 3373](https://github.com/rust-lang/rfcs/pull/3373) is accepted and scheduled for stabilization in some future edition, items nested inside of other items may define the hidden type for opaques declared outside of those items without those items having to recursively be allowed to define the hidden type themselves.
The context is that we allow this:
```rust
trait Trait {}
struct S;
const _: () = {
impl Trait for S {} // Allowed.
};
```
Should we accept spiritually-similar TAIT code unless and until we decide to go a different direction with the language?
### "TAIT decision on "may define implies must define"" rust#117861
**Link:** https://github.com/rust-lang/rust/issues/117861
TC: The question is whether this should be true:
> At least until the new trait solver is stabilized, any item that is allowed to define the hidden type of some opaque type *must* define the hidden type of that opaque type.
TC: This is important for the new trait solver.
TC: Here's one reason for that. The new trait solver treats strictly more code as being a defining use. It's also more willing to reveal the hidden type during inference if that hidden type is defined within the same body. This rule helps to avoid inference changes when moving from the old solver to the new solver. Adding this restriction makes TAIT roughly equivalent to RPIT with respect to these challenges.
TC: (This question is entirely orthogonal to how we notate whether an item is allowed to define the hidden type of an opaque.)
### "TAIT decision on "may not define may guide inference"" rust#117865
**Link:** https://github.com/rust-lang/rust/issues/117865
TC: The question is whether this should be true:
> The compiler is allowed to rely on whether or not an item is allowed to define the hidden type of an opaque type to guide inference.
Here's the door that this would close:
> If this rule is adopted, then after TAIT is stabilized, it will not be possible in a fully backward compatible way to later change the rules that determine whether or not an item is allowed to define the hidden type in such a way that an item in existing code that uses an opaque type could switch (without any code changes) from being not allowed to define its hidden type to being allowed to define it.
TC: This is of importance to the new trait solver.
TC: Here's one reason for this. When we're type checking a body and we find an opaque type, we sometimes have to decide, should we infer this in such a way that this body would define the hidden type, or should we treat the type as opaque (other than auto trait leakage) and infer based on that? Depending on that, we can get different answers.
TC: If we did not let inference rely on this, then we would be closing the door on later *allowing* inference to rely on this without provoking changes in inference.
TC: (This question is entirely orthogonal to how we notate whether an item is allowed to define the hidden type of an opaque. Answering this question in the affirmative would update one element of the [#107645 FCP][].)
[#107645 FCP]: https://github.com/rust-lang/rust/issues/107645#issuecomment-1571789814
### "Raw Keywords" rfcs#3098
**Link:** https://github.com/rust-lang/rfcs/pull/3098
### "Tracking issue for RFC 2102, "Unnamed fields of struct and union type"" rust#49804
**Link:** https://github.com/rust-lang/rust/issues/49804
### "Stabilize `extended_varargs_abi_support`" rust#116161
**Link:** https://github.com/rust-lang/rust/pull/116161
### "Fallout from expansion of redundant import checking" rust#121708
**Link:** https://github.com/rust-lang/rust/issues/121708
### "False positives for the new `non_local_definitions` lint" rust#121746
**Link:** https://github.com/rust-lang/rust/issues/121746
### "Elaborate on the invariants for references-to-slices" rust#121965
**Link:** https://github.com/rust-lang/rust/pull/121965
### "Proposal: Remove `i128`/`u128` from the `improper_ctypes` lint" lang-team#255
**Link:** https://github.com/rust-lang/lang-team/issues/255
### "Stabilize associated type position impl Trait (ATPIT)" rust#120700
**Link:** https://github.com/rust-lang/rust/pull/120700
TC: This is presently just waiting on Oli, CE, and myself to finish up some work.
## Action item review
- [Action items list](https://hackmd.io/gstfhtXYTHa3Jv-P_2RK7A)
## Pending lang team project proposals
None.
## PRs on the lang-team repo
### "Add soqb`s design doc to variadics notes" lang-team#236
**Link:** https://github.com/rust-lang/lang-team/pull/236
### "Update auto traits design notes with recent discussion" lang-team#237
**Link:** https://github.com/rust-lang/lang-team/pull/237
## RFCs waiting to be merged
None.
## `S-waiting-on-team`
### "[ptr] Document maximum allocation size" rust#116675
**Link:** https://github.com/rust-lang/rust/pull/116675
### "warn less about non-exhaustive in ffi" rust#116863
**Link:** https://github.com/rust-lang/rust/pull/116863
### "offset: allow zero-byte offset on arbitrary pointers" rust#117329
**Link:** https://github.com/rust-lang/rust/pull/117329
### "Add `wasm_c_abi` `future-incompat` lint" rust#117918
**Link:** https://github.com/rust-lang/rust/pull/117918
### "Lint singleton gaps after exclusive ranges" rust#118879
**Link:** https://github.com/rust-lang/rust/pull/118879
### "Rename `AsyncIterator` back to `Stream`, introduce an AFIT-based `AsyncIterator` trait" rust#119550
**Link:** https://github.com/rust-lang/rust/pull/119550
### "privacy: Stabilize lint `unnameable_types`" rust#120144
**Link:** https://github.com/rust-lang/rust/pull/120144
### "align_offset, align_to: no longer allow implementations to spuriously fail to align" rust#121201
**Link:** https://github.com/rust-lang/rust/pull/121201
## Proposed FCPs
**Check your boxes!**
### "RFC: inherent trait implementation" rfcs#2375
**Link:** https://github.com/rust-lang/rfcs/pull/2375
### "unsafe attributes" rfcs#3325
**Link:** https://github.com/rust-lang/rfcs/pull/3325
### "MaybeDangling" rfcs#3336
**Link:** https://github.com/rust-lang/rfcs/pull/3336
### "Add text for the CFG OS Version RFC" rfcs#3379
**Link:** https://github.com/rust-lang/rfcs/pull/3379
### "RFC: Syntax for embedding cargo-script manifests" rfcs#3503
**Link:** https://github.com/rust-lang/rfcs/pull/3503
### "Reserve `gen` keyword in 2024 edition for `Iterator` generators " rfcs#3513
**Link:** https://github.com/rust-lang/rfcs/pull/3513
### "add float semantics RFC" rfcs#3514
**Link:** https://github.com/rust-lang/rfcs/pull/3514
### "RFC: New range types for Edition 2024" rfcs#3550
**Link:** https://github.com/rust-lang/rfcs/pull/3550
### "Tracking issue for function attribute `#[coverage]`" rust#84605
**Link:** https://github.com/rust-lang/rust/issues/84605
### "Stabilise inline_const" rust#104087
**Link:** https://github.com/rust-lang/rust/pull/104087
### "Implement `PartialOrd` and `Ord` for `Discriminant`" rust#106418
**Link:** https://github.com/rust-lang/rust/pull/106418
### "Stabilize `anonymous_lifetime_in_impl_trait`" rust#107378
**Link:** https://github.com/rust-lang/rust/pull/107378
### "Report monomorphization time errors in dead code, too" rust#112879
**Link:** https://github.com/rust-lang/rust/pull/112879
### "`c_unwind` full stabilization request: change in `extern "C"` behavior" rust#115285
**Link:** https://github.com/rust-lang/rust/issues/115285
### "[ptr] Document maximum allocation size" rust#116675
**Link:** https://github.com/rust-lang/rust/pull/116675
### "Stabilize Wasm target features that are in phase 4 and 5" rust#117457
**Link:** https://github.com/rust-lang/rust/pull/117457
### "Stabilize Wasm relaxed SIMD" rust#117468
**Link:** https://github.com/rust-lang/rust/pull/117468
### "Add `REDUNDANT_LIFETIMES` lint to detect lifetimes which are semantically redundant" rust#118391
**Link:** https://github.com/rust-lang/rust/pull/118391
### "privacy: Stabilize lint `unnameable_types`" rust#120144
**Link:** https://github.com/rust-lang/rust/pull/120144
### "Stabilize associated type position impl Trait (ATPIT)" rust#120700
**Link:** https://github.com/rust-lang/rust/pull/120700
### "Consider linting against 00B7 aka interpunct aka middle dot" rust#120797
**Link:** https://github.com/rust-lang/rust/issues/120797
## Active FCPs
### "RFC: patchable-function-entry" rfcs#3543
**Link:** https://github.com/rust-lang/rfcs/pull/3543
### "Tracking issue for Allow a re-export for `main` (RFC 1260)" rust#28937
**Link:** https://github.com/rust-lang/rust/issues/28937
### "Prevent opaque types being instantiated twice with different regions within the same function" rust#116935
**Link:** https://github.com/rust-lang/rust/pull/116935
### "Add `wasm_c_abi` `future-incompat` lint" rust#117918
**Link:** https://github.com/rust-lang/rust/pull/117918
### "Lint singleton gaps after exclusive ranges" rust#118879
**Link:** https://github.com/rust-lang/rust/pull/118879
### "align_offset, align_to: no longer allow implementations to spuriously fail to align" rust#121201
**Link:** https://github.com/rust-lang/rust/pull/121201
### "`E0492: borrow of an interior mutable value may end up in the final value` during const eval when no inner mutability is involved" rust#121250
**Link:** https://github.com/rust-lang/rust/issues/121250
### "Propagate temporary lifetime extension into if and match." rust#121346
**Link:** https://github.com/rust-lang/rust/pull/121346
## P-critical issues
None.