--- title: "Lang/RfL meeting 2025-06-18" tags: ["T-lang", "design-meeting", "minutes"] date: 2025-06-18 discussion: https://rust-lang.zulipchat.com/#narrow/channel/410673-t-lang.2Fmeetings/topic/RfL.20meeting.202025-06-18/ url: https://hackmd.io/XjpxRmswSHGJdYgIYJUuvA --- # Lang/RfL meeting 2025-06-18 ## Attendance People: - TC - Alice Ryhl - Wesley Wiser - Boqun Feng - Benno Lossin - Miguel Ojeda - Josh Triplett - Tomas Sedovic Minutes: Tomas Sedovic ## Tracking [Tracking issue](https://github.com/rust-lang/rust-project-goals/issues/116) ## Stabilize derive(CoercePointee) (blocked on #136764 / #136776) Alice: The FCP finished, but there have been arguments taht it should be stabilised with arbitrary self types. Ding is working on that, hoped he'd be here. Miguel: Yes, hoped Ding would be here. People outside of RfL are also asking about this feature. Alice: The status of arbitrary self type: in the deref trait they have a type ?? and they want to move it to the supertrait of `Receiver`. TC: We had a lang design on some of the options. Jules has an RFC for implementable trait aliases. ## Stabilize arbitrary self types v2 (blocked on #136764 / #136776) Alice: part of teh same discussion. ## support for pointers with asm_const Support for pointers with asm_const rust#128464 Alice: Lang asked for an RFC, that hasn't happened yet. Gary: The implementation is ready. Need to write the RFC -- don't have a lot of time to write it. Not sure if that's blocking the merging of this as that's been feature gated. Gary: Can we get this merged and feature-gate it to start testing? Miguel: Good idea. Alice: RFC should be for stabilisation, so yes. TC: I'm okay with proceeding as a lang experiment on nightly. Gary: I'll find time to rebase this and hopefully we can get it on nightly. ## ABI-modifying compiler flags ### Target modifiers https://github.com/rust-lang/rust/issues/136966 Alice: Two remaining things: sanitizers [PR#138736](https://github.com/rust-lang/rust/pull/138736) and -Zharden-sls [PR#136597](https://github.com/rust-lang/rust/pull/136597). Alice: Jubilee did a review recently and we're waiting for azhogin to reply to Jubilee's review. ## `--crate-attr` (Configure no-std externally) The RFC entered FCP: https://github.com/rust-lang/rfcs/pull/3791 Miguel: When that goes in, we can start using it conditionally. It would be nice to keep the `-Zcrate-attr` for a few releases at least, but worst case we could do it even if it is replaced (and it works). ## Rustdoc features to extract doc tests Miguel: The rustdoc merged the PR so the new iteration of the new flag is now in. And we have a new patch on the kernel side. I took a quick look and I think it's what we want -- it removes all the hardcoded detauils we depended on from the rustdoc side. ## Clippy configuration Miguel: No change from last time ## `-Zsanitize-kcfi-arity` Miguel: no change. Alice: Nothing to talk about here until the sanitizers are stabilised. Miguel: I gave Peter a way to test them, haven't heard back yet. ## In-place initialization, pin projection, etc. Niko: I talked to Michael about async function in Pin traits and pin init. He's keen on working on this as an H2 2025 goal. I'd like to see motion here. Michael works best when pointed in a direction and left to knock down all the walls in his way. =) Alice: What Michael told me was: Ding was going to look at defining an Tnit trait and Michael is going to look into the async function in dyn trait side. *** TC: There's ongoing discussion about these two documents: - [In-place initialization - Alice Ryhl](https://hackmd.io/lUUKcfsFStip6u2AuciEqA) - [Field projections v3 - y86-dev](https://hackmd.io/7cqCHmDeR8OYkgF75i6NJQ) With discussion in: - <https://rust-lang.zulipchat.com/#narrow/dm/116883,158589,218683,239881,303710,434618,458499-group> - <https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/In-place.20initialization> One item I'd raise is that both of these touch on the expected behavior of pin projection (and they assume earlier proposals that used `#[pin]`). Frank King and Eric Holk have been doing work on pin ergonomics, which includes pin projection. Here are the rules I'd expect for that: - The type `&pin mut T` coerces to `&mut T` if `T: Unpin`. - The type `&mut T` coerces to `&pin mut T` if `T: Unpin`. - If `T: Drop`, then `impl !Unpin for T` is only allowed if `Drop` is implemented with `fn drop(&pin mut self)`. - Projection of `&pin mut T` to `&pin mut T.U` is allowed if `T: !Unpin`. - Projection of `&pin mut T` to `&mut T.U` is allowed if `U: Unpin`. I'm curious to hear to what degree the designs in the current draft documents on in-place initialiiization and generalized projection are able to work with this statement of rules. These rules are similar to Niko's MinPin rules, but with a different factoring that assumes coercions to achieve some of the desirable projections and handles the `drop` problem with a rule about when `!Unpin` can be implemented. Niko: Rules from [Niko's MinPin blog post](https://smallcultfollowing.com/babysteps/blog/2024/11/05/minpin/): The rules for field projection from a `s: &pin mut S` reference are based on whether or not `Unpin` is implemented: * Projection is always allowed for fields whose type implements `Unpin`. * For fields whose types are not known to implement `Unpin`: * If the struct S is Unpin, &mut projection is allowed but not pinned &mut. * If the struct S is !Unpin[^neg] and does not have a fn drop(&mut self) method, pinned &mut projection is allowed but not &mut. * If the type checker does not know whether S is Unpin or not, or if the type S has a Drop impl with fn drop(&mut self), neither form of projection is allowed for fields that are not Unpin. Benno Lossin: I think that sadly I found an unsoundness bug (see below; it's not unsound): ```rust struct Foo { bar: Bar } impl Unpin for Foo {} struct Bar; impl !Unpin for Bar; fn bad(x: &mut Foo) { let y: &pin mut Foo = x; let bar: &pin mut Bar = &pin mut y.bar; // <-- error from rule 4, or "If the struct S is Unpin, &mut projection is allowed but not pinned &mut" in Niko's post // ^^^ not actually pinned, but an `!Unpin` type :( } ``` Solutions: * make `Unpin` an `unsafe` trait * forbid projections when manual `Unpin` impls are in play * don't use type-direction for pin-projections Alice: The projections and the Unpin impl may not play well together. TC + Alice: The example there does not work because of the second to last rule that requires that `T: !Unpin`. Benno: I think TC & Alice you're correct, this is fine. Alice: If the field is `Unpin`, then an initializer for that field must implement `Init` (and not just `PinInit`) TC: What's the necessity for `Init`? Alice: An initializer always implements `PinInit` and `Init` is an optional trait that it can implement. Benno: If it implements `Init`, the value isn't guaranteed `Pin` after that. E.g. if you want to have a big `u8` array you can use that. TC: Obviously you need `PinInit`. But for `Init` do you actually need it? Benno: Doing just `PinInit` does fit better with the type-directed projection rules. Right now we're using a field-specified projection rule. Even if a field is unpinned, you're not allowed to use a reference. If we go the type-directed route we may only need one trait. Alice: The `PinInit` field is only useful for the C++ and Rust for Linux case. Benno: If we only have one trait, a future can only be Pin initialised. Example: putting ?? in a vector. TC: This is something else we were talking about. If I had to do this I'd put async closures in a vector. Benno: You can also have a struct that's always unpin. Alice: join all doesn't require Unpin. ```rust= async fn foo<F>( mut gen_future: impl FnMut() -> impl Init<F>, // **must** use `Init` and cannot be `PinInit`, // since the vector might grow (and thus reallocate) below mut merge: impl FnMut(F::Output, F::Output) -> F::Output ) -> F::Output where F: Future { let mut vec = Vec::new(); for _ in 0..100 { vec.push_init(gen_future()); } let result: Vec<F::Output> = join_all(vec).await; result.into_iter().reduce(merge).unwrap() } ``` Gary: We've already mentioned that structs can be either pin or unpin. When we say something is init or uninit it depends on whether it's pin/unpin. TC: It's still the same structural pinning rule; we're not changing the `Pin` contract. We're just allowing certain safe projections. Alice: You have this ForceUnpin type you want to wrap the field in. You can never use an initializer for that type. TC: Don't return the addres-sensitive type but a constructor for the address-sensitive type (`IntoFuture`) -- or the closure-like initializer. Alice: Let's say we use `Unpin` to determine whether the initializer creates a pinned type. Then, we only have the `PinInit` trait left (but maybe we rename it to `Init`). The trait we called `Init<T>` becomes `PinInit<ForceUnpin<T>>`. TC: What I'm saying is: this init syntax already creates a closure-like thing. Why are you creating the value early when you can return the initializer later and only call it when you're ready to pin it. Defer the execution. Alice: Then I'd have to create a vector of initializers and then another vector of the pinned types. And the initializers better be the same type since `Init` is not dyn-compatible. Alice: I don't know how common this is but I don't think there are zero such cases. Benno: But the alternative is just to have the `Init` and `PinInit`. TC: But then there is then that tension in the model. Alice: We should write up a document; we now have two competing lang experiments. TC: That's why I wanted to bring it to your awareness. TC: The active PRs on the lang experiment include: - https://github.com/rust-lang/rust/pull/139751 - https://github.com/rust-lang/rust/pull/135731 - https://github.com/rust-lang/rust/pull/135631 And the tracking issue is: - https://github.com/rust-lang/rust/issues/130494 --- Miguel: We have someone who wanted to contribute to the compiler. They were okay working on some RfL related compiler flag. Is there someone to mentor, something to give them? Zulip name is: @rperier