---
title: Triage meeting 2021-07-13
tags: triage-meeting
---
# T-lang meeting agenda
* Meeting date: 2021-07-13
## Attendance
* Team members: nikomatsakis, Josh, Taylor
* Others: simulacrum
## Meeting roles
* Action item scribe: simulacrum
* Note-taker: nikomatsakis
## Scheduled meetings
- 2021-07-21 / "Lang team process, part 2" [lang-team#104](https://github.com/rust-lang/lang-team/issues/104)
- 2021-07-28 / "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)
## 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
* In progress lang-team design note - https://github.com/rust-lang/lang-team/pull/103
* No discussion necessary.
### "negative impls integrated into coherence" lang-team#96
**Link:** https://github.com/rust-lang/lang-team/issues/96
* Need to identify liaision and/or owner.
* Niko wanted to discuss at planning meeting, but that didn't happen.
### "Trait Upcasting" lang-team#98
**Link:** https://github.com/rust-lang/lang-team/issues/98
* Discussion point: seconded, but before new initiative process. not clear owner/liaision. May just need to get "merged".
### "Discontinue meeting recordings" lang-team#100
**Link:** https://github.com/rust-lang/lang-team/issues/100
* Needs to be closed -- seems to be no action item?
### "Deprecate target_vendor " lang-team#102
**Link:** https://github.com/rust-lang/lang-team/issues/102
* Not yet seconded; discussion seems in-progress.
## New PRs on the lang-team repo
### "add design notes from lang-team#86 (eager drop)" lang-team#103
**Link:** https://github.com/rust-lang/lang-team/pull/103
### "introduce new lang team "initiatives" process" lang-team#105
**Link:** https://github.com/rust-lang/lang-team/pull/105
## RFCs waiting to be merged
* joshtriplett: This is a very manual process, can we optimize it a little more?
### "RFC: Overconstraining and omitting `unsafe` in impls of `unsafe` trait methods" rfcs#2316
**Link:** https://github.com/rust-lang/rfcs/pull/2316
### "RFC: Supertrait item shadowing" rfcs#2845
**Link:** https://github.com/rust-lang/rfcs/pull/2845
### "`#[derive(Default)]` on enums with a `#[default]` attribute" rfcs#3107
**Link:** https://github.com/rust-lang/rfcs/pull/3107
### "RFC: let-else statements" rfcs#3137
**Link:** https://github.com/rust-lang/rfcs/pull/3137
- has a concern for the author to add a bit more text to unresolved questions and alternatives
## Proposed FCPs
**Check your boxes!**
### "RFC: Add `target` configuration" rfcs#2991
**Link:** https://github.com/rust-lang/rfcs/pull/2991
* Blocked on author of the RFC writing up the alternative syntax.
### "Tracking issue for RFC 2523, `#[cfg(version(..))]`" rust#64796
**Link:** https://github.com/rust-lang/rust/issues/64796
* Blocked on impl of a subset of cfg-accessible.
* Related to https://github.com/rust-lang/cargo/pull/9601
* This PR supplied compiler version to build scripts, among a bunch of other things
* But author is willing to defer
### "Stabilize `arbitrary_enum_discriminant`" rust#86860
**Link:** https://github.com/rust-lang/rust/pull/86860
* Needs checkboxes. joshtriplett / scottmcm, get on that!
## Active FCPs
### "Add `expr202x` macro pattern" rust#84364
**Link:** https://github.com/rust-lang/rust/pull/84364
### "Stabilize `const_fn_transmute`, `const_fn_union`" rust#85769
**Link:** https://github.com/rust-lang/rust/pull/85769
* Ralf wanted to make us aware of the implications here
* [Thread on Zulip](https://zulip-archive.rust-lang.org/213817tlang/18226Stabilizeconstfntransmuteconstfnunion.html)
* Net effect:
* This is the first time that you can have non-deterministic const fn (requires unsafe)
* in principle you could do it with `const fn foo() -> usize { let x = 5; &x as usize }` too
* e.g. by transmuting a pointer to an integer
* at runtime: nondeterministic
* at compilation time:
* today, this function compiles: `const unsafe fn foo() -> usize { let x = 5; std::mem::transmute(&x as *const _) } `
* in general you can pass around pointers that became integers but cannot do much with them
* there is some discussion about just how much you should be allowed do with them; e.g., can you mask off and embed data in the low-order bits?
* Key point:
* In the past, we might've assumed that `const fn` implied purity and determinism, but this is not true given this change.
* Now it might be observable
* nikomatsakis: Note that the `x as usize` could be unsafe in a const fn, particularly if you take the approach [ralf advocates here](https://www.ralfj.de/blog/2018/07/19/const.html)
* joshtriplett: presently, everything that would allow nondeterminism is unsafe; if we go fwd here, we still have the option of maintaining the invariant that nondeterminism requires unsafe
* making `as` const (and safe) would be another step
```rust=
#![feature(const_fn_transmute)]
const unsafe fn foo() -> usize { let x = 5; std::mem::transmute(&x as *const _) } // compiles today
```
### "Deprecate target_vendor " lang-team#102
**Link:** https://github.com/rust-lang/lang-team/issues/102
### "introduce new lang team "initiatives" process" lang-team#105
**Link:** https://github.com/rust-lang/lang-team/pull/105
## T-lang P-critical issues
## Nominated RFCs, PRs and issues
### "Fix how allow/warn/deny/forbid `warnings` is handled" rust#85298
**Link:** https://github.com/rust-lang/rust/pull/85298
* The warnings "lint group" is currently implemented in a surprising way:
* Basically, it becomes a kind of "ambient" setting, so that when a lint would *otherwise* be a warning, it gets changed to the level of the warnings group
* Downside is: you cannot override it
```rust=
#[warn(unused)]
#[deny(warnings)]
fn main() {
#[warn(unused_variables)]
let a = 5; // Still gets an error
}
```
[yields](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=34bca059e0d41ba8de80200c58384db7)
```
error: unused variable: `a`
--> src/main.rs:5:9
|
5 | let a = 5; // Still gets an error
| ^ help: if this is intentional, prefix it with an underscore: `_a`
|
note: the lint level is defined here
--> src/main.rs:2:8
|
2 | #[deny(warnings)]
| ^^^^^^^^
= note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]`
```
* The PR changes this so that lint level declarations that are "inside" the `warnings` take precedence.
* Things that come at the same level, but "later" take precedence
```rust=
#[warn(unused)]
#[deny(warnings)] // Same depth, greater position (in the attributes list), overrides `warn(unused)`
fn main() {
#[warn(unused_variables)] // Greater depth, overrides `deny(warnings)`
let a = 5;
}
```
* Question for *lang team*:
* What behavior do we want here?
* What backwards compatibility concerns to consider?
```rust=
#![warn(some_allow_lint)]
#[deny(warnings)] // includes `some_allow_lint`
fn foo() {
// error if allow_lint trigger, under this PR
}
```
```rust=
#![deny(warnings)]
#[warn(some_allow_lint)] // warning becomes deny?
fn foo() {
// warning, under this PR
}
```
```rust=
#![deny(some_allow_lint)]
#[warn(some_allow_lint)] // warning becomes deny?
fn foo() {
// warning, today
}
```
* cramerj: I would expect `deny(warnings)`, at the crate level, to mean that no warnings would be emitted
* scottmcm: if you think of deny warnings as its own thing, that makes sense, but if you think of it as a lint group, not
* joshtriplett: the behavior I have seen people expect is that they are searching for the equivalent of `-Werror` from a C compiler; which is to say, if I would ever get a warning, stop and die instead.
* We introduce the idea of doing it at a scope level.
* But in general the behavior I think people expect is "I don't care where you list it, I want every warning to become an error"
* cramertj: this matches my intuition, I have learned to read `deny(warnings)` as `-Werror`
* pnkfelix: (double-check: you can do `#[warn(warnings)]` to undo Taylor's hypothesis, right?)
[Example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=eadfde1e2241d2c919fdad35be118e4d)
```
#![deny(warnings)]
#[warn(warnings)]
fn main() {
let x = 5;
}
```
yields a warning.
* joshtriplett: You could do `-Fwarnings` if you want to prevent that.
* cramertj: When I do `Dwarnings` I want it to act like `-Werror` -- that is, unless the lint is *allowed*, I should see an error
* (allow is ok because it makes no warning at all)
* nikomatsakis: I had never even considered the idea that this was not a group of lints; I think if we want `-Werror` we should add *that* instead
* cramertj: yes, I think that is what I would want
* simulacrum: also things that are not lints, right? we have some hardcoded warnings
* cramertj: I'm thinking of this in "cargo-less" systems for the most part, and I want to ensure that when somebody does a build of a big repository with a bunch of targets that they depend on but don't control, they don't see a bunch of things about code that they don't own
* nikomatsakis: isn't that cap-lints?
* cramertj: no, I want *hard errors* (min. lint level). I work in a giant monorepo. What happens when I go to build my target is that it is also building a bunch of std libraries maintained by other people I don't know. Their code isn't necessarily logically separated from mine in the build system, so they will receive the same set of compiler flags as my code does, because we don't have a distinction between internal/external dependencies. What I *want* is to ensure that any code that lands in that repository is not giving warnings or command line messages to downstream consumers.
* That means: if it would've triggered a lint, it gets fixed before it goes in.
* Once it's in, I want people to never see any warnings on the command line because there are no warnings.
* joshtriplett: this matches my intuition as well. It had never occurred to me that somebody could allow warnings.
* Makes me tempted to forbid.
* cramertj: that's too strong, because sometimes you want to allow specific warnings.
* joshtriplett: I thought we had a conversation a long time back about how forbid and lint groups behaves. I thought that if you forbid a group, it doesn't necessarily mean that you forbid each lint? I can't remember.
* (nobody can remember)
* in any case, I would like the ability to say "I want all warnings to be errors" and "I can still override individual warnings by name"
* joshtriplett: I think that based on the behavior cramertj and I expect, that would argue for closing this PR?
* nikomatsakis: It's not quite, right? It's neither at present.
* cramertj: I think the outcome was that we should think of `warnings` as a lint group...?
* simulacrum: but it works today and a lot of people rely on it
* pnkfelix: https://github.com/rust-lang/rust/issues/81218 seems like the issue that josh was talking about
* seems like we didn't come to any concrete conclusions
* pnkfelix: https://github.com/rust-lang/rust/pull/81556 : we decided to Future-compatibility-warn on a `forbid(group)` followed by `allow(indvidual)`.
* nikomatsakis: I am surprised you all thought it was a mode, but I think right now it's like half a lint group and half a mode, and I think we should make it be one or the other. We might want to disallow e.g. `#[warn(foo)]`.
* joshtriplett: what is the semantics/use case for it acts like a lint group?
* scottmcm: I would expect it to act "as if" you had typed the names of the lints; I would think it would work like the other lint groups that is a pre-defined set, and warnings it short-hand for the "things that say will warn by default".
* nikomatsakis: that is what I would've expected, but I am ok with saying "Warnings is not a lint group, don't think of it that way", just to avoid churn. I don't really have a use case for this. But then we should clarify and make it do that job better.
* pnkfelix: my intuition is that warnings as a "normal lint group" would side-step a lot of thorny semantic questions, and could add separate flag to get what Taylor et al want.
* If we didn't take that approach, though, and we left the current behavior, we could lint on `allow(warnings)` or `warn(warnings)`.
* cramertj: wait, is this lint warn?
* pnkfelix:
* cramertj:
* pnkfelix:
* C-c
* joshtriplett: I think documenting current behavior and warning where it diverges from `-Werror` would be good
* 1) Warn if you `#[warn(warnings)]` or `#[allow(warnings)]` when `#[deny(warnings)]` is active.
* This will actually error unless `-Acap-lints` is involved...
* 2) Warn if you `#[warn(lint)]` (on a warn or deny lint, not an allow lint) inside of a `#[deny(warnings)]`. (Note that people almost never seem to `#[warn(x)]`.)
* simulacrum: the second case, putting `#[warn]` inside of `#[deny(warnings)]`, is something that rustc relies upon as a feature
* josh: Then given that people almost never do it otherwise "in the wild", we don't need to worry about warning on it
* pnkfelix: we could do a FCW for case (1), right?
* nikomatsakis: but why? no soundness reason?
* pnkfelix: If we don't warn about (2), wouldn't cramertj not get his property?
* simulacrum: second case will issue an error today, so cramertj is happy
* joshtriplett: I would only do (2) specifically for the case where `lint` was deny-by-default
* this is the case that doesn't behave like a lint group
* The user was trying, presumably, to "downgrade" from a deny-to-a-warn
* nikomatsakis: I would prefer not to do (2) because it disables a potential use case
* It seems like the use case is "issue warnings" when I'm building locally, and hard errors on CI
* And that might be what people wanted for the deny-by-default lint too
* Consensus:
* Close this PR, working as intended
* Request documentation
* simulacrum: wait, I use `allow(warnings)` all the time
* nikomatsakis: oh, yes, so do I, but in that case the behavior doesn't match what I would want:
* scottmcm: Hmm, a place where the "it's a lint group" might be valuable is `#![allow(warnings)]` on the crate but `#[warn(warnings)]` again on a particular method. (Not that I think I'd ever recommend that.)
```
#![allow(warnings)]
#[warn(unused_variable)]
fn foo() {
let x = 3; // This doesn't warn (I checked) and that's weird
(in scott's opinion, because of the scoping)
// counterpoint: simulacrum thinks this shouldn't warn indeed
}
```
* cramertj: It might be that there was a bunch of warnings and you added `#![allow(warnings)]` to make it stop
### "Allow limited transmuting between types involving type parameters" rust#86281
**Link:** https://github.com/rust-lang/rust/pull/86281
OP:
> Before this change, functions could never perform transmutes between types which involve type parameters.
>
> This opens up slightly less limited analysis whereby certain types involving `Sized` type parameters can be considered relative to each other, even if the exact size of that type parameter isn't yet known because monomorphization hasn't happened yet. Specifically it allows:
> 1. `repr(transparent)` types to be considered to have the same size as the `Sized` type they wrap.
> 2. Arrays of type parameters (or `repr(transaprent)` wrappers thereof) to be considered to have the same size as other arrays of the same type parameters (or `repr(transparent)` wrappers thereof), as long as their element count is the same.
>
> It only supports very limited comparisons, but it opens up more safe and legal transmutes than were previously allowed.
>
> In particular, it allows for transmutes like:
> ```rust
> fn make_array<T, const N: usize>() -> [T; N] {
> let mut values: [MaybeUninit<T>; N] = unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() };
> // [... Init values]
> std::mem::transmute(values)
> }
> ```
> which are currently not allowed because `[T; N]` isn't considered to have the same size as `[MaybeUninit<T>; N]`
>
> Fixes #61956.
scottmcm comments:
> Personally I'm torn here. On one hand, I think this would be quite useful. On the other hand, I worry that this might make it harder to make transmute non-magic.
>
> Maybe someone from the const WG has an idea about whether this would make it harder to encode the "sizes are the same" check as a "real" type system predicate instead of intrinsic magic?
>
> For the specific example in the OP, one way forward would be to just stabilize https://doc.rust-lang.org/nightly/std/mem/union.MaybeUninit.html#method.array_assume_init (or something like it).
### "Associated functions that contain extern indicator or have `#[rustc_std_internal_symbol]` are reachable" rust#86492
**Link:** https://github.com/rust-lang/rust/pull/86492
* [Discussed in previous meeting](https://github.com/rust-lang/lang-team/blob/master/minutes/2021-07-06.md#associated-functions-that-contain-extern-indicator-or-have-rustc_std_internal_symbol-are-reachable-rust86492)
* TL;DR
* `#[no_mangle]` on an inherent method currently is not considered reachable, but is allowed
* Clear that we have a couple of stabs in a larger design space
* Options:
* Support `#[no_mangle]` on inherent methods; symbol has name of method; make it be considered reachable
* Disallow it, permit only on top-level functions, and address more broadly
* No real loss of expressiveness either way
### "Fix autoborrowing when coercing to a mutable raw pointer" rust#86647
**Link:** https://github.com/rust-lang/rust/pull/86647
From last meeting:
> Discussed in the @rust-lang/lang team meeting today. We weren't really sure what is being proposed here! @scottmcm is going to follow up and try to figure out how to describe the effects of this proposed PR on the language itself.
### "Allow reifying intrinsics to `fn` pointers." rust#86699
**Link:** https://github.com/rust-lang/rust/pull/86699
Niko summarized:
> I'm tagging this as T-lang and nominating, as it seems like a lang change. It'd perhaps be nice to write up a lang proposal or something that summarizes it. It's a short PR. The details are:
>
> * The type of an intrinsic like `transmute` is a zero-sized function type.
> * Under this PR, it can be coerce to an `extern "Rust"` function pointer
> * This will create a wrapper around the intrinsic.
> * This mechanism is 'insta-stable', but the only stable intrinsic is believed to be `transmute`.
### "Allow labeled loops as value expressions for `break`" rust#87026
**Link:** https://github.com/rust-lang/rust/pull/87026
> Nominated for @rust-lang/lang. I believe what is being proposed here is a change to the grammar. I believe the grammar would be something like this:
>
> ```
> BreakExpr :=
> 'break'
> 'break' lifetime Expr
> 'break' Expr
>
> Expr :=
> lifetime: 'loop'
> ...
> ```
>
> In other words, you can write `break 'foo: loop { .. }`. I would sort of expect this to work but I guess it didn't, presumably because of a parser bug. (I've not read the code closely.)
>
> Does this sound correct?
scottmcm adds:
> Given that this works with `return` already, I'd personally consider this a bug, and that it was probably expected to work this way the whole time.
>
> (It seems like it's an easy mistake to make, since `return try { ... }` didn't use to work either, https://github.com/rust-lang/rust/pull/76274 .)
### "Support `#[track_caller]` on closures and generators" rust#87064
**Link:** https://github.com/rust-lang/rust/pull/87064
> This PR allows applying a `#[track_caller]` attribute to a
> closure/generator expression. The attribute as interpreted as applying
> to the compiler-generated implementation of the corresponding trait
> method (`FnOnce::call_once`, `FnMut::call_mut`, `Fn::call`, or
> `Generator::resume`).
>
> This feature does not have its own feature gate - however, it requires
> `#![feature(stmt_expr_attributes)]` in order to actually apply
> an attribute to a closure or generator.
>
> This is implemented in the same way as for functions - an extra
> location argument is appended to the end of the ABI. For closures,
> this argument is *not* part of the 'tupled' argument storing the
> parameters - the final closure argument for `#[track_caller]` closures
> is no longer a tuple.
>
> For direct (monomorphized) calls, the necessary support was already
> implemented - we just needeed to adjust some assertions around checking
> the ABI and argument count to take closures into account.
>
> For calls through a trait object, more work was needed.
> When creating a `ReifyShim`, we need to create a shim
> for the trait method (e.g. `FnOnce::call_mut`) - unlike normal
> functions, closures are never invoked directly, and always go through a
> trait method.
>
> Additional handling was needed for `InstanceDef::ClosureOnceShim`. In
> order to pass location information throgh a direct (monomorphized) call
> to `FnOnce::call_once` on an `FnMut` closure, we need to make
> `ClosureOnceShim` aware of `#[tracked_caller]`. A new field
> `track_caller` is added to `ClosureOnceShim` - this is used by
> `InstanceDef::requires_caller` location, allowing codegen to
> pass through the extra location argument.
>
> Since `ClosureOnceShim.track_caller` is only used by codegen,
> we end up generating two identical MIR shims - one for
> `track_caller == true`, and one for `track_caller == false`. However,
> these two shims are used by the entire crate (i.e. it's two shims total,
> not two shims per unique closure), so this shouldn't a big deal.
### "Clarify "string continue" for (byte) string literals" reference#1042
**Link:** https://github.com/rust-lang/reference/pull/1042
> The previous version just said "whitespace at the beginning of the next
> line is ignored", but that is not quite correct. Currently, exactly four
> characters are ignored in that position. This is different from the
> definition of `char::is_whitespace` and `char::is_ascii_whitespace`.
>
> Additionally "at the beginning of the next line" is confusing as
> additional \n are also ignored.
>
> See the lexer implementation:
>
> https://github.com/rust-lang/rust/blob/595088d602049d821bf9a217f2d79aea40715208/compiler/rustc_lexer/src/unescape.rs#L281-L287
>
> https://github.com/rust-lang/rust/blob/595088d602049d821bf9a217f2d79aea40715208/compiler/rustc_lexer/src/unescape.rs#L300-L307