T-lang planning meeting agenda

  • Meeting date: 2023-12-06

Attendance

  • People: TC, tmandry, eholk, waffle, Josh, scottmcm, eholk

Meeting roles

  • Minutes, driver: TC

Availabiliy

  • December 13: Everyone present is available.
    • Let's do match ergonomics.
  • December 20: Everyone present is available.
    • Let's do lang-team#235.
  • December 27: rule out due to holiday
    • Between Christmas and New Years.
    • Let's cancel.

Proposed meetings

  • "We need to settle the behaviour of floating-point in const" #222
  • "discuss/resolve fn { mod { (use) super::...; } } and its interaction with derive patterns" #193
  • "Design meeting: Rust issues encountered by new Rust users in the Bevy project" #229
  • "Design meeting: resolve ABI issues around target-feature" #235
  • "Nail down cargo-script syntax proposal" #232
    • Might be able to settle this in a triage meeting, depending on async discussion and proposal updates.

Other pending proposals include:

  • Standing proposal: Work on the 2024 edition.
  • Discussing the needs and use cases of Rust for Linux.
  • Flexible Unsize and CoerceUnsize traits - pre-RFC.
  • Improvements to match ergonomics - proposal in issue.
    • Seems like we wouldn't get through this in a triage meeting, might want to use a design meeting for it.
  • P-high lang issue, incorrect UB when when a ! place is constructed (but not loaded!) #117288

Please update these in https://github.com/orgs/rust-lang/projects/31/views/7.

Discussion

tmandry: We should schedule Rust for Linux if there will be a doc for it. Not clear whether that would happen yet or not.

Josh: Could also follow through with inviting someone from Bevy to talk about their list of issues new users encounter.

TC: The lang-team#235 has a doc ready from RalfJ.

tmandry: Making a short list, lang-team#235 should probably be discussed. Also RFL.

tmandry: Looking at the match ergonomics, some of those are edition-related, so we should prioritize.

tmandry: I'd propose we schedule that and the doc that RalfJ prepared. And we should tell the RFL folks that we definitely want to talk about that.

TC: Thoughts? Hearing none, sounds like consensus.

TC: Propose the match ergonomics first, as it's edition sensitive, then RalfJ's the week after.

Planning for 2024 edition

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

Disallow references to static mut [Edition Idea] - #114447

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

TC: I'm meaning to write an RFC about this.

tmandry: One question is do we need one.

scottmcm: I'd probably hope for an RFC here, but hopefully a short one. (It's something that people have been using in stable for a while, so it feels like "more" than just an issue, in a sense.)

Josh: We may want a &raw syntax, so there could be churn here. Not a blocker, since we could suggest one thing, then later suggest another, just a consideration.

scottmcm: We really just want people to use SyncUnsafeCell or to define their own type.

Josh: Should we reopen the discussion of forbidding static mut?

scottmcm: Yes, but not for the 2024 edition.

scottmcm: I like RalfJ's suggestion here. We can discourage static mut, but in the meantime to maybe later removing it, we can do this.

tmandry: Sounds like we want an RFC. I'll unnominate this.

Josh: Note that SyncUnsafeCell only implements Sync if T implements Sync. We may want an unsafe type that always implements Sync.

scottmcm: That's surprising, since SyncUnsafeCell was, I thought, designed for this use case.

Fix whitespace escaping behavior in string literals

(No issue link.)

Some background:

https://github.com/rust-lang/reference/pull/1042

Josh: So in the edition, we'd remove the behavior of removing multiple newlines.

tmandry: There's also something about only skipping increments of 4.

Josh: We should fix this.

waffle: This is probably complicated enough to merit an RFC.

waffle: Do we want a special syntax for multiline strings, like what Zig does?

tmandry: Anyone disagree this needs an RFC?

Josh: It needs clear documentation at least. I'd take it with a patch for the reference, or an RFC if others prefer that.

"incorrect UB when when a ! place is constructed (but not loaded!)" rust#117288

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

(TC: We deferred this from triage to maybe discuss in the planning meeting.)

TC: @RalfJ found some interesting examples where rustc generates SIGILL on code that shouldn't have UB. T-compiler marked this P-high. RalfJ:

Nominating this to get first vibes on which of the following lines should be accepted, and which should be UB. (Currently they are all accepted and all UB but that's a bug.)

#![feature(never_type)]
fn deref_never<T>() {
    unsafe {
        let x = 3u8;
        let x: *const ! = &x as *const u8 as *const _;
        let _val = addr_of!(*x); // must be OK
        let _ = *x; // should probably be OK since we said `_` discards the place (and is UB-equivalent to `addr_of!`)
        let _: ! = *x; // does a no-op type annotation force the place to be loaded and hence cause UB?
        let _: () = *x; // is this UB? should we even accept such code?
        let _: String = *x; // what about this?
        let _: T = *x; // is this UB even if T = ! ?
    }
}

TC: I asked RalfJ for a proposal for the right behavior on the ones with question marks. RalfJ:

I don't know how to arrive at a principled answer to this. There's no obvious "correct" here, it's a judgment call.

If you are asking for my personal preference ignoring backwards compatibility constraints, then my immediate gut feeling is that places of type ! should not be subject to never-to-any coercions (the coercion should apply only to values, matching the comment that justifies the coercion in the first place). So:

        let _: ! = *x; // OK, not UB
        let _: () = *x; // does not compile
        let _: String = *x; // does not compile
        let _: T = *x; // does not compile

TC: What do we think?

Josh: Why do we allow?:

let x: *const ! = &x as *const u8 as *const _;

scottmcm: You can create any pointer and it's inhabited. The pointer is fine, but the read is invalid.

Josh: But that's not true at the type level. Any time you have a never is code that will never be run.

scottmcm: If you have a byte that is 3, and you can have a *const bool to it. So the pointer is fine, but it's a pointer you can't read without invoking UB. So that's entirely normal for raw pointers.

TC: +1 to scottmcm.

tmandry: +1 to scottmcm.

scottmcm: We can't even make a post-mono error, as it could be under an if false. It's legal Rust code, just UB.

waffle: We shouldn't make these more special. It'd be worth making them less special.

scottmcm: Consider tuples and partial initialization.

Josh: If you have a *const (u32, !), can you dereference it if you only look at the u32 and never create a !?

scottmcm: The question is, do we enforce validity rules on place creation or on place reading?

waffle: We really want to say that let _ = *x does not make a read. We enforce validity when the place is converted to a value. If you're not using the place in any way, then you don't hit the invalidity.

scottmcm: Consider:

let p: *const (u32, !) = ...;
let q = ptr::addr_of!((*p).0); // uses only *place* operations, not values

waffle: Yes I think this should be correct.

Josh: So if we accept any of the proposals for pointer projection, then this would be fine.

scottmcm: So this would be justifiable

This should be legal even if U=! and f1 panics.

pub fn blah<T, U>(f0: impl Fn() -> T, f1: impl Fn() -> U) -> (T, U) {
    unsafe {
        let mut mu: MaybeUninit<(T, U)> = MaybeUninit::uninit();
        let p = mu.as_ptr_mut();
        //(*addr_of_mut!((*p))).0 = f0();
        // place projection here is fine, because it never became a value
        (*p).0 = f0();
        pointermagic.1 = f1();
        return mu.assume_init();
    }
}

waffle: An invalid type is OK in a place, but it's UB when you coerce that into a value.

scottmcm: The code above is the same as the original argument that these tuples can't be ZSTs because of what compiler does internally. The compiler already wants to write code like this (at least to LLVM) for tuple creation.

waffle:

// Ralf's suggestion from above

// x: *const !

// OK because we say that `_` does not covert a
// place to a value.
let _: ! = *x; // OK, not UB

// This should not compile because if it compiled,
// it would make it so that we converted never to unit,
// and that would be immediate UB.
let _: () = *x; // does not compile
// because this is actually
let _: () = (*x) as ();
// and thus there's a value,
// and thus we don't *want* it to compile because that'd be super confusing

// Q: is this also doing a coercion
// in a world where it hits type fallback instead
// of inferring to `!`?  (Since nothing infers to `!` today)
// like if someone uses the never-type-on-stable hack...
//
// A: yes
let _ = *x; //~ Shouldn't compile because it infers unit and be UB, today.  But we want it to not compile.
// Today: compiles as UB because it infers as `()` due to fallback
// Wish: doesn't compile because oh god no.


let _: String = *x; // does not compile
let _: T = *x; // does not compile

enum Never {}
let y: *const Never = 1 as _; //~ OK today.

// this doesn't compile today,
// because there is no Never -> () place coercion which is probably incorrect with !
let _: () = *y; //~ ERROR: type mismatch

// This still will be UB:
let _: () = {*x};

Josh: No objection any longer about what was mentioned above. Happy to defer to expert analysis here.

tmandry: Stabilizing ! is one of the 2024 issues up for discussion.

TC: If there are things we could do in 2024 that would help make it possible to evetually do the never type, we should look at that.

scottmcm: If we stopped doing this coercion, and people had to write it out, that's one thing we could do.

scottmcm: second attempt at stabilizing never: https://github.com/rust-lang/rust/issues/57012

scottmcm: Nothing ever infers to ! today because it's not a type on stable. It's a weird magic syntax. So reading a pointer to !, if you do a hack to get it, is that the value you get back will infer to unit, because that's what type parameter fallback does in these cases, which is why we're having trouble stabilizing never in the first place. So because of that type parameter fallback, you get coercions in places that wouldn't be corecions for literally any other type.

waffle: That's correct.

waffle: Simple explanation:

// We want to say that this:
let _ = *x; //~ Does not do a read.

This implies that places don't enforce validity invariants.

Which means that a place coercion of ! -> T is invalid, because it assumes that !'s validity invariant (false) was enforced.

I.e. The place coercion of ! -> T (any type T) is a compiler bug. It's wrong that we accept this code today.

If you have a value of never, then you can coerce it. But you can't validly do that to a place.

TC: Does this have bearing on the never stabilization?

scottmcm: We can't remove the value coercion since we need that. But if we could figure out how to remove the value coercion, that would make it more possible.

tmandry: We could change how the coercions work with the edition. We could make it go from being implicit to explicit.

scottmcm: Of course, if it's explicit, it's not a coercion.

tmandry: It's a cast.

scottmcm: There's no place cast in stable Rust. In this case, we'll get rid of the place coercion, so we don't need a place cast.

tmandry: Sounds good to me. I trust you all to figure this out.

TC: Could we make those value coercions into casts, over an edition?

scottmcm: Maybe? It's hard to make confident statements in this area.

scottmcm: If we could notice what you're calling is a function that returns ! and treat that as control-flow rather than value flow somehow, and do that in a way that is edition dependent. But this is all slightly wrong because of how we do HIR building.

scottmcm: Theoretically the only thing you can do with ! today is to have a value return from a function. It's technically wrong to use it elsewhere. It's officially unstable, so maybe we could carve something out.

TC: We've discussed how stabilizing Infallible made more difficult the stabilization of the never type.

scottmcm: It's because we want Infallible to be a type alias to never.

TC: Is there any sense in that all emtpy enums should coerce to !?

scottmcm: Maybe. This may get into the problem of type parameter fallback.

let x = returns_bang(); // x is of type `()`
let y = returns_infallible(); // y is of type `Infallible`

waffle: If I recall correctly, the problem with type fallback is that for generic functions, we currently infer unit, but we want to infer bang. But if we infer bang, then existing code become UB.

scottmcm:

if false { panic!() } else { transmute(()) }

This is not UB today. But if the panic!() inferred to bang, then it would be UB.

A trunsmute creating a ! is obvious immediate UB. Since the transmute is unconstrained, changing the type of panic!() changes the dst type of transmute from unit to bang.

TC: We needed to circle back to:

let _: () = *x; // Insta-UB or compiler error?

scottmcm: Even if we say that the place can't be coerced, that could still do the place to value coercion, and then convert that.

waffle: The place to value coercion happens at the let level

scottmcm: And we wouldn't be asking for the value?

TC: It seems like we're saying it's at least insta-UB, and any insta-UB that the compiler can find is of course good.

scottmcm: I might put this in a deny-by-default lint rather than a compiler error category.

TC: +1.

scottmcm: You only get the coercion if it's literally a coercion to !. If it's a pointer to a generic type, and that happens to be substituted to !, then

waffle:

unsafe fn foo<T>(p: *const T) {
    // doesn't compile because generics don't work like that
    let _: () = *p; //~ ERROR
}
// so you only hit that if it's literally bang, like
unsafe fn bar(p: *const !) {
    let _: () = *p;
}
// and nobody would ever write that.

scottmcm: If bar is UB to call but compiles, then I'm OK with that. Don't write that.

scottmcm: Do we want a crater run?

TC: What would we expect crater to hit?

waffle: Not doing place coercions should make strictly less code compile.

scottmcm: What classes of things would hit this?

scottmcm: If we could make this be the rule, that'd be great.

Consensus: It's not UB to have an invalid thing in a place. But it's UB to coerce that invalid place to a value. And anywhere that the compiler can statically determine that insta-UB is happening, that would be a good spot for a deny-by-default lint, and it'd also be fine to hard error on those cases if that's easier.

Ralf's comment here https://github.com/rust-lang/rust/issues/117288#issuecomment-1813030483

scottmcm: Where this may break is the use of the never type hack, but that's probably OK.

waffle:

trait Hack {
    type Out;
}

impl<T> Hack for fn() -> T {
    type Out = T;
}

type Never = <fn() -> ! as Hack>::Out;

scottmcm: More details: https://github.com/rust-lang/never-type-initiative

(The meeting ended here.)

Active initiatives

"project-safe-transmute" lang-team#21

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

"const-evaluation" lang-team#22

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

"const-generics" lang-team#51

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

"Deref patterns" lang-team#88

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

"Generators (iterator functions), sync and async" lang-team#137

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

"Initiative: trusted external static declarations" lang-team#149

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

Pending proposals on the lang-team repo

None.

Pending PRs on the lang-team repo

"project-safe-transmute" lang-team#21

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

"const-evaluation" lang-team#22

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

"clarify lint policy " lang-team#48

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

"const-generics" lang-team#51

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

"Make a place for a "lang team wishlist"" lang-team#54

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

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

"Eventual Concern: Send/Sync insufficient in the presence of multiple execution contexts." lang-team#87

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

"Deref patterns" lang-team#88

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

"Specification of safe rust ?" lang-team#123

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

"Generators (iterator functions), sync and async" lang-team#137

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

"Initiative: trusted external static declarations" lang-team#149

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

"agenda generation should include section with S-waiting-on-team + T-lang" lang-team#172

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

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

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

"Language design principles" lang-team#189

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

"discuss/resolve fn { mod { (use) super::...; } } and its interaction with derive patterns" lang-team#193

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

"lang agenda generator ignores lang-nominated closed issues" lang-team#199

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

"The #[diagnostic] attribute namespace" lang-team#204

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

"Rust 2024 survey" lang-team#209

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

"Extern types V2 RFC" lang-team#211

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

"Capturing lifetimes in impl Trait" lang-team#215

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

"RFC review Inherent Trait Impls RFC#2375" lang-team#217

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

"RFC review: Add f16 and f128 float types RFC#3453" lang-team#218

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

"RFC review: MaybeDangling RFCS#3336" lang-team#219

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

"Design meeting: Decide about the future for consts in patterns" lang-team#220

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

"mdbook build and deploy is failing" lang-team#221

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

"We need to settle the behaviour of floating-point in const" lang-team#222

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

"Meeting proposal: Unsafe extern blocks" lang-team#223

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

"Design meeting: Implementable trait aliases" lang-team#224

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

"Design meeting: Rust issues encountered by new Rust users in the Bevy project" lang-team#229

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

"Nail down cargo-script syntax proposal" lang-team#232

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

"Design meeting: resolve ABI issues around target-feature" lang-team#235

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

"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

"Website broken" lang-team#238

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

Select a repo