--- title: Triage meeting 2021-08-17 tags: triage-meeting --- # T-lang meeting agenda * Meeting date: 2021-08-17 ## Attendance * Team members: nikomatsakis, Scott, Felix, Josh * Others: Mark, Mara, Ryan ## Meeting roles * Action item scribe: simulacrum * Note-taker: nikomatsakis ## Scheduled meetings - "Structural equality" [lang-team#94](https://github.com/rust-lang/lang-team/issues/94) ## Action item review * [Action items list](https://hackmd.io/gstfhtXYTHa3Jv-P_2RK7A) ## Special section: Stabilization and Rust 2021 Edition * Want to release the 2021 Edition in Sep * Contents: https://doc.rust-lang.org/nightly/edition-guide/index.html * It contains three lang features that are not stabilized * RFC 2229: Disjoint capture in closures * Need a stabilization report * There is an update to the reference * https://github.com/rust-lang/reference/pull/1059 * Josh: Biggest concern would be cementing semantics that have not been sufficiently reviewed and experimented with. People may have Curse-of-Knowledge and not have visibility into the semantics. * Ways to gain confidence: * Measurements of closure sizes (no noticeable increase) * Porting compiler and standard library * Public testing phase of the edition * Mark: The kind of feature that you don't notice, so no news is -- in some sense -- good news * Josh: Yes, the question is more, if you're finding yourself in the space. * Niko: I see a few options here * we can do an emergency meeting to talk things over * we can write up the stabilization report and see how people feel after they read it * Josh: Having some thoughts about Rust 2018, where we spend quite a bit of time on cleanup nailing down the semantics etc last minute. This is one of the larger features that may have more surprising interactions. I don't think we've gone over the details very carefully. A subset of group has been going over diligently but not the group as a whole. * Niko: How do you propose moving forward? * Josh: Stabilization report would help. Can we get that this week? * Niko: I think we could get that ready by tomorrow if desired. * Josh: Could replace tomorrow's meeting, although this is last minute. Could try doing something on Zulip to go over the details. * Niko: I think a sync meeting would be best to really get understanding. * Josh: When is branch for 1.56? * Mara: 17 days from now. * Josh: Hence we have to start it tomorrow, if we want an FCP. * Tomorrow's meeting is spoken for -- today's agenda, though, is fairly light. If information is readily available, we could talk about it for 20 minutes and see if we want to talk more tomorrow * OK, plan is to start at the half hour. * Reserved prefixes * Force-warn (in FCP, later in this agenda) * Already stabilized * Or patterns in macro rules * Warnings promoted to errors ## Pending lang team project proposals ### "MCP: Allowing the compiler to eagerly drop values" lang-team#86 **Link:** https://github.com/rust-lang/lang-team/issues/86 ### "negative impls integrated into coherence" lang-team#96 **Link:** https://github.com/rust-lang/lang-team/issues/96 ### "Trait Upcasting" lang-team#98 **Link:** https://github.com/rust-lang/lang-team/issues/98 ### "Deprecate target_vendor " lang-team#102 **Link:** https://github.com/rust-lang/lang-team/issues/102 ### "Non exhaustive reachable patterns lint" lang-team#112 **Link:** https://github.com/rust-lang/lang-team/issues/112 * Discussion about semver: * Josh points out that if a library creates a non-exhaustive enum and an app uses this with deny, it will stop compiling when a new variant is added * But others point out this is "working as designed", and is no different from (for example) a library deprecating one of its functions (and an app using deny(deprecated)) -- in short, the reason to deny is because you WANT errors, but we never want to give errors in code you don't control. * Let's explicitly state that this does not make non-breaking changes into breaking changes, and then accept this. * Mara: Maybe ping the libs API team? * Josh: Sounds reasonable. Do you mean on the PR? This is just the project proposal to develop the PR. * Mara: Maybe better now, in case any major concerns arise before the code is already written...? * Josh: Sounds good. We can also cc them into a Zulip stream. * Conclusion: * Accept project * cc libs-api (and note that they should be CCed on subsequent GitHub and Zulip discussions) * Document that adding new variants is not considered a major semver change *even though* projects may use deny(reachable) * Josh/Niko take the action item ## PRs on the lang-team repo ### "Initial draft of copy ergonomics design note" lang-team#62 **Link:** https://github.com/rust-lang/lang-team/pull/62 ### "Autoref/autoderef for operators" lang-team#63 **Link:** https://github.com/rust-lang/lang-team/pull/63 ### "Add draft of variadic notes" lang-team#76 **Link:** https://github.com/rust-lang/lang-team/pull/76 ### "consensus decision making" lang-team#113 **Link:** https://github.com/rust-lang/lang-team/pull/113 ## RFCs waiting to be merged ### "RFC: Supertrait item shadowing" rfcs#2845 **Link:** https://github.com/rust-lang/rfcs/pull/2845 ## Proposed FCPs **Check your boxes!** ### "RFC: Add `target` configuration" rfcs#2991 **Link:** https://github.com/rust-lang/rfcs/pull/2991 ### "Tracking issue for RFC 2523, `#[cfg(version(..))]`" rust#64796 **Link:** https://github.com/rust-lang/rust/issues/64796 ### "Stabilize "force warn" option " rust#86516 **Link:** https://github.com/rust-lang/rust/issues/86516 - **Time-sensitive** -- related to 2021 Edition - Adds an option to require that a lint emit a warning - Used by rustfix to force migration lints, no matter what users have done - Now in FCP (:tada:) - One open question: - `--force-warn warnings` -- what does this mean? - Josh: Maybe we want to rule them out - Ryan: the semantics as implemented are basically... - ...if anything were to ever warn, then force-warn will cause it to warn - Meaning if there is a lint that is a warn in one part of the code, but which is allowed in some other part of the code, the lint will fire as a warning in all parts - Suppose foo is an allow-by-default lint. - command-line: -A foo --force-warn foo - module X: #[warn()] - module Y: #[allow()] - get warnings in both X and Y - Josh: do you mean that it will only warn if there is a warn *somewhere*? - Niko: if you had - module X: #[allow] - module Y: #[allow] - should still get warnings in both X and Y - Ryan: yes, we are saying, there is nothing you can do to change "foo" from being a warning - Mark: "or worse"? - Ryan: yes, or worse - Josh: YAFIYGI - Niko: motivation was that we wanted `cargo fix` to work for people using `#![allow(warnings)]` - Ryan: Tricky part is something like `--force-warn warnings` - Niko: last time we discussed warnings it was clear that "warnings" shouldn't be considered a lint group, it's more of its own thing - Josh: Let's just prohibit `--force-warn warnings` for now; we can always define semantics later ### "Support `#[track_caller]` on closures and generators" rust#87064 **Link:** https://github.com/rust-lang/rust/pull/87064 ## Active FCPs ### "negative impls integrated into coherence" lang-team#96 **Link:** https://github.com/rust-lang/lang-team/issues/96 ### "Trait Upcasting" lang-team#98 **Link:** https://github.com/rust-lang/lang-team/issues/98 ### "Non exhaustive reachable patterns lint" lang-team#112 **Link:** https://github.com/rust-lang/lang-team/issues/112 ## P-critical issues None. ## Nominated RFCs, PRs and issues ### "Stabilize "force warn" option " rust#86516 **Link:** https://github.com/rust-lang/rust/issues/86516 - Time-sensitive. ### "Make `#[derive(A, B, ...)]` cfg-eval its input only for `A, B, ...` and stabilize `feature(macro_attributes_in_derive_output)`" rust#87220 **Link:** https://github.com/rust-lang/rust/pull/87220 ### "Stabilize built-in attribute macro `#[cfg_eval]`" rust#87221 **Link:** https://github.com/rust-lang/rust/pull/87221 ### "Niches of `Cell` and others still not hidden" rust#87341 **Link:** https://github.com/rust-lang/rust/issues/87341 ### "Which patterns on union fields should be considered safe?" rust#87520 **Link:** https://github.com/rust-lang/rust/issues/87520 ## Special RFC 2229 semantics discussion [Reference guide PR](https://github.com/rust-lang/reference/pull/1059) Main question: What gets captured when you write a closure in Rust 2021? * Observatin: * This transformation affects MIR desugaring * But not the borrow checker * Axioms: * When taking ownership of a value, either in a move closure or for a specific upvar gets moved: * Only move bytes from the enclosing stack frame * This is true in Rust today, and it's a property RFC 2229 preserves * See example 1 * In Move Closures, we sometimes capture by reference * See example 2 * Unsafe code * Any operation that would be unsafe happens in the closure, not creator of the closure * More precise about irrefutable patterns * Ordering of drop could change * `let _ = &b // inert way to access a variable` * forces a capture of an entire variable without otherwise affecting semantics * Optimization around `&T` * significant `Drop`: * annotation when the `Drop` is not significant * just affects migration * attributes to indicate significance not stable, just for stdlib * Comfortable shipping without this, but it would improve the quality of migrations Example 1: ```rust let b: Box<[u8; 1024]> = Box::new([0; 1024]); let c = move || drop(*b); // path that gets used is `*b` // but the path that gets *captured* is `b` ``` Example 2: ```rust let b: &mut (String, String) = ("hello".to_string(), "world".to_string()); let c = move || b.0.truncate(0); // desugars to a `&mut b.0` // Rust 2018: capture `b` by value, which means we capture an `&mut (String, String)` // Rust 2021: capture `b.0` **by mutable reference*, which means we capture a `&mut String` b.1 = "some new string".to_string(); // allowed in Rust 2021, but not in Rust 2018 b = (some_other_string, some_other_other_string); // not allowed in either Rust 2018 or Rust 2021 ``` Example 3: ```rust let b: *mut (String, String) = ("hello".to_string(), "world".to_string()); let c = move || unsafe { (&mut *b).0.truncate(0) }; // closure borrows `*b` with `&mut` // Rust 2018: capture `b` // Rust 2021: also capture `b` because `*b` is unsafe // other examples: accessing fields of packed structs b.1 = "some new string".to_string(); // allowed in Rust 2021, but not in Rust 2018 b = (some_other_string, some_other_other_string); // not allowed in either Rust 2018 or Rust 2021 ``` Example 4: ```rust let b: &(String, String) = ("hello".to_string(), "world".to_string()); let c = move || drop((&b.0, &b.1)); // whenever you have multiple paths that capture data owned by (referent of) a shared reference, just capture the reference instead // Rust 2018: captured just `b` // Rust 2021: we will also capture just `b` (instead of two references, one to `b.0` and one to `b.1`) let b: & &'static String; let c = || drop(**b); // Rust 2018: captures by shared ref // Rust 2021: capture `**b` by shared ref (means that `c: 'static') ``` ```rust let b: (String, String, String) = ("hello".to_string(), "world".to_string()); let c = move || drop((&b.0, &b.1)); // Does this capture b? b.2.make_ascii_lowercase(); // allowed? yes ``` Example 5: ```rust let b = 0i32; let c = || { let _ = b; // this just ignores `b` // Rust 2018: capture `b`, beacuse we are looking at what gets named // Rust 2021: capture nothing at all because `b` is not really used }; ``` Non-exhaustive: ``` // crate A #[non_exhastive] enum Foo { Bar } // crate B let c = match foo { Foo::Bar => ... }; // does this capture `foo` or not? ``` Irrefutable, but exhaustive: ```rust= enum Foo { A } enum Bar { A, B } let a = Foo::A; let b = Bar::A; let c = || { let Foo::A = a; // this just ignores `a` let Bar::A | Bar::B = b; // this *does not* ignore b -- because it is not univariant. }; ``` ### Questions - Josh: Do these same semantics apply to what gets captured when you write an async block, or in the future an async closure? Can we apply uniform semantics to all of them? (We don't want to have subtly different semantics.) - Mark: [wildcards](https://github.com/rust-lang/reference/blob/6b88e48ffebc46be91884ef6237accb947e5f6f3/src/types/closure.md#wild-card-patterns) seems to be potentially problematic from our unsafe-code checking discussions with unions, where we noted that wildcards can be a little ambiguous with today's semantics - `#[repr(u8)] enum Foo { Bar } match foo { Foo::Bar => {} }` - `#[repr(u8)] enum Foo { Bar, Baz } match foo { Foo::Bar | Foo::Baz => {} }` which *technically* doesn't have a read, but if you imagine s/enum/union, might want one in the future. - https://github.com/rust-lang/rust/issues/87520 - https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/union.20field.20semantics.20and.20safety ### Next steps - If a stablization report is posted, and we started an FCP, does anyone feel uncomfortable without further sync discussion? - Scott: PFCP'ing seems clear - Josh: I may have more questions, but I can ask them asynchronously during PFCP - Conclusions: - Fix the non-exhaustive bug above - Decide whether to make `Foo::A` always treated as a read