T-lang meeting agenda

  • Meeting date: 2024-01-24

Attendance

  • People: TC, tmandry, Urgau, waffle, Santiago, scottmcm, nikomatsakis

Meeting roles

  • Minutes, driver: TC

Scheduled meetings

  • 2024-01-24: "Bounds for RPIT/RPITIT/async fn" #246
  • 2024-01-31: "Design meeting: Rust for Linux" #240

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!)

Rust 2024 review: Priority issues

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 but it has a dependency on some means of expressing precise capturing. That probably means stabilizing TAIT. We're starting with stabilizing ATPIT, and we're currently working on the stabilization report for that. We're hoping to have that ready this month.

Reserve gen keyword in 2024 edition for Iterator generators #3513

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

TC: Oli is back, and we're all working on this. The minimum we need to do for 2024 is reserving the keyword.

Tracking issue for promoting ! to a type (RFC 1216) #35121

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

TC: We're hoping to land a lint here and work is progressing on that.

TC: This is what we want to lint against:

fn never_type_fallback() { unsafe {
    if false { panic!() } else { transmute::<_, _ /* ?0 */>(()) }
    // later in fallback:     ?0 := ()
    // after ! stabilization: ?0 := !
}}

TC: Waffle has said that there are some complications about which he'll write.

Waffle: Still need to write that up.

Rust 2024 review: Needs triage

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

TC: The one issue here is also nominated. Let's cover it in the nominations.

Nominated RFCs, PRs, and issues

"refining_impl_trait only fires on public traits" rust#119535

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

TC: We recently in Rust 1.75 stabilized RPITIT/AFIT. Along with that, somewhat unusually, we stabilized two "please confirm you understand how Rust works" lints against the new feature.

One lint is async_fn_in_trait:

pub trait Foo {
    async fn foo() -> impl Sized;
    //~^ WARN use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
    //~| NOTE you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`
    //~| NOTE `#[warn(async_fn_in_trait)]` on by default
    //~| HELP you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change
}

The other is refining_impl_trait:

pub trait Foo {
    fn foo() -> impl Sized;
}

impl Foo for () {
    fn foo() -> () {}
    //~^ WARN impl trait in impl method signature does not match trait method signature
    //~| NOTE add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
    //~| NOTE `#[warn(refining_impl_trait)]` on by default
    //~| HELP replace the return type so that it matches the trait
}

TC: We decided to make the first lint fire only when the trait is crate public. We did the same for the second lint but it was discussed less explicitly.

TC: tmandry proposes that we make the second lint always fire:

  • The async fn lint is only temporary to help avoid footguns created by missing language features, and we want to make non-footgunny uses more convenient.
  • Refinement is a mechanism that will always exist and is fundamental to trait implementations.
  • Refinement's ability to "punch through" abstraction boundaries can happen accidentally, even within a crate.

TC: CE has advocated to keeping it so that the lint only fires for publicly-reachable traits:

My understanding was that private traits are always crate-local, and be always fixed in a non-semver-breaking way, so it makes no sense to bug people about things local to their crate.

The refines lint being public-only has to do with the fact that refinement is a possibly-accidental over-promising of trait bounds on an implementation. when that implementation is published as part of a public (and reachable) trait in a library, then it becomes a breaking change to remove it. It doesn't make sense to enforce that internally within a crate, imo.

TC: What do we think?

tmandry: My intuition is that type system features should work the same way within and outside of a crate.

waffle: This is just a lint so it does work the same way.

Josh: I was going to say something similar to waffle. It is true that this feature (refinement) exists in general. Within a crate you can also provide a more specific type and those things can rely on that if they know what they're using. But if it's only used within a non-public trait impl, you can always change it without breaking anything. So it seems like it only matters within a public API.

NM: I feel the same way that tmandry does. Trying to put my finger on why You're signaling your intent here, it's not just about breaking changes. Also it's surprising when you get more lints when you make something public. That seems like something to minimize. People might understand simpler lint rules better.

tmandry: In the refine RFC, this was going to be a dedicated attribute, and it did work regardless of whether your trait was public or not. And we later relaxed that to just be a lint. But I do feel like something that works more uniformly is more in line with the original RFC.

waffle: It's important also to optimize lints to not be annoying. If all uses of a feature causes a lint, then it subtracts value.

Josh: If we lint against a language feature across the board, then we have effectively turned the lint into a kind of language feature. On the other hand, if it fires only on public items, because it tells people about what they're committing to, that seems appropriate. But if we do it across the board, then we should have a refine attribute. But I don't want to turn #[allow(refining_impl_trait)] into a verbose version of that.

NM: Part of the compromise was to start with the lint to gather data and decide whether to move to a required #[refine] or to something more limited.

NM: Also, we're not linting against every use of RPITIT, only refining impls, and we don't know how common those will be (that was part of the goal with having a lint).

TC: To Josh's point, and to Niko's, one angle of doing it as a lint was that so that people could turn it off for the whole crate. That helps us gather data by seeing how often people turn it off across the crate.

NM: It's easier to relax lints rather than make them more strict.

Josh: If our intent is to gather data, do we want to find that in crater or by putting it into a release?

TC: We only released this at the end of December, so the denominator will be small.

NM: If part of the story is gathering data, we should make a point to actually gather it. In my ideal world we would do e.g. focus group evaluation. But at least we should experience it ourselves and have an idea.

tmandry: If I made a proposal to start linting on this in all cases, what would we think?

TC: In spirit of collecting data, we could make this into two lints. That would help with understanding intent when people disable this.

tmandry: And we can put them into a lint group.

Josh: We could solicit feedback in the lint itself. When people see a warning, they have to ask, "am I wrong, or is the compiler wrong?" People may be annoyed about false positives, if they consider this superfluous.

TC: We do that, e.g., for the required Self: 'a bound for GATs. So there is precedent.

NM: +1. I was going to suggest the same thing, and I would like to direct people to an issue. But people's experiences of Rust may be different, and not everyone is willing to go and post something.

tmandry: Any way that we can gather comments and use cases would be valuable. However, I'm not sure about a compiler lint that apologizes for itself.

NM: We can tell people that we're considering or trying to refine the lint.

Josh: If we're doing an explicit experiment where we lint across the board but we're trying to collect feedback across 2-3 releases, then that would be more appealing than turning it on and likely leaving it on for years.

tmandry: I agree that we should follow through, but I'm not sure that 2-3 releases will be long enough.

Josh: It's not about a particular number of releases, it's about setting a date on which we'll review this automatically. I personally think that if we haven't gotten the required feedback in 2-3 releases, I'd be surprised.

TC: The proposal on the table is that we add a separate lint for the non-public version, we put the two into a lint group, we create an issue and display that with the lint to gather feedback (as with GATs), and we make a note to review that feedback in 2-3 releases.

JT: +1 on that. I've been experimenting with the SnoozeThis bot, and we could run that against our repo to autonominate this.

tmandry: I'm not sure how much feedback we've gathered for GATs or how much we will here.

NM: Not sure there's any downside to setting a timeline.

JT: Here's the command:

@SnoozeThis wait 3 months -> tell rustbot label I-lang-nominated

Consensus: Let's add a separate lint against impls that refine a return type defined with RPITIT even when the trait is not crate public, let's put that in a lint group along with the analogous crate public lint, let's create an issue to solicit feedback, let's have the warnings displayed with each lint reference this issue in a similar manner to how we do that today with the required Self: '0' bound on GATs, and let's make a note to review this feedback in 2-3 releases.

"RFC: New range types for Edition 2024" rfcs#3550

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

TC: This RFC proposes migrating the ecosystem to new Range types with the new edition.

Change the range operators a..b, a.., and a..=b to resolve to new types ops::range::Range, ops::range::RangeFrom, and ops::range::RangeInclusive in Edition 2024. These new types will not implement Iterator, instead implementing Copy and IntoIterator.

TC: There is extensive discussion in the RFC body about the approach to migration.

TC: How do we want to approach this?

Josh: (Discusses some background.)

NM: How does the RFC propose to solve this?

Josh: We add new range types on different paths, then change how the language desugars.

NM: And we deprecate the others?

scottmcm: Not deprecate; they become like the Iter types.

Josh: And the new range types will implement RangeBounds so most functions that accept a range will automatically work.

scottmcm: for loops use IntoIterator, so they're fine with the new types already.

NM: I'm all in favor of this. The major downsides are two. One, how confusing is this for the future users of new editions? Two, have we done data gathering about how much pain there will be?

scottmcm: This is essentially the same proposal as came up three years ago. The migration is kind of ugly. I don't think anyone has come up with something magical. But we have three more years of experience, which may help us understand how useful this is to do. for x in old_range and v[old_range] continue to work, but there are lots of for x in (0..10).map(|_| foo()) that may not.

NM: When moving to the new edition, we could rewrite it in three different ways. Do we have data on how often we'd need to rewrite it into the less desirable options?

scottmcm: In tests, from the examples I saw in the discussions, there is awful lot of code that does e.g. (0..10).map. It's not a particularly useful iterator for real code, but it shows up often in tests.

tmandry: It doesn't have to just be a static range like that. I've written non-test code in that style. I've also been annoyed by the "range is not copy" problem. Maybe we could split the difference by implementing map directly.

NM: That's what I was going to propose.

scottmcm: The problem is that's very inconsistent.

NM: Maybe we can make this the problem of T-libs-api.

waffle: The RFC does propose to add the map method on new ranges, and the other common one, rev. It's inconsistent, but it will make the transition easier.

Josh: The work of making it friendly is T-libs-api work. So we should decide whether we approve of the lang aspect of this. Are we willing to change the desugaring of range in a new edition? If there are other things we want to make sure are considered, we can mention that and throw it over the wall to T-libs-api.

scottmcm: There are some lang concerns in the issue we should address. (Describes those.)

JT: We shouldn't do automatic coercion. But we could have .into() for the range types.

NM: +1 on that. Let's be minimal and try to collect data.

scottmcm: Hopefully anything that's taking range types is really taing range bounds.

waffle: The RFC proposes to implement From. It proposes automatic fixes for the migration.

waffle: We can gather data somewhat automatically. We can make the changes proposed in the RFC and run crater.

nikomatsakis: 1+ to what Waffle said.

TC: To reinforce what Waffle said, there is extensive discussion in the RFC about the migration plan.

Josh: We could lint against taking a range type and suggest taking a range lint.

NM: Seems like a good clippy lint?

NM: Are we in favor of this overall?

scottmcm: Correction: I had said that the old range types would be the Iter-like types, but it isn't the proposal. Anyone care?

Josh/NM: It's probably a T-libs-api concern.

tmandry: Let's tag this T-lang, T-libs-api, and propose FCP merge.

Consensus: Let's do this.

"Make it so that async-fn-in-trait is compatible with a concrete future in implementation" rust#120103

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

TC: CE nominated this for us:

There's no technical reason why an AFIT like async fn foo() cannot be satisfied with an implementation signature like fn foo() -> Pin<Box<dyn Future<Output = ()> + 'static>>.

We rejected this previously because we were uncertain about how AFITs worked with refinement, but I don't believe this needs to be a restriction any longer.

TC: As background, we allow:

trait Foo {
    fn foo() -> impl Future<Output = ()>;
}
impl Foo for () {
    fn foo() -> core::future::Ready<()> { todo!() }
}

And we allow:

trait Foo {
    async fn foo();
}
impl Foo for () {
    fn foo() -> impl Future<Output = ()> { async {} }
}

But we don't transitively allow:

trait Foo {
    async fn foo();
}
impl Foo for () {
    fn foo() -> core::future::Ready<()> { todo!() }
    //~^ ERROR method `foo` should be async because the method from the trait is async
}

TC: Do we agree with CE that we should fix this?

Waffle: This should work.

tmandry: I agree we should make this work. It is a form of refinement, so we should treat it as any other form of refinement.

Josh: +1, and we should emit the refinement lint. My only concern on this one is the question of whether someone will get caught out by some unusal impl of Future. E.g. people sometimes get surprised that Option impls Iterator. Not sure whether there are similarly odd things here.

Waffle: It's probably not a problem here.

NM: Surprising Future impls may be the problem here, not that you could use them in this context.

NM: +1 this should work.

Josh: Let's do this via FCP.

Consensus: Let's do this, and let's do it via FCP.

"[ptr] Document maximum allocation size" rust#116675

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

TC: RalfJ nominated this for us to check whether this language is acceptable to us:

It is guaranteed that an allocated object never spans more than isize::MAX bytes. An allocated object cannot contain [null()] (i.e., the address with the numerical value 0) and cannot contain the last (usize::MAX) byte of the address space.

NM: The phrasing there may be ambiguous about how it's using null.

waffle: The null pointer is obviously valid.

scottmcm: "The address of an allocated object" might address the concern.

waffle: An object could start at the end of the address space (say usize::MAX-1) and end at the start (say 1), then it would span across both 0 and usize::MAX. (This is of course forbidden with this proposal.)

NM: Maybe: "The range of addresses used by an allocated object cannot overlap with null."

NM: +1 on intent. I have suggestions on wording.

Josh: What do we expect people to do instead?

scottmcm: Write raw assembly. There's no way to do this within the Rust abstract machine.

scottmcm: The place is malformed, so you can't even make the place, even if you never read or write from it.

TC: We want to propose FCP merge?

tmandry: I'll start an FCP.

Consensus: Let's do this.

(The meeting ended here.)

"Discuss feedback for T-spec sample chapters" lang-team#250

Link: https://github.com/rust-lang/lang-team/issues/250

TC: Recently, members of T-spec wrote some sample chapters to prompt discussion of what the content and style of the spec may be.

In a recent meeting, the members of T-spec expressed a desire to hear feedback from T-lang on these drafts.

NM: This would be a good use for a design meeting!

Background reading

We opened a thread to discuss this async here:

https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Feedback.20on.20T-spec.20sample.20chapters

TC: How do we want to approach reviewing and giving feedback here?

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

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

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

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

"Tracking Issue for cfg-target-abi" rust#80970

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

TC: Chris Denton proposes to stabilize #[cfg(target_abi = "..")]:

Stabilization report

I propose to stabilize #[cfg(target_abi = "...")], This implements RFC-2992 (cfg-target-abi). The implementation was completed in #86922 and this tracking issue was subsequently marked as ready for stabilization by @joshtriplett.

Summary

This stabilizes the cfg option called target_abi:

#[cfg(target_abi = "macabi")]

And target_abi is also shown when using --print=cfg (output snipped for length):

> rustc --print=cfg --target aarch64-apple-ios-sim

target_abi="sim"
target_arch="aarch64"
target_env=""
target_os="ios"
target_vendor="apple"

Without target_abi, cfgs are limited to target_arch, target_vendor, target_os, and target_env. However, some targets are only differentiated by their abi and thus it's necessary to resort to parsing the full target string in a build script when there's a need to disambiguate. For example, the following targets are the same if only using stable target_* cfgs:

  • aarch64-apple-ios and aarch64-apple-ios-sim (arch: "aarch64", vendor: "apple", os: "ios", env: "")
  • x86_64-pc-windows-gnullvm and x86_64-pc-windows-gnu (arch: "`x86_64", vendor: "pc", os: "windows", env: "gnu")

Notes

The target_abi defaults to "" (the empty string) and most targets don't set it. This is similar to target_env where if it's not needed for disambiguation then it's often not set.

In the future target_abi could be an array of zero or more properties that affect the ABI (e.g. softfloat may be combined with other ABI properties), However, this feature can be added later without breaking compatibility.

TC: Given the recent discussions over ABI issues, I made sure RalfJ was aware of this, and he had no particular concerns.

"Make ConstPropLint lint run on promoteds" rust#119432

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

TC: Oli nominates this for us:

Nominating for T-lang for awareness TLDR: existing lints will trigger in more situations where we were missing them before. In our test suite this causes duplicate lint emissions, but they are deduplicated for users.

gurry:

Fixes #117949 wherein the lint didn't fire for the following promoteds:

  • SHL or SHR operators in a non-optimized build
  • any arithmetic operator in an optimized build

What I have done here is simply enabled ConstPropLint to run on promoted bodies by removing the relevant if check.

After this change all promoted arithmetic operators will lint in both non-optimized and optimized builds. On the flip side programs containing the above mentioned overflowing promoteds that were accepted earlier will now be rejected. Hope that is okay from a backward compatibility standpoint.

I have added tests covering all overflowing promoted & non-promoted ops for both compile-time and runtime operations and for optimized as well as non-optimized builds.

I had to amend some existing tests to make them pass and had to delete a couple that were set to pass despite overflows.

This PR increases the number of duplicate diagnostics emitted (because the same operator might get linted in both the promoted MIR and the main MIR). I hope that is an acceptable trade-off given that we now lint overflows much more comprehensively than earlier.

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

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?

"privacy: Stabilize lint unnameable_types" rust#120144

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

TC: petrochenkov nominates this for us and describes the change:

This is the last piece of "RFC #2145: Type privacy and private-in-public lints".

Having unstable lints is not very useful because you cannot even dogfood them in the compiler/stdlib in this case (#113284). The worst thing that may happen when a lint is removed are some removed_lints warnings, but I haven't heard anyone suggesting removing this specific lint.

This lint is allow-by-default and is supposed to be enabled explicitly. Some false positives are expected, because sometimes unnameable types are a legitimate pattern. This lint also have some unnecessary false positives, that can be fixed - see #120146 and #120149.

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

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

"Decision: semantics of the #[expect] attribute" rust#115980

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

TC: @nikomatsakis gives this background:

This issue is spun out from #54503 to serve as the decision issue for a specific question. The question is what the 'mental model' for the expect attribute should be. Two proposed options:

  1. The expectation is fulfilled, if a #[warn] attribute in the same location would cause a diagnostic to be emitted. The suppression of this diagnostic fulfills the expectation. (src) (Current implementation in rustc)
  2. The expectation is fulfilled if removing the #[expect] attribute would cause the warning to be emitted. (src)

@xFrednet created a list of use cases to help with the discussion of these two models; they found both models work equally well, except for use case 4 which would only be possible with the first model.

TC: and proposes that we adopt option 1.

"Support overriding warnings level for a specific lint via command line" rust#113307

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

TC: We discussed in the 2023-09-26 meeting, but were unsure of the question we were being asked. @jieyouxu has since replied:

I believe I wanted to ask that if the command line indeed forms the root of the tree, or if it actually overrides the source annotations.

TC: On that basis, @tmandry replied:

Nesting

I think the command line (specifically -A, -W, -D flags) should form the root of the tree. We have --cap-lints, --force-warn, and -F (forbid) for overriding the source. (Actually the mental model documented in the rustc book is that force-warn and forbid still form the root of the tree, but cannot be overridden; I think the distinction is mostly academic.)

That's almost all the expressive power one could want along this axis. One wrinkle is that --forbid is overridden by --cap-lints, while --force-warn is not. If we wanted full fine-grained control we could always add --force-allow and --force-deny.

warnings

Regarding the meaning of warnings, it is a simpler mental model for this to mean "the set of things that are warn-by-default". But this ignores what I perceive to be a common (and valid) use case, which is to disallow all warnings in a codebase: In other words, prevent code from being checked in that causes warnings to be printed to a user's screen. Of course, for this to be practical one must control the version of rustc being used to build a codebase, but that is common in monorepo setups.

Conclusion

Given that there is an existing use case that relies on documented behavior, I think we should continue to treat warnings as a "redirect" for all warnings that come out of a particular level of the tree. Interpreting -Awarnings -Wfoo in the way proposed by this PR would muddy the (already complicated) mental model and add inconsistency between CLI and the command line, as noted by @oli-obk.

A different group, like default-warnings, could be used to mean "the set of things that are warn-by-default". The compiler could further warn users that specify -Awarnings -Wfoo on the command line to use -Adefault-warnings -Wfoo instead.

TC: Where do we want to go from here?

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

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?

"Arbitrary self types v2" rfcs#3519

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

TC: We discussed this on 2023-11-22. The general feeling seemed to be that we wanted to find some way to enable this, including for raw pointers, NonNull, etc., but we were feeling unsure about the path to get there. We asked the author to cogitate on this and come back with a revised plan.

TC: The author did that, and we had an extensive discussion on 2024-01-17 without consensus. We have open threads for discussing this asynchronously.

Here's the thread for the proposal:

https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Arbitrary.20self.20types.20v2.20RFC

And here's the thread for the broader question of whether we want arbitrary self types at all:

https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Do.20we.20want.20arbitrary.20self.20types.3F

"RFC: Syntax for embedding cargo-script manifests" rfcs#3503

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

TC: We discussed this for most of one triage meeting in November without reaching any consensus. There is a design meeting proposal, but we have not yet scheduled it for a date. At Josh's suggestion, Ed Page has renominated this for us.

Earlier context included:

@scottmcm raised these interesting points:

My biggest question here is how much it should be thought of as tied to the script use, and thus to the #!.

My instinct is that either

  1. This is tied to the shebang, so there's only one of them, to be consumed only by whatever tool is in the shebang, and rustc completely ignores it, like we completely ignore the shebang line. And thus the "``` right after the shebang" syntax seems entirely reasonable to me.
  2. This is a general tool feature, for which there will be multiple of them, and for which they'd want something like tool attribute namespacing so there's a clear route to lots of them under understood namespaces, and are a full part of the parsed structure of the crate, maybe included in rustdoc, etc. (Like perhaps --document-private-items on a crate would show an embedded rustfmt::config block somewhere, one day.)

@nikomatsakis noted that, even if it's tied to a shebang, he doesn't see a reason to limit it to only one.

@tmandry suggested that:

With my lang hat on, I don't see a reason we should RFC a feature that only allows cargo front matter, without specifying a path to generalizing it to other tooling. If we want to be conservative in what we stabilize, let's approach that in the stabilization rather than in the RFC.

In the meeting, @nikomatsakis suggested that we seem misaligned on the purpose of this. Others in the meeting suggested that the syntax should derive from a clear understanding of that purpose and the eventual goals for it.

TC: We've since discussed this asynchronously here:

https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Syntax.20for.20embedded.20tooling.20metadata/near/409126434

We seemed to agree that:

  • .rs files should parse as valid Rust.
    • I.e., we don't want to expect the runner to have to strip out these blocks.
  • Rust itself should not validate the content of these blocks.

The open questions include:

  • Should there be only one of these blocks or potentially many?
    • If we only support one block, tools that need many will define their own syntax for delineation.
      • It could be awkward to change our mind later on this, as tools will have already defined this delineation in their own SemVer commitments.
    • Supporting only one is simpler (for us) and gives tools flexibility.
    • But if we want IDEs to eventually support syntax highlighting for these blocks (e.g. based on the file type indicated in the info string), then we probably need to handle this ourselves.
      • tmandry: "Making that kind of editor integration possible is important to me, even though I expect that many editors won't support that level of generality in their syntax definitions today."
  • Relatedly, do we want to support info strings?
  • Should the shebang be optional or required when using these blocks?
    • It's more conventional for the shebang to be optional.
    • If it's required, people may end up writing e.g. #!/bin/false as a workaround.
    • The shebang is meaningless for Windows.
  • What syntax to use?
    • Triple (or more) backticks.
      • Upside: Beginners may prefer this, but of course they would due to Markdown familiarity.
      • Downside: Even figuring out how to encode those backticks literally in this document is difficult. Users would need to know advanced Markdown to encode these Rust files. Some markdown parsers (e.g. the one for Discord) are not sophisticated enough to allow this.
        • tmandry: "I think that is a serious quality of life hazard we should be cognizant of. If I were to boil it down to a principle I would say that Rust should feel pleasant to use, and that includes in places like github comments, chatrooms, and forums, where many people write Rust code every day!"
      • Downside: It's a new matched string literal syntax when Rust already uses # for this.
    • Triple (or more) hashes (###).
      • Upside: This would look natural with the shebang and would suggest association with the shebang.
      • Upside: Rust already uses matched #s for literals.
      • Downside: We may want a space before the info string.
    • Triple (or more) dashes (---).
      • Upside/downside: This is associated with YAML header blocks.
      • Downside: It's a new matched string literal syntax when Rust already uses # for this.
      • Downside: This may look less natural with an info string, or we may want a space before it.

There is an open experiment on the cargo side that simulates the various syntax options, e.g.:

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

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

"Uplift clippy::precedence lint" rust#117161

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

TC: The proposal is to lint against:

-2.pow(2); // Equals -4.
1 << 2 + 3; // Equals 32.

These would instead be written:

-(2.pow(2)); // Equals -4.
1 << (2 + 3); // Equals 32.

Prompts for discussion:

  • 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. !, *, &)?

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

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

RFCs waiting to be merged

"Avoid non-local definitions in functions" rfcs#3373

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

"RFC: constants in patterns" rfcs#3535

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

S-waiting-on-team

"Tracking issue for dyn upcasting coercion" rust#65991

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

"Stabilize anonymous_lifetime_in_impl_trait" rust#107378

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

"make matching on NaN a hard error, and remove the rest of illegal_floating_point_literal_pattern" rust#116284

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

"warn less about non-exhaustive in ffi" rust#116863

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

"Add lint against function pointer comparisons" rust#118833

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

"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

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

"add float semantics RFC" rfcs#3514

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

"RFC: patchable-function-entry" rfcs#3543

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

"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

"Decision: semantics of the #[expect] attribute" rust#115980

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

"References refer to allocated objects" rust#116677

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

"Prevent opaque types being instantiated twice with different regions within the same function" rust#116935

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

"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

"static mut: allow mutable reference to arbitrary types, not just slices and arrays" rust#117614

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

"Add REDUNDANT_LIFETIMES lint to detect lifetimes which are semantically redundant" rust#118391

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

Active FCPs

None.

P-critical issues

"Pointer casts allow switching trait parameters for trait objects, which doesn’t interact soundly with trait upcasting" rust#120222

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

Select a repo