T-lang meeting agenda

  • Meeting date: 2024-10-16

Attendance

  • People: TC, pnkfelix, scottmcm, nikomatsakis, CE, Urgau, Xiang

Meeting roles

  • Minutes, driver: TC

Scheduled meetings

  • 2024-10-16: "Extended triage 2024-10-16" #293
  • 2024-10-23: "Design meeting: Concern resolution / trait modifiers" #294
  • 2024-10-30: "Rust spec update" #295

Edit the schedule here: https://github.com/orgs/rust-lang/projects/31/views/7.

Announcements or custom items

(Meeting attendees, feel free to add items here!)

Guest attendee items

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.

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.

Design meeting at 12:30 EST / 09:30 PST / 17:30 CET

TC: Remember that we have a design/planning meeting that starts half an hour after this call ends.

Next meeting with RfL

We're next meeting with RfL on 2024-10-23 to review the status of RfL project goals.

https://github.com/rust-lang/rfcs/pull/3614

Rust 2024 review

Project board: https://github.com/orgs/rust-lang/projects/43/views/5

None.

Meta

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 motivating priorities are:

  • Make this edition a success.
  • Do so without requiring heroics from anyone.
    • or stressing anyone or everyone out.

The current timeline is:

Date Version Edition stage
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

All lang priority items are ready for Rust 2024. The remaining not-ready lang items are:

"Tracking Issue for RFC 3593: Reserve unprefixed guarded string literals in Edition 2024" rust#123735

Link: https://github.com/rust-lang/rust/issues/123735

"Tracking Issue for RFC 3606: Drop temporaries in tail expressions before local variables" rust#123739

Link: https://github.com/rust-lang/rust/issues/123739

"Tracking Issue for Rust 2024: Deny references to static mut" rust#123758

Link: https://github.com/rust-lang/rust/issues/123758

"Tracking Issue for Rust 2024: Rescope temporary lifetimes with respect to else" rust#124085

Link: https://github.com/rust-lang/rust/issues/124085

"Tracking issue for Rust 2024: Match ergonomics rules 1C/2C" rust#131414

Link: https://github.com/rust-lang/rust/issues/131414

Nominated RFCs, PRs, and issues

"Decide on name for derive(SmartPtr)" rust#129104

Link: https://github.com/rust-lang/rust/issues/129104

TC: We've decided to go with derive(CoercePointee) for what was previously known as derive(SmartPtr). This is now in FCP. This is just a heads-up for visibility, before we unnominate, as there was some back and forth here.

"Emit error when calling/declaring functions with vectors that require missing target feature" rust#127731

Link: https://github.com/rust-lang/rust/pull/127731

TC: RalfJ nominates for us:

There's only 2 crates.io failures and they are both spurious. And the github failures I checked were also all spurious. So looking pretty good I would say. :)

Seems like the next step process-wise is to check back in with the lang team, now that we have crater results. (That's based on this message.) @rust-lang/lang this aims to fix #116558, which is part of the discussion we had in rust-lang/lang-team#235. The way it is fixed is by making it a hard error to call or declare an extern "C" function that passes a SIMD type by-value without enabling the target feature that enables SIMD vectors of the appropriate size. The reason it is made a hard error is that these functions end up having a different ABI depending on whether that target feature is enabled or not. "Rust" ABI functions are not affected as those functions pass SIMD vectors indirectly (they do that precisely to avoid these ABI issues).

There are two points we'd like your take on:

  • How to stage this. Should it become a hard error immediately, or first be reported as a future-compat lint (I would say we can make it show up in dependencies immediately)? Crater found no regressions (probably because extern "C" functions are generally fairly rare), but of course crater doesn't see all the codebases out there.
  • What exactly should be checked? Right now, the check is extremely low-level and looks at the computed effective ABI of the function, ensuring it doesn't end up with a too large by-value SIMD vector argument. The check is done during monomorphization, each time a function is instantiated, to make sure that we can even know the actual effective ABI. More mono-time checks are unfortunate, but there's no good way to test this in generic code since we can't know whether a generic argument is a SIMD vector or not. Give that it should be rather rare to run into this, hopefully a mono-time check is acceptable.
    The other concern is semver compatibility: if a library changes a public type, e.g., from being an array of i32 to being a SIMD vector instead, that can now break downstream code. However, it can only break downstream code that passes types of this library by-value across an extern "C". If that is an FFI boundary, this is already extremely sketchy to do due to all the concerns around FFI safety and ABI compatibility. The most realistic scenario I could come up with is code using extern "C" for Rust-to-Rust calls; not sure how much we worry about such code I presume it is fairly rare. Still, we could try to mitigate this by making the check some sort of overapproxomation that generally refuses to pass types from other crates across an extern "C" boundary if those types could in the future be changed such that the ABI ends up with a by-value SIMD vector (i.e., (i32, ForeignType) would be okay but TransparentWrapper<ForeignType> would not). I personally am not convinced that is worth the effort.

TC: What do we think?

scottmcm: This makes sense and seems fine. This is like some other things we do.

pnkfelix: Anyone know why we're not doing an FCW here?

scottmcm: It's easier and crater didn't find anything here, probably.

pnkfelix: I'm not sure I like that as a cultural norm.

scottmcm: Maybe we could separate out calling from declaring and treat that separately.

NM: When is this actually UB versus a sharp edge?

scottmcm: It's UB if calling and declaring doesn't agree on the target features.

NM: And it's probably a bug if you're trying to call such a function when the target feature isn't enabled.

NM: Probably I lean toward doing the FCW, maybe for two releases. But it's hard to ensure we follow up on this.

pnkfelix: scottmcm's proposal of doing a hard error if you actually call the thing is appealing to me, since that's clearly a problem.

TC: What about the second part of RalfJ's question, about SemVer?

NM, pnkfelix: Doesn't sound like a problem worth addressing.

pnkfelix: I'll write it up for us.

"Tracking issue for const <*const T>::is_null" rust#74939

Link: https://github.com/rust-lang/rust/issues/74939

TC: There's a stabilization up for <*const T>::is_null. The report is here:

https://github.com/rust-lang/rust/issues/74939#issuecomment-2381628703

The libs-api team wants us to handle the pointer semantics questions here.

TC: What do we think?

scottmcm: There's some appeal to panicking in these cases.

TC: We did open the door to non-deterministic const eval in the float work. Maybe it's at least an option to return a conservative false here. But what are the downsides to that?

NM: Hopefully we could move from panicking to the conservative false. But we should check on that.

scottmcm: We might later want a more explicit API that exposes "maybe null".

TC: Maybe something that returns an enum.

NM: Perhaps we could look at this like casting to usize and trying to shift it. That would panic too presumably.

TC: Let's propose dual lang/libs-api FCP here.

scottmcm: I'll write it up.

"Lint against &T to &mut T and &T to &UnsafeCell<T> transmutes" rust#128351

Link: https://github.com/rust-lang/rust/pull/128351

TC: CE nominates for us a proposal by ChayimFriedman2:

Conversion from & to &mut are and always were immediate UB, and we already lint against them, but until now the lint did not catch the case were the reference was in a field.

Conversion from & to &UnsafeCell is more nuanced: Stacked Borrows makes it immediate UB, but in Tree Borrows it is sound.

However, even in Tree Borrows it is UB to write into that reference (if the original value was Freeze). In all cases crater found where the lint triggered, the reference was written into.

More details here:

https://github.com/rust-lang/rust/pull/128351#issue-2435783651

TC: What do we think?

CE: I nominated it as the new lint needs lang approval.

pnkfelix: There are two things here, there's a lint expansion and a new thing. Overall, this seems OK to me.

NM, scottmcm, TC: Ship it.

NM: I'll write up the FCP.

TC: And it's now in FCP.

"optimize attribute applied to things other than methods/functions/c…" rust#128943

Link: https://github.com/rust-lang/rust/pull/128943

TC: jieyouxu nominates for us:

This needs a T-lang FCP since it diverges from the original RFC 2412 specified behavior. cc @rust-lang/lang

Summary for T-lang

This PR proposes to elevate #[optimize] attribute (as specified in RFC 2412) applied to unsupported HIR nodes from a warn-by-default unused_attributes lint to a hard error.

More details are here:

https://github.com/rust-lang/rust/pull/128943#issuecomment-2282357407

TC: What do we think?

(Discussion to the effect that we'd prefer to hard error conservatively here, even though this is just an optimization and so doesn't affect the language in a specification sense.)

TC: This is still unstable, right?

CE: Actually, yes. OK, then we don't need to crater run this.

(The first part of the meeting ended here.)


(The second part of the meeting started here.)

People: TC, pnkfelix, scottmcm, nikomatsakis, CE, Urgau

"Lint against getting pointers from immediately dropped temporaries" rust#128985

Link: https://github.com/rust-lang/rust/pull/128985

TC: This is a new proposed lint to catch certain kinds of UB. There are known false positives, of course, like this one:

https://github.com/rust-lang/rust/pull/128985#issuecomment-2355705422

TC: What do we think?

CE: Assuming the implementation is fine, I think the idea is good.

pnkfelix: Let's ship it.

TC: It's now in FCP.

"#[inline(required)]" rfcs#3711

Link: https://github.com/rust-lang/rfcs/pull/3711

TC: davidtwco proposes:

rustc supports inlining functions with the #[inline]/#[inline(always)]/#[inline(never)] attributes, but these are only hints to the compiler.

Sometimes it is desirable to require inlining, not just suggest inlining: security APIs can depend on being inlined for their security properties, and performance intrinsics can work poorly if not inlined.

Add a forever-unstable #[inline(required)] and #[inline(must)] which will always inline regardless of cost heuristics and will emit a deny/warn lint if inlining was not possible.

TC: It's been raised in the thread that it might be a bit odd to commit to these being forever-unstable if part of the purpose here is enabling better security APIs.

TC: Overall, what do we think?

CE: Maybe it'd be better to let the RFC thread play out further.

scottmcm: It's funky too, since in a spec sense, all of these do nothing.

"RFC: No (opsem) Magic Boxes" rfcs#3712

Link: https://github.com/rust-lang/rfcs/pull/3712

TC: Connor proposes:

Currently, the operational semantics of the type alloc::boxed::Box<T> is in dispute, but the compiler adds llvm noalias to it. To support it, the current operational semantics models have the type use a special form of the Unique (Stacked Borrows) or Active (Tree Borrows) tag, which has aliasing implications, validity implications, and also presents some unique complications in the model and in improvements to the type (e.g. Custom Allocators). We propose that, for the purposes of the runtime semantics of Rust, Box is treated as no more special than a user-defined smart pointer you can write today1. In particular, it is given similar behaviour on a typed copy to a raw pointer.

and scottmcm nominates:

I, at least, fully expect us to eventually have some way of writing alignment-obeying raw pointers in Rust in some way. If nothing else, slice::Iter is less good than it could be because of the lack of them, and optimizing that type is super-important.

(Transmuting between NonNull<T> and unsafe<'a> &'a T is one thing that might work, for example, though it's also possible that the opsem for that will end up saying that it doesn't and that something else is required instead.)

TC: What do we think?

scottmcm: I'm a big fan of this. People going from Vec to Boxed slices and getting different unsafe behavior is surprising.

CE: Maybe we want opsem to check off on this first.

TC: It seems that we all want to make Box less magic, but clearly there's a reason we haven't yet done this to date. How do we feel about the details here?

NM: I'm a bit unclear on what is being proposed. Are they saying "stop optimize box" or "we should make it possible that other people can define types like box".

scottmcm: From a compiler perspective, the detail here is "take the #[noalias] off of Box when it's passed as a function parameter."

scottmcm: To TC's question, I think it's been a matter of analysis paralysis about losing that optimization.

NM: Vec and Box are inconsistent, and it seems we should reconcile them. There's a question of whether these are end-user abstractions versus how much these are building blocks for unsafe code.

NM: I think that I wish Vec were a real abstraction rather than a building block, and that we had something else for the building block. But the ship has probably sailed on that. So it seems we should probably make Box more like Vec.

TC: Since this would change the code the compiler generates, it seems that we should see benchmark results here.

NM: These seem like the right questions. I haven't read the doc in question but I would like them to address it from the perspective of trading off "Box and Vec as building blocks for unsafe" vs "Box and Vec as end-user abstractions". It seems to me that Vec is more of an end-user abstraction than Box is, but we treat Vec (presently) like an unsafe building block and Box like an abtraction, and it's not clear that we can reverse that first point anymore so we should probably embrace the "building blocks for unsafe" direction. String is kind of the same, hence our challenge in doing the "pointer to static data".

pnkfelix: Unfortunately the benchmarking we do is compiler-focused and probably wouldn't yield relevant data here.

TC: We could think about other ways we could give this control back.

pnkfelix: Is there any world in which we add a different version of Vec and Box?

NM: I think that will happen.

scottmcm: E.g., if we had a type that was like a raw pointer, but is aligned, that's what Box would use. Or a similar thing with noalias would make sense.

NM: I think the precedent is toward Vec and String being "naive but useful data structures" vs "highly optimized end-user abstractions". We may just want to run with that. I'll leave a comment.

"edition lint: migrating extern crate with #[macro_use]" rust#52043

Link: https://github.com/rust-lang/rust/issues/52043

TC: Code like this today isn't idiomatic, since we would use use to import any macros, but it doesn't lint:

#[macro_use]
extern crate rayon;

fn main() { }

TC: Josh nominates as it seems perhaps beyond time that we do so. What do we think?

NM: There is a lint:

#![warn(macro_use_extern_crate)]

#[macro_use]
extern crate futures;

fn main() {
    async {
        join!();    
    };
}

You have to actually use the macro for it to fire.

TC: OK, it sounds like we want this; we can communicate that, and then we can FCP the change to the lint level when there's a PR for it.

"Consider deprecation of UB-happy static mut" rust#53639

Link: https://github.com/rust-lang/rust/issues/53639

TC: Long ago, eddyb opened an issue to consider deprecating static mut. This is because handling long-lived references to static mut items is hard to do right.

We decided for Rust 2024 to lint at deny-by-default against long-lived references to static mut items, thus apparently solving the problem that motivated opening the issue. And there seem to be use cases for static mut. As RalfJ says:

Sometimes, you need global mutable state. We already had several cases of people being quite confused and concerned by the lints we started emitting, and it turns out that what they were doing is completely fine and we basically told them to add a bit of noise to their code to silence the lint. Those people will be even more confused if we now tell them that static mut will be banned entirely, and I am not convinced that replacing addr_of_mut!(STATIC) with STATIC.get() is really doing anything for ensuring the safety of global mutable state.

Many people that use static mut now are entirely aware of what they are doing, they didn't accidentally stumble into global mutable state. People that just mindlessly run into static mut will equally mindlessly start using SyncUnsafeCell (probably by copying some online resource telling them how to silence that annoying borrow checker, or by following helpful compiler hints).

So overall I am not convinced that the churn caused on existing code, and the overhead caused for people that know what they are doing, is balanced by a sufficient risk reduction for people that don't know what they are doing.

Given all this, it's hard to me to imagine that we've soon depracet static mut, so I propose FCP close.

TC: What do we think?

NM: +1 to what Ralf says.

"Tracking Issue for the C-cmse-nonsecure-call ABI" rust#81391

Link: https://github.com/rust-lang/rust/issues/81391

TC: T-compiler nominates for us:

Nominating for both T-lang and T-compiler discussion: there is a request for the stabilization of the C-cmse-nonsecure-call ABI (posted above at #81391 (comment)), there's also the seemingly related #[cmse_nonsecure_entry] attribute (#75835). This is mostly nominated for several reasons stated below.

For T-lang:

  • Procedure questions:

    • Does this need T-lang sign-off, like a T-lang FCP or a joint T-lang/T-compiler FCP?

For both T-compiler and T-lang:

  • Is the cmse-related efforts being tracked anywhere?

TC: What do we think?

CE: We only landed support for this earlier this year, and there are outstanding bugs. I wonder if this is too soon to stabilize. Presumably, a sufficiently-thorough stabilization report would address those.

CE: From a types team perspective, I'd like to see discussion of the validation here.

NM: Probably we want an RFC here.

scottmcm: Yes, this seems like much more than an ABI.

NM: I've left a comment.

"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. They've now done so.

TC: In 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 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

TC: What do we think about these, and would we lint on derived PartialEq cases like these or no?

NM: My sense is that linting for cases like RawWakerVtable will result in a lot of false positives. I think most of the time people are comparing those kinds of things for equality they will not have an issue due to the fns, you'd have to have the userdata being equal; and I think often when people compare aggregrate structurues for equality those structures were not created in distinct modules but rather from a common function, which will work reasonably reliably (though of course can go wrongespecially with monomorphization).

The three scenarios:

  • two concrete function pointers
  • deriving on a struct that contains function pointers
  • using a type that is PartialEq and which has a derived struct from function pointers

NM: I am in favor of number 1 but not 2 or 3 at least not now.

Consensus:

  • Add lint, with suggestion to use the new addr_eq fn, but not machine applicable

"Tracking Issue for enum access in offset_of" rust#120141

Link: https://github.com/rust-lang/rust/issues/120141

TC: There's a proposed FCP merge for us:

https://github.com/rust-lang/rust/issues/120141#issuecomment-2161507356

TC: What do we think?

scottmcm: This has a Josh concern, probbaly we should wait for him.

"Support for pointers with asm_const" rust#128464

Link: https://github.com/rust-lang/rust/issues/128464

TC: Josh nominates for us the question:

Nominating this for lang to discuss the question of whether we should support use of const in asm! for things that can't just be textually substituted, or whether we should give that a different name.

@Amanieu, any input you'd like to provide would be helpful.

To which Amanieu replies:

After thinking about it a bit, I think it's probably fine to add this functionality to const. I'm a bit bothered about the duplication with sym, which is already stable.

TC: What do we think?

NM: Ralf has a comment there that makes sense. There's a difference between pasting in a constant value and pasting in a string. If we wanted the latter, we should call it something else. It feels different.

TC: Sounds like this is asking for positive vibes so that someone can go and implement this.

NM: I'll write it up.

"#[inline(never)] does not work for async functions" rust#129347

Link: https://github.com/rust-lang/rust/issues/129347

TC: When a user writes:

#[inline(never)]
pub async fn foo() -> u8 {}

there's a lang semantics question here, which is apparently open, about whether that attribute applies to the function that produces the future or to the poll function of the future, or both.

TC: WG-async discussed this and it seemed that it should apply to both, and that people could desugar if they needed better control than that.

TC: What do we think?

scottmcm: It feels odd for the funciton that creates the future to be inline(never), because that's nearly always what you'd want.

TC: How do you feel about inline(always)? Does it get turned around?

scottmcm: My instinct is that the attribute should be applied to the poll function, and that the function that returns the object should always be inlined.

pnkfelix: +1.

NM: It seems obvious that users intended for this to be on the poll function. There's interesting overlap with the "flavors" concept. Thinking about this, #[inline(..)] should be applicable to an async block, closures, async closures, etc. It should go where the code is rather than on the shim function.

scottmcm: #[optimize(..)] should go there too.

TC: +1 to the above. I've proposed FCP merge.

(The meeting ended here.)


"Remove unstable cfg target(...) compact feature" rust#130780

Link: https://github.com/rust-lang/rust/pull/130780

TC: Urgau suggests that we remove the cfg_target_compact unstable feature. Its tracking issue is:

https://github.com/rust-lang/rust/issues/96901

TC: What do we think?

"Strengthen the follow-set rule for macros" rust#131025

Link: https://github.com/rust-lang/rust/issues/131025

TC: Over in:

@compiler-errors describes this general problem:

The breakage specifically represents an inherent limitation to the "macro follow-set" formulation which is supposed to make us more resilient against breakages due to extensions to the grammar like this.

Given two macro matcher arms:

  • ($ty:ty) => ...
  • (($tt:tt)*) => ...

And given tokens like:

  • & pin mut [more tokens may follow]

On nightly today, &pin gets parsed as a type. However, we run out of matchers but still have tokens left (the mut token is next), so we fall through to the next arm. Since it's written like ($tt:tt)*, everything is allowed, and we match the second arm successfully

I think that's weird, because if this second arm were written like $ty:ty mut, that would be illegal, since mut is not in the follow-set of the :ty matcher. Thus, we can use :tt matchers to observe whether the compiler actually parses things not in our grammar that should otherwise be protected against, which seems pretty gross.

And @Noratrieb proposes a general solution:

I believe a solution to this would be the following new logic:

  • after the end of a macro matcher arm has been reached
  • and there are still input tokens remaining
  • and if the last part of the matcher is a metavar
  • ensure that the first remaining token is in the follow set of this metavar
  • if it is, move on to the next arm
  • if it is not, emit an error

What this semantically does is strengthen the "commit to fully matching metavars or error" behavior such that it extends past the end. I don't know how many macros rely on this, but it seems like emitting an FCW (instead of error) on such macro invocations would find all these cases and ensure that the follow-set logic is actually robust past the end. But imo this shouldn't block this PR (which should probably just ship as-is) and can be done separately.

About this, NM noted:

I don't think this proposal is sufficient but I am interested in pursuing a real fix to this for a future edition.

Example:

macro_rules! test {
    (if $x:ty { }) => {};
    (if $x:expr { }) => {};
}

This basically says to pick one arm if something is a type, another if it's an expression. Extending the type grammar to cover new cases could change which arm you go down to.

I think the most general fix is to say: when you would start parsing a fragment, first skip ahead to find the extent of it (i.e., until you see an entry from the follow-set). Then parse it as the fragment. If the parsing fails or there are unconsumed tokens, report a hard error.

I suspect it would break a lot in practice and we would need an opt-in.

TC: What do we think?

"Decide on name for Freeze" rust#131401

Link: https://github.com/rust-lang/rust/issues/131401

TC: We still need to pick a name for Freeze (which may still be Freeze) so that we can proceed with:

Having heard no options particularly more appealing options than Freeze, I propose we go with that as the author of that RFC has suggested.

TC: What do we think?

"Stabilize count, ignore, index, and length (macro_metavar_expr)" rust#122808

Link: 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 of count, ignore, index and length.

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:

https://rust-lang.zulipchat.com/#narrow/stream/404510-wg-macros/topic/Partial.20macro_metavar_expr.20stabilization

TC: Josh proposed FCP merge on this stabilization.

"Effective breakage to jiff due to ambiguous_negative_literals" rust#128287

Link: https://github.com/rust-lang/rust/issues/128287

TC: We have an allow-by-default lint against ambiguous_negative_literals like:

assert_eq!(-1.abs(), -1);

It's allow-by-default because we found use cases such as jiff (by BurntSushi) that have, in their API, operations whose result is invariant to the order of the negation and that rely on this syntax for the intended ergonomics.

Urgau has a proposal for us. He'd like to lint by default, and have an

#[diagnostic::irrelevant_negative_literal_precedence]

attribute (of some name), using the diagnostic namespace, that could be applied to function definitions and that would suppress this lint on their callers. Urgau would prefer this be opt-in rather than opt-out so as to bring awareness to this, even though many functions don't affect the sign bit and so will have this invariance.

I've asked BurntSushi for his views on this proposal with respect to jiff, to confirm this would address his use case.

TC: What do we think?

"Supertrait item shadowing v2" rfcs#3624

Link: https://github.com/rust-lang/rfcs/pull/3624

TC: This RFC is in FCP. One of the main motivations for this RFC is so that libs-api can stabilize methods whose names match those used by itertools. Since the FCP started, one of the maintainers of itertools chimed in to say:

tmandry said:

We'll be creating a slightly bad experience for users of itertools with the lint, and that will only be resolved by the crate releasing a new semver-incompatible version or a new trait (or perhaps doing rustc version hacks, if the signatures are compatible).

This is going to create a slightly bad experience for the maintainers of itertools, too. We will get issues filed by users who would like us to remove now-shadowing methods for their toolchain because of the lint. (If we're very unlucky, those users will have also discovered that the rationale for the lint is to avoid supply chain attacks.) We won't be able to readily remove these methods, because that conflicts with our longstanding policy of maintaining a conservative MSRV. The only way we'll be able to reconcile these interests is by using build.rs-rustc-version-detection hacks, something we've intentionally avoided because build.rs is a vector for supply chain attacks.

Please consider making this lint allow-by-default.

I nominated so we could consider that feedback. We could of course handle the setting of the lint level during stabilization, but it seems worth discussing this feedback while it's fresh.

TC: What do we think?

"Trait method impl restrictions" rfcs#3678

Link: https://github.com/rust-lang/rfcs/pull/3678

TC: This RFC just went into FCP. I'd like to check my box, as I want something like this, but there are some things I'd like to talk though.

This RFC is about restricting where trait methods can be implemented, e.g. preventing any but default impls.

There's an existing accepted RFC 3323 for restricting where traits can be implemented, e.g.:

pub impl(crate) trait Tr {
    fn method(&self) { .. }
}

and where fields can be mutated

pub struct S {
    pub mut(crate) inner: u8,
}

so the original draft of the RFC extended this "restrictions" RFC to support where methods can be implemented, e.g.:

pub trait Tr {
    impl(crate) fn method1(&self) { .. }
    impl(trait) fn method2(&self) { .. }
}

(RFC 3323 itself left the exact syntax as an open question, and this RFC would have inherited that by building on RFC 3323.)

Later drafts updated this to use the final keyword:

pub trait Tr {
    final fn method(&self) { .. }
}

Things to talk through:

Keyword vs attribute

TC: In the issue, we've received feedback that an attribute would feel more consistent to some, e.g.:

pub trait Tr {
    #[final]
    fn method(&self) { .. }
}

The argument is that it feels closer to something like #[non_exhaustive] than to async, const, or pub.

I wonder how much having the keyword reserved should change our thinking here. If we didn't, it feels likely we wouldn't have thought twice about this being an attribute.

Is final too OO, and is the analogy correct?

TC: Probably also admittedly very subjectively the final keyword to me feels a bit too "OO" for Rust. A trait isn't a base class, but that's kind of what my brain sees with final there.

Less subjectively, given its meaning for inheritance, it suggests another plausible meaning in Rust. Traits can "extend" other traits, i.e. be subtraits ("typeclass inheritance"?). So, arguable, especially in the context of supertrait item shadowing

https://github.com/rust-lang/rfcs/pull/3624

where we're preferring subtrait methods of the same name, one might expect final to be a designation on the supertrait that indicates that a subtrait cannot "override" the method. This is actually a more intuitive meaning, given what final means in OO systems, than meaning some restriction about how an "interface" (to use the OO term) can be implemented.

Are there no use cases for overriding within the crate?

TC: I wonder, given how a crate providing traits often provides various blanket impls, are there really no use cases for a restriction that allows for overriding the method within the crate but not otherwise? If there are, it seems a bit strange to me to break parity with RFC 3323.

(If we don't like the syntax of RFC 3323, we can still change that.)

Alternate syntax proposal

TC: In the RFC thread, there's recently been a proposal by PoignardAzur for:

trait MyTrait<T> {
    fn output(&self) -> T;
}

impl<T: Display> MyTrait<T> {
    fn method(&self) {
        println!("{}", self.output());
    }
}

This syntax would basically be an inherent impl block, for traits. It would have the same properties as final in this RFC.

TC: If this makes sense semantically, this does syntactically feel more Rust-like to me.

Guaranteed devirtualization?

TC: I had assumed that final (in whatever form) would guarantee devirtualization so that it could be used for cases like the next method for AsyncGen, but now I see discussion that we may never want to do that (for reasonable reasons) and such methods should continue to live on separate traits with blanket impls. This seems a major class of use cases we'd be cutting out. I wonder if we want a way for users to control this.

Cutting this out also causes me to reconsider the distribution of use cases. Guaranteed devirtualization is a good reason for restricting impls to the trait and not to the rest of the crate. Without this, I start to imagine again reasons why one might want such crate-local but not trait-local impls.

"Simplify lightweight clones, including into closures and async blocks" rfcs#3680

Link: https://github.com/rust-lang/rfcs/pull/3680

TC: Josh nominates a new RFC for us. What do we think?

"[RFC] Default field values" rfcs#3681

Link: https://github.com/rust-lang/rfcs/pull/3681

TC: This RFC adds a way to set field defaults, e.g.:

struct Point {
    x: u8 = 0,
    y: u8 = 0,
}

let p = Point { .. };

But, unfortunately, the interaction with Default here is a bit weird. If we write:

struct Point {
    x: u8,
    y: u8,
    // We just want to override the default `None` on this field,
    // but we can leave the others alone because `Default::default`
    // for those is fine, right?
    z: Option<u8> = Some(0),
}

let p = Point { .. }; //~ ERROR
let p = Point::default(); //~ OK!

In general, under this RFC, Point { .. } and Point::default() can each work when the other can fail and can have arbitrarily different behaviors. So it's in that context that I nominate, suggestion a nightly experiment, and propose a design meeting.

https://github.com/rust-lang/lang-team/issues/291

TC: What do we think?

"Declarative macro_rules! attribute macros" rfcs#3697

Link: https://github.com/rust-lang/rfcs/pull/3697

TC: Josh proposes an RFC for us:

Many crates provide attribute macros. Today, this requires defining proc macros, in a separate crate, typically with several additional dependencies adding substantial compilation time, and typically guarded by a feature that users need to remember to enable.

However, many common cases of attribute macros don't require any more power than an ordinary macro_rules! macro. Supporting these common cases would allow many crates to avoid defining proc macros, reduce dependencies and compilation time, and provide these macros unconditionally without requiring the user to enable a feature.

E.g.:

macro_rules! main {
    attr() ($func:item) => { make_async_main!($func) };
    attr(threads = $threads:literal) ($func:item) => { make_async_main!($threads, $func) };
}

#[main]
async fn main() { ... }

#[main(threads = 42)]
async fn main() { ... }

TC: What do we think?

"Declarative macro_rules! derive macros" rfcs#3698

Link: https://github.com/rust-lang/rfcs/pull/3698

TC: Josh proposes an RFC for us:

Many crates support deriving their traits with derive(Trait). Today, this requires defining proc macros, in a separate crate, typically with several additional dependencies adding substantial compilation time, and typically guarded by a feature that users need to remember to enable.

However, many common cases of derives don't require any more power than an ordinary macro_rules! macro. Supporting these common cases would allow many crates to avoid defining proc macros, reduce dependencies and compilation time, and provide these macros unconditionally without requiring the user to enable a feature.

E.g.:

trait Answer { fn answer(&self) -> u32; }

#[macro_derive]
macro_rules! Answer {
    // Simplified for this example
    (struct $n:ident $_:tt) => {
        impl Answer for $n {
            fn answer(&self) -> u32 { 42 }
        }
    };
}

#[derive(Answer)]
struct Struct;

fn main() {
    let s = Struct;
    assert_eq!(42, s.answer());
}

TC: What do we think?

"Elided lifetime changes in rust_2018_idioms lint is very noisy and results in dramatically degraded APIs for Bevy" rust#131725

Link: https://github.com/rust-lang/rust/issues/131725

TC: Long ago, we set a direction of wanting to move away from eliding lifetimes in paths, e.g.:

#![deny(elided_lifetimes_in_paths)]

struct S<'a>(&'a ());

fn f(x: &()) -> S {
    //          ~
    //~^ ERROR expected lifetime parameter
    S(x)
}

However, that lint is currently allow-by-default. It was part of the rust_2018_idioms lint group (which is also allow-by-default).

We talked about changing this in Rust 2024, but it seems we didn't get around to it.

One of the maintainers of Bevy has now written in to ask us to never change this.

I'd probably highlight:

TC: What do we think?

"Add support for use Trait::func" rfcs#3591

Link: https://github.com/rust-lang/rfcs/pull/3591

This RFC would add support for:

use Default::default;

struct S {
    a: HashMap<i32, i32>,
}

impl S {
    fn new() -> S {
        S {
            a: default()
        }
    }
}

Josh has proposed FCP merge and has nominated. There are outstanding concerns about the handling of turbofish and associated constants.

TC: What do we think?

"Tracking issue for the start feature" rust#29633

Link: 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 use fn main(). the compiler, together with std, will then ensure that code ends up at main (by having a platform-specific entrypoint that gets directed through lang_start in std to main - 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], like main, _start, WinMain or my_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 by std, 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?

"Coercing &mut to *const should not create a shared reference" rust#56604

Link: https://github.com/rust-lang/rust/issues/56604

TC: It's currently UB to write:

fn main() {
    let x = &mut 0;
    let y: *const i32 = x;
    unsafe { *(y as *mut i32) = 1; }
    assert_eq!(*x, 1);
}

This is due to the fact that we implicitly first create a shared reference when coercing a &mut to a *const. See:

TC: What do we think about this?

"Stabilize anonymous_lifetime_in_impl_trait" rust#107378

Link: 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.

"#[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.

"Emit a warning if a match is too complex" rust#122685

Link: 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 allowable. 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 a match into smaller matches 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?

"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?

"Proposal: Remove i128/u128 from the improper_ctypes lint" lang-team#255

Link: 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#3573

Link: 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?

"Unsafe fields" rfcs#3458

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?

"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:

// 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?

"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?

"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 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?

"Uplift clippy::double_neg lint as double_negations" rust#126604

Link: 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?

"Language vs. implementation threat models and implications for TypeId collision resistance" rust#129030

Link: https://github.com/rust-lang/rust/issues/129030

TC: We use SipHash-1-3-128 in Rust for hashing types to form TypeIds. If these TypeIds collide in a single program, UB may result.

If SipHash-1-3-128 is a secure PRF, then the probability of such collisions happening accidentally in a program that contains an enormous 1M types is one in 2^-89.

But, if someone wanted to brute-force a collision that is, find two entirely random types that would have the same TypeId the work factor for that is no more than about 2^64 on average.

The question being nominated for lang is whether we consider that good enough for soundness, for now.

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 (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?

"RFC: inherent trait implementation" rfcs#2375

Link: https://github.com/rust-lang/rfcs/pull/2375

TC: We had a design meeting on 2023-09-12 about inherent trait impls. In that meeting, I proposed a use syntax for this:

In the discussion above, we had left two major items unresolved.

  • How do we make blanket trait impls inherent?
  • How can we allow only some items from the trait impl to be made inherent?
    • This is especially tricky for associated functions and methods with a default implementation.

(Part of the motivation for wanting to allow only some items to be made inherent is to prevent or to fix breakage caused when a trait later adds a new method with a default implementation whose name conflicts with the name of an existing inherent method.)

Coming up with a syntax for these that combines well with the #[inherent] attribute could be challenging.

One alternative that would make solving these problems straightforward is to add some syntax to the inherent impl block for the type. Given the desugaring in the RFC, there is some conceptual appeal here. (quaternic proposed this arrangement; TC is proposing the concrete syntax.)

We can use use syntax to make this concise and intuitive.

Here's an example:

trait Trait1<Tag, T> {
    fn method0(&self) -> u8 { 0 }
    fn method1(&self) -> u8 { 1 }
}
trait Trait2<Tag, T> {
    fn method2(&self) -> u8 { 2 }
    fn method3(&self) -> u8 { 3 }
    fn method4(&self) -> u8 { 4 }
}

struct Tag;

struct Foo<T>(T);
impl<T> Foo<T> {
    // All methods and associated items of Trait1 become inherent,
    // except for `method0`.  The inherent items are only visible
    // within this crate.
    pub(crate) use Trait1<Tag, T>::*;
    // Only `method2` and `method3` on Trait2 become inherent.
    pub use Trait2<Tag, T>::{method2, method3};

    fn method0(&self) -> u64 { u64::MAX }
}

impl<T> Trait1<Tag, T> for Foo<T> {}
impl<U: Trait1<Tag, T>, T> Trait2<Tag, T> for U {}

This solves another problem that we discussed above. How do we prevent breakage in downstream crates when a trait later adds a new method with a default implementation? Since a downstream crate might have made an impl of this trait for some local type inherent and might have an inherent method with a conflicting name, this could be breaking.

We already handle this correctly for use declarations with wildcards. Any locally-defined items override an item that would otherwise be brought into scope with a wildcard import. We can reuse that same behavior and intuition here. When a wildcard is used to make all items in the trait inherent, any locally-defined inherent items in the impl prevent those items from the trait with the same name from being made inherent.

Advantages:

  • It provides a syntax for adopting as inherent a blanket implementation of a trait for the type.
  • It provides a syntax for specifying which methods should become inherent, including methods with default implementations.
  • The wildcard import (use Trait::*) makes it very intuitive what exactly is happening and what exactly your API is promising.
  • The use syntax makes it natural for a locally-defined item to override an item from the wildcard import because that's exactly how other use declarations work.
  • rust-analyzer would probably support expanding a wildcard use Trait::* to an explicit use Trait::{ .. } just as it does for other use declarations, which would help people to avoid breakage.
  • We can support any visibility (e.g. use, pub use, pub(crate) use, etc.) for the items made inherent.

Disadvantages:

  • There's some redundancy, especially when the items to make inherent are specifically named.

During the meeting, this emerged as the presumptive favorite, and we took on a TODO item to updated the RFC.

After follow-on discussion in Zulip, Niko agreed, and also raised a good question:

Per the discussion on zulip, I have become convinced that it would be better to make this feature use the syntax use, like:

impl SomeType {
    pub use SomeTrait::*;  // re-export the methods for the trait implementation
}

This syntax has a few advantages:

  • We can give preference to explicit method declared in the impl blocks over glob re-exports, eliminating one source of breakage (i.e., trait adds a method with a name that overlaps one of the inherent methods defined on SomeType)
  • Can make just specific methods (not all of them) inherent.
  • Easier to see the inherent method when scanning source.
  • You can re-export with different visibility levels (e.g., pub(crate))
  • It would work best if we planned to permit use SomeTrait::some_method; as a way to import methods as standalone fns, but I wish we did that.

However, in writing this, I realize an obvious disadvantage if the trait has more generics and things, it's not obvious how those should map. i.e., consider

struct MyType<T> {
}

impl<T> MyType<T> {
    pub use MyTrait::foo;
}

impl<T: Debug> MyTrait for MyType<T> {
    fn foo(&self) { }
}

This would be weird is this an error, because the impl block says it's for all T? And what if it were trait MyTRait<X>?

TC: My sense is that we've just been awaiting someone digging in and updating the RFC here.

"Raw Keywords" rfcs#3098

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:

  • What do we want to do about Rust 2015 and Rust 2018? It's a breaking change to add this there. Is this OK? Do we want to do a crater run on this?
  • Would we have the stomach to actually do this? It's one thing to say that if we wanted to use a new keyword within an edition, we'd write 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?

"RFC: Implementable trait aliases" rfcs#3437

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?

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

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 with SIGPIPE set to SIG_IGN, so that they will not properly terminate on broken pipe. But if you just made it set SIGPIPE to SIG_DFL before invoking the commands, now it would be broken in the case where the invoking user intentionally set SIGPIPE to SIG_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.)

"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?

"[RFC] core::marker::Freeze in bounds" rfcs#3633

Link: https://github.com/rust-lang/rfcs/pull/3633

TC: There's a proposal on the table for the stabilization of the Freeze trait in bounds.

We discussed this in our design meeting on 2024-07-24.

TC: What's next here?

"Implement PartialOrd and Ord for Discriminant" rust#106418

Link: 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)

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

"Fallout from expansion of redundant import checking" rust#121708

Link: https://github.com/rust-lang/rust/issues/121708

TC: We discussed this in the meeting on 2024-03-13. The feelings expressed included:

  • We don't want to create a perverse incentive for people to expand existing lints rather than to create new ones where appropriate just because there's less process for expanding the meaning of an existing lint.
  • It would be good if potentially-disruptive expansions of an existing lint either:
    • Had a machine-applicable fix.
    • Or had a new name.
  • We don't want to require a new lint name for each expansion.
  • We don't want to require a crater run for each change to a lint.
  • There are two ways to prevent disruption worth exploring:
    • Prevent potentially-disruptive changes from hitting master.
    • Respond quickly to early indications of disruption once the changes hit master.
  • Compiler maintainers have a sense of what might be disruptive and are cautious to avoid it. It may be OK to have a policy that is not perfectly measurable.

TC: tmandry volunteered to draft a policy proposal.

"What are the guarantees around which constants (and callees) in a function get monomorphized?" rust#122301

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?

"Policy for lint expansions" rust#122759

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:

  • We don't want to create a perverse incentive for people to expand existing lints rather than to create new ones where appropriate just because there's less process for expanding the meaning of an existing lint.
  • It would be good if potentially-disruptive expansions of an existing lint either:
    • Had a machine-applicable fix.
    • Or had a new name.
  • We don't want to require a new lint name for each expansion.
  • We don't want to require a crater run for each change to a lint.
  • There are two ways to prevent disruption worth exploring:
    • Prevent potentially-disruptive changes from hitting master.
    • Respond quickly to early indications of disruption once the changes hit master.
  • Compiler maintainers have a sense of what might be disruptive and are cautious to avoid it. It may be OK to have a policy that is not perfectly measurable.

TC: tmandry volunteered to draft a policy proposal. He's now written up this proposal in this issue.

TC: What do we think?

"Decide on path forward for attributes on expressions" rust#127436

Link: https://github.com/rust-lang/rust/issues/127436

TC: We decided recently to unblock progress on attributes on expressions (RFC 16) by allowing attributes on blocks. We have a proposed FCP to this effect.

After we did this, the question came up what we want to do about attributes in list contexts, e.g.:

call(#[foo] { block1 }, #[bar] { block2 })

in particular, macro attributes.

Petrochenkov says:

It needs to be decided how proc macros see the commas, or other separators in similar cases.

Ideally proc macros should be able to turn 1 expression into multiple (including 0) expressions in this position, similarly to cfgs or macros in list contexts without separators. So it would be reasonable if the separators were included into both input and output tokens streams (there are probably other alternatives, but they do not fit into the token-based model as well). The "reparse context" bit from #61733 (comment) is likely relevant to this case as well.

We filed a concern to figure this all out.

We discussed this on 2024-07-24 and came up with these options:

Options ordered from least to most conservative (and then from most to least expressive):

  • Option A: Punt this case and don't support attributes in this position without parens (e.g. call((#[attr] arg), (#[attr] arg2)))
  • Option B (exactly one): Specify that, for now, if you use a macro attribute on an expression, that macro can only expand to a single expresion (not zero tokens, and no tokens following in the output).
  • Option C (zero or one): Specify that, for now, if you use a macro attribute on an expression, that macro can only expand to zero tokens or an expression with nothing following (extra tokens, including ,, are an error for now)
  • Option D (zero or more): Specify that an attribute in this position can expand to tokens that may include a ,, and that if they expand to zero tokens then we elide the comma.
  • Option E (flexible): include comma, let macro decide, etc
    • We find it surprising that comma would be included.

In discussion, we seemed generally interested in allowing at least zero and 1. We weren't sure about N, and we weren't sure about the handling of the comma in the input.

TC: What do we think?

"Decide on bounds syntax for async closures (RFC 3668)" rust#128129

Link: https://github.com/rust-lang/rust/issues/128129

In the special design meeting 2024-07-23, we discussed five syntaxes for async closures:

  • F: async FnMut() -> T
  • F: AsyncFnMut() -> T
  • F: async mut fn() -> T
  • F: async mut () -> T
  • F: async mut || -> T

Our current straw poll is:

name async Fn*() -> T AsyncFn*() -> T async fn * () -> T async * () -> T async * |A, B| -> T
nikomatsakis +1 +0 -1 -1 -1
tmandry +1 +1 -0.5 -1 -0.5
Josh -1 +0.75 +0.5 +1 +0.5
pnkfelix +0 -0 -0.5 +0 -1
scottmcm
TC +1 -0.5 -1 -1 -1
CE +1 -1 -1 -0.5 -1
eholk +1 +0 -1 -0.75 -0.5
  • +1: "This is what I would do."
  • +0: "I'm OK with this, leaning positive."
  • -0: "I'm neutral to this, leaning negative."
  • -1: "I would block this."

We agreed to:

  • Move this to an unresolved question in RFC 3668.
  • Allow that RFC to proceed to FCP.
  • Implement both of the two main syntax options in nightly.
  • Give both syntaxes equal billing in any blog posts about this.

There was substantial discussion of this after the design meeting itself in the thread here:

https://rust-lang.zulipchat.com/#narrow/stream/410673-t-lang.2Fmeetings/topic/Design.20meeting.202024-07-23

TC: This is just an FYI for those that didn't follow this closely.

"Tracking issue for release notes of #127672: Stabilize opaque type precise capturing (RFC 3617)" rust#129577

Link: https://github.com/rust-lang/rust/issues/129577

Action item review

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

Link: https://github.com/rust-lang/lang-team/pull/258

Link: https://github.com/rust-lang/lang-team/pull/267

"text describing how other teams are enabled to make decisions." lang-team#290

Link: https://github.com/rust-lang/lang-team/pull/290

RFCs waiting to be merged

None.

S-waiting-on-team

"Stabilize extended_varargs_abi_support" rust#116161

Link: https://github.com/rust-lang/rust/pull/116161

"Emit error when calling/declaring functions with vectors that require missing target feature" rust#127731

Link: https://github.com/rust-lang/rust/pull/127731

"Allow dropping dyn Trait principal" rust#126660

Link: https://github.com/rust-lang/rust/pull/126660

"optimize attribute applied to things other than methods/functions/c…" rust#128943

Link: https://github.com/rust-lang/rust/pull/128943

"Lint against getting pointers from immediately dropped temporaries" rust#128985

Link: https://github.com/rust-lang/rust/pull/128985

"repr(tag = ...) for type aliases" rfcs#3659

Link: https://github.com/rust-lang/rfcs/pull/3659

"Stabilize count, ignore, index, and length (macro_metavar_expr)" rust#122808

Link: https://github.com/rust-lang/rust/pull/122808

"Emit a warning if a match is too complex" rust#122685

Link: https://github.com/rust-lang/rust/pull/122685

"Better errors with bad/missing identifiers in MBEs" rust#118939

Link: https://github.com/rust-lang/rust/pull/118939

"Uplift clippy::double_neg lint as double_negations" rust#126604

Link: https://github.com/rust-lang/rust/pull/126604

"Rename AsyncIterator back to Stream, introduce an AFIT-based AsyncIterator trait" rust#119550

Link: https://github.com/rust-lang/rust/pull/119550

"Implement RFC 3349, mixed utf8 literals" rust#120286

Link: https://github.com/rust-lang/rust/pull/120286

"Allow #[deny] inside #[forbid] as a no-op" rust#121560

Link: https://github.com/rust-lang/rust/pull/121560

"Stabilize s390x inline assembly" rust#131258

Link: https://github.com/rust-lang/rust/pull/131258

Proposed FCPs

Check your boxes!

"repr(tag = ...) for type aliases" rfcs#3659

Link: https://github.com/rust-lang/rfcs/pull/3659

"Consider deprecation of UB-happy static mut" rust#53639

Link: https://github.com/rust-lang/rust/issues/53639

"Tracking Issue for enum access in offset_of" rust#120141

Link: https://github.com/rust-lang/rust/issues/120141

"Decide on name for Freeze" rust#131401

Link: https://github.com/rust-lang/rust/issues/131401

"Stabilize count, ignore, index, and length (macro_metavar_expr)" rust#122808

Link: https://github.com/rust-lang/rust/pull/122808

"Supertrait item shadowing v2" rfcs#3624

Link: https://github.com/rust-lang/rfcs/pull/3624

"Trait method impl restrictions" rfcs#3678

Link: https://github.com/rust-lang/rfcs/pull/3678

"[RFC] Default field values" rfcs#3681

Link: https://github.com/rust-lang/rfcs/pull/3681

"Add support for use Trait::func" rfcs#3591

Link: https://github.com/rust-lang/rfcs/pull/3591

"Stabilize anonymous_lifetime_in_impl_trait" rust#107378

Link: https://github.com/rust-lang/rust/pull/107378

"[RFC] externally implementable functions" rfcs#3632

Link: https://github.com/rust-lang/rfcs/pull/3632

"Implement PartialOrd and Ord for Discriminant" rust#106418

Link: https://github.com/rust-lang/rust/pull/106418

"Policy for lint expansions" rust#122759

Link: https://github.com/rust-lang/rust/issues/122759

"Decide on path forward for attributes on expressions" rust#127436

Link: https://github.com/rust-lang/rust/issues/127436

"Don't allow unwinding from Drop impls" rfcs#3288

Link: https://github.com/rust-lang/rfcs/pull/3288

"Add text for the CFG OS Version RFC" rfcs#3379

Link: https://github.com/rust-lang/rfcs/pull/3379

"[RFC] Add #[export_ordinal(n)] attribute" rfcs#3641

Link: https://github.com/rust-lang/rfcs/pull/3641

"Stabilize associated type position impl Trait (ATPIT)" rust#120700

Link: https://github.com/rust-lang/rust/pull/120700

Active FCPs

"Implement edition 2024 match ergonomics restrictions" rust#131381

Link: https://github.com/rust-lang/rust/pull/131381

"Stabilize shorter_tail_lifetime" rust#131445

Link: https://github.com/rust-lang/rust/issues/131445

"Decide on name for derive(SmartPtr)" rust#129104

Link: https://github.com/rust-lang/rust/issues/129104

"Finish stabilization of result_ffi_guarantees" rust#130628

Link: https://github.com/rust-lang/rust/pull/130628

P-critical issues

None.

Select a repo