rust icon indicating copy to clipboard operation
rust copied to clipboard

Stabilize `let else`

Open est31 opened this issue 3 years ago • 108 comments

:tada: Stabilizes the let else feature, added by RFC 3137. :tada:

Reference PR: https://github.com/rust-lang/reference/pull/1156

Filing a draft as it is still subject to FCP approval.

closes #87335 (let else tracking issue)

FCP: https://github.com/rust-lang/rust/pull/93628#issuecomment-1029383585

Status: Blocked on FCP, which is blocked on #98672 being fixed as well as on https://github.com/rust-lang/rust/issues/87335#issuecomment-1184114137 . Fixes are proposed: #99291 and #99954


Stabilization report

Summary

The feature allows refutable patterns in let statements if the expression is followed by a diverging else:

fn get_count_item(s: &str) -> (u64, &str) {
    let mut it = s.split(' ');
    let (Some(count_str), Some(item)) = (it.next(), it.next()) else {
        panic!("Can't segment count item pair: '{s}'");
    };
    let Ok(count) = u64::from_str(count_str) else {
        panic!("Can't parse integer: '{count_str}'");
    };
    (count, item)
}
assert_eq!(get_count_item("3 chairs"), (3, "chairs"));

Differences from the RFC / Desugaring

Outside of desugaring I'm not aware of any differences between the implementation and the RFC. The chosen desugaring has been changed from the RFC's original. You can read a detailed discussion of the implementation history of it in @cormacrelf 's summary in this thread, as well as the followup.

Test cases

In chronological order as they were merged.

Added by df9a2e0687895731e12f4a2651e8d70acd08872d (#87688):

Added by 5b95df4bdc330f34213812ad65cae86ced90d80c (#87688):

Added by bf7c32a4477a76bfd18fdcd8f45a939cbed82d34 (#89965):

  • ui/let-else/issue-89960.rs as a regression test for the ICE-on-error bug #89960 . Later in 102b9125e1cefbb8ed8408d2db3f9f7d5afddbf0 this got removed in favour of more comprehensive tests.

Added by 856541963ce95ef4f7d4a81784bb5002ccf63c93 (#89974):

Added by 9b45713b6c1775f0103a1ebee6ab7c6d9b781a21:

  • ui/let-else/let-else-allow-unused.rs as a regression test for #89807, to ensure that #[allow(...)] attributes added to the entire let statement apply for bindings created by the let else pattern.

Added by 61bcd8d3075471b3867428788c49f54fffe53f52 (#89841):

  • ui/let-else/let-else-non-copy.rs to ensure that a copy is performed out of non-copy wrapper types. This mirrors if let behaviour. The test case bases on rustc internal changes originally meant for #89933 but then removed from the PR due to the error prior to the improvements of #89841.
  • ui/let-else/let-else-source-expr-nomove-pass.rs to ensure that while there is a move of the binding in the successful case, the else case can still access the non-matching value. This mirrors if let behaviour.

Added by 102b9125e1cefbb8ed8408d2db3f9f7d5afddbf0 (#89841):

Added by 2715c5f984fda7faa156d1c9cf91aa4934f0e00f (#89841):

  • Match ergonomic tests adapted from the rfc2005 test suite.

Added by fec8a507a27de1b08a0b95592dc8ec93bf0a321a (#89841):

Added since this stabilization report was originally written (2022-02-09)

Added by 76ea56667703ac06689ff1d6fba5d170fa7392a7 (#94211):

  • ui/let-else/let-else-destructuring.rs to give a nice error message if an user tries to do an assignment with a (possibly refutable) pattern and an else block, like asked for in #93995.

Added by e7730dcb7eb29a10ee73f269f4dc6e9d606db0da (#94208):

  • ui/let-else/let-else-allow-in-expr.rs to test whether #[allow(unused_variables)] works in the expr, as well as its non presence, as well as putting it on the entire let else affects the expr, too. This was adding a missing test as pointed out by the stabilization report.
  • Expansion of ui/let-else/let-else-allow-unused.rs and ui/let-else/let-else-check.rs to ensure that non-presence of #[allow(unused)] does issue the unused lint. This was adding a missing test case as pointed out by the stabilization report.

Added by 5bd71063b3810d977aa376d1e6dd7cec359330cc (#94208):

  • ui/let-else/let-else-slicing-error.rs, a regression test for #92069, which got fixed without addition of a regression test. This resolves a missing test as pointed out by the stabilization report.

Added by 5374688e1d8cbcff7d1d14bb34e38fe6fe7c233e (#98574):

Added by 6c529ded8674b89c46052da92399227c3b764c6a (#98574):

Added by 9b566401068cb8450912f6ab48f3d0e60f5cb482 (#99518):

  • src/test/ui/let-else/let-else-temp-borrowck.rs as a regression test for #93951
  • Extension of src/test/ui/let-else/let-else-temporary-lifetime.rs to include a partial regression test for #98672 (especially regarding else drop order)

Added by baf9a7cb57120ec1411196214fd0d1c33fb18bf6 (#99518):

  • Extension of src/test/ui/let-else/let-else-temporary-lifetime.rs to include a partial regression test for #93951, similar to let-else-temp-borrowck.rs

Added by 60be2de8b7b8a1c4eee7e065b8cef38ea629a6a3 (#99518):

  • Extension of src/test/ui/let-else/let-else-temporary-lifetime.rs to include a program that can now be compiled thanks to borrow checker implications of #99518

Added by #99291:

  • TBD, not merged yet.

Added by #99954:

  • TBD, not merged yet.

Added by #100132:

  • TBD, not merged yet.

Added by this PR:

  • ui/let-else/let-else.rs, a simple run-pass check, similar to ui/let-else/let-else-run-pass.rs.

Added by #94012:

  • TBD, the PR is not yet merged.

Things not currently tested

  • ~~The #[allow(...)] tests check whether allow works, but they don't check whether the non-presence of allow causes a lint to fire.~~ → test added by e7730dcb7eb29a10ee73f269f4dc6e9d606db0da
  • ~~There is no #[allow(...)] test for the expression, as there are tests for the pattern and the else block.~~ → test added by e7730dcb7eb29a10ee73f269f4dc6e9d606db0da
  • ~~let-else-brace-before-else.rs forbids the let ... = {} else {} pattern and there is a rustfix to obtain let ... = ({}) else {}. I'm not sure whether the .fixed files are checked by the tooling that they compile. But if there is no such check, it would be neat to make sure that let ... = ({}) else {} compiles.~~ → test added by e7730dcb7eb29a10ee73f269f4dc6e9d606db0da
  • ~~#92069 got closed as fixed, but no regression test was added. Not sure it's worth to add one.~~ → test added by 5bd71063b3810d977aa376d1e6dd7cec359330cc
  • consistency between let else and if let regarding lifetimes and drop order: https://github.com/rust-lang/rust/pull/93628#issuecomment-1055738523

Don't think these missing tests should block stabilization, they are rather details. But feel free to disagree.

Possible future work / Refutable destructuring assignments

RFC 2909 specifies destructuring assignment, allowing statements like FooBar { a, b, c } = foo();. As it was stabilized, destructuring assignment only allows irrefutable patterns, which before the advent of let else were the only patterns that let supported. So the combination of let else and destructuring assignments gives reason to think about extensions of the destructuring assignments feature that allow refutable patterns, discussed in #93995.

A naive mapping of let else to destructuring assignments in the form of Some(v) = foo() else { ... }; might not be the ideal way. let else needs a diverging else clause as it introduces new bindings, while assignments have a default behaviour to fall back to if the pattern does not match, in the form of not performing the assignment. Thus, there is no good case to require divergence, or even an else clause at all, beyond the need for having some introducer syntax so that it is clear to readers that the assignment is not a given (enums and structs look similar). There are better candidates for introducer syntax however than an empty else {} clause, like maybe which could be added as a keyword on an edition boundary:

let mut v = 0;
maybe Some(v) = foo(&v);
maybe Some(v) = foo(&v) else { bar() };

Further design discussion is left to an RFC, or the linked issue.

est31 avatar Feb 03 '22 19:02 est31

r? @jackh726

(rust-highfive has picked a reviewer for you, use r? to override)

rust-highfive avatar Feb 03 '22 19:02 rust-highfive

The job mingw-check failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
configure: rust.debug-assertions := True
configure: rust.overflow-checks := True
configure: llvm.assertions      := True
configure: dist.missing-tools   := True
configure: build.configure-args := ['--enable-sccache', '--disable-manage-submodu ...
configure: writing `config.toml` in current directory
configure: 
configure: run `python /checkout/x.py --help`
configure: 

rust-log-analyzer avatar Feb 03 '22 19:02 rust-log-analyzer

The job x86_64-gnu-llvm-12 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
To only update this specific test, also pass `--test-args let-else/let-else-check.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/let-else/let-else-check.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/let-else/let-else-check" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/let-else/let-else-check/auxiliary"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
error: unused variable: `x`
  --> /checkout/src/test/ui/let-else/let-else-check.rs:13:9
   |
LL |     let x = 1; //~ ERROR unused variable: `x`
   |         ^ help: if this is intentional, prefix it with an underscore: `_x`
note: the lint level is defined here
  --> /checkout/src/test/ui/let-else/let-else-check.rs:1:9
   |
LL | #![deny(unused_variables)]
---
normalized stderr:
warning: unused variable: `x`
  --> $DIR/let-else.rs:4:14
   |
LL |     let Some(x) = Some(1) else {
   |              ^ help: if this is intentional, prefix it with an underscore: `_x`
   = note: `#[warn(unused_variables)]` on by default

warning: 1 warning emitted

---
To only update this specific test, also pass `--test-args let-else/let-else.rs`

error: 1 errors occurred comparing output.
status: exit status: 0
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/let-else/let-else.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/let-else/let-else/a" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/let-else/let-else/auxiliary"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
warning: unused variable: `x`
  --> /checkout/src/test/ui/let-else/let-else.rs:4:14
   |
LL |     let Some(x) = Some(1) else {
   |              ^ help: if this is intentional, prefix it with an underscore: `_x`
   = note: `#[warn(unused_variables)]` on by default

warning: 1 warning emitted

---
To only update this specific test, also pass `--test-args pattern/usefulness/top-level-alternation.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/top-level-alternation" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/top-level-alternation/auxiliary"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:6:23
   |
LL |     while let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern
   |
note: the lint level is defined here
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:1:9
   |
   |
LL | #![deny(unreachable_patterns)]
   |         ^^^^^^^^^^^^^^^^^^^^

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:7:20
   |
LL |     if let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:11:15
   |
   |
LL |             | 0 => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:16:15
   |
   |
LL |             | Some(0) => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:21:9
   |
   |
LL |         (0, 0) => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:41:9
   |
   |
LL |         _ => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:45:9
   |
   |
LL |         Some(_) => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:46:9
   |
   |
LL |         None => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:51:9
   |
   |
LL |         None | Some(_) => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:55:9
   |
   |
LL |         1..=2 => {}, //~ ERROR unreachable pattern

Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu
error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:58:14
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:58:14
   |
LL |     let (0 | 0) = 0 else { return }; //~ ERROR unreachable pattern

error: aborting due to 11 previous errors


rust-log-analyzer avatar Feb 03 '22 20:02 rust-log-analyzer

This looks good to me; I'll start a T-lang FCP.

joshtriplett avatar Feb 03 '22 20:02 joshtriplett

Shall we stabilize let else syntax? We've had many demonstrated uses, including extensively throughout rust-lang/rust, we've seen the value of it, and there aren't any known issues with it.

@rfcbot merge

joshtriplett avatar Feb 03 '22 20:02 joshtriplett

Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members:

  • [x] @cramertj
  • [x] @joshtriplett
  • [x] @nikomatsakis
  • [x] @pnkfelix
  • [x] @scottmcm

Concerns:

  • ~~need-consistency-rvalue-temporary-rules-between-let-and-let-else~~ resolved by https://github.com/rust-lang/rust/pull/93628#issuecomment-1238498468
  • ~~not-while-rustfmt-breaks-on-it~~ resolved by https://github.com/rust-lang/rust/pull/93628#issuecomment-1032936704
  • ~~semicolon~~ resolved by https://github.com/rust-lang/rust/pull/93628#issuecomment-1059799661
  • ~~stabilization-report~~ resolved by https://github.com/rust-lang/rust/pull/93628#issuecomment-1033846359
  • ~~summarize-concerns~~ resolved by https://github.com/rust-lang/rust/pull/93628#issuecomment-1056785904

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

rfcbot avatar Feb 03 '22 20:02 rfcbot

The job x86_64-gnu-llvm-12 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
To only update this specific test, also pass `--test-args pattern/usefulness/top-level-alternation.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/top-level-alternation" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/top-level-alternation/auxiliary"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:6:23
   |
LL |     while let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern
   |
note: the lint level is defined here
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:1:9
   |
   |
LL | #![deny(unreachable_patterns)]
   |         ^^^^^^^^^^^^^^^^^^^^

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:7:20
   |
LL |     if let 0..=2 | 1 = 0 {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:11:15
   |
   |
LL |             | 0 => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:16:15
   |
   |
LL |             | Some(0) => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:21:9
   |
   |
LL |         (0, 0) => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:41:9
   |
   |
LL |         _ => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:45:9
   |
   |
LL |         Some(_) => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:46:9
   |
   |
LL |         None => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:51:9
   |
   |
LL |         None | Some(_) => {} //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:55:9
   |
   |
LL |         1..=2 => {}, //~ ERROR unreachable pattern

error: unreachable pattern
  --> /checkout/src/test/ui/pattern/usefulness/top-level-alternation.rs:58:14
   |
   |
LL |     let (0 | 0) = 0 else { return }; //~ ERROR unreachable pattern

error: aborting due to 11 previous errors


rust-log-analyzer avatar Feb 03 '22 20:02 rust-log-analyzer

@rfcbot concern not-while-rustfmt-breaks-on-it

I remembered it not formatting last I tried using it in rustc, and sure enough it still seems to fail when I try it in playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=350415c3adb74101bbdc002031976b70

(There's enough people using rustfmt in CI that I think adding formatting support for it after stabilization would be impolite.)

EDIT: "breaks" is not the word I should have used here. I meant "while rustfmt is unable to normalize formatting for the construct", since that's what I'd expect rustfmt to do for all stable syntax.

scottmcm avatar Feb 03 '22 20:02 scottmcm

I remembered it not formatting last I tried using it in rustc, and sure enough it still seems to fail when I try it in playground:

It's not that rustfmt is "breaking" on it, but the formatting rules aren't established yet so rustfmt is just leaving whatever you wrote in place. You have trailing whitespace in your snippet, and rustfmt is just acknowledging the presence of what was originally written; it's not modifying what was already there/inserting trailing whitespace itself.

calebcartwright avatar Feb 03 '22 20:02 calebcartwright

it's not modifying what was already there

I think that's my complaint. I think it's clear that we'd want rustfmt to format it, but based on https://rust-lang.github.io/rfcs/2437-rustfmt-stability.html it'd need to be a new version to add formatting support for it if we did so after stabilization. And I don't think that dance is worth it; it should just have formatting support in the release that stabilizes it.

scottmcm avatar Feb 03 '22 20:02 scottmcm

it'd need to be a new version to add formatting support for it if we did so after stabilization. And I don't think that dance is worth it; it should just have formatting support in the release that stabilizes it

That's not the case actually.

rustfmt has always had leeway to make formatting changes for "new" syntax (we have to) until such time as the formatting has actually been stabilized. We try very hard to only do this once, which is why the "first do no harm" pattern followed for syntax that's new to rustfmt.

I've never seen a case where stabilization of a feature was held up on rustfmt, and doing so would be a big mistake IMO. Throughout my time working on rustfmt it's often been an after thought where we weren't even aware of syntax changes until long after they'd been in use, and there's plenty of cases where rustfmt exhibits this same behavior on long-standing syntax (e.g. try adding comments between trait bounds).

I'd think that blocking feature stabilization on style guide + formatting stabilization would either greatly elongate the lead time for feature availability on stable, or create large amounts of friction on the rustfmt side between expediency (not wanting to block) and formatting stability + quality/correctness.

Also, and I say this as someone that spends a large chunk of my free time trying to maintain and improve rustfmt 😄, there's a non-zero subset of the Rust population that dislikes rustfmt and doesn't use it whatsoever. If I were one of those folks I think it would be extremely frustrating to not have access to a language feature on stable simply because of an optional tool I don't leverage.

calebcartwright avatar Feb 03 '22 21:02 calebcartwright

The job x86_64-gnu-tools failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
  IMAGE: x86_64-gnu-tools
##[endgroup]
From https://github.com/rust-lang/rust
 * branch              master     -> FETCH_HEAD
Searching for toolstate changes between 4e8fb743ccbec27344b2dd42de7057f41d4ebfdd and 24e178481e9f3e5dbd1ffba37e9a302e2386197c
Rustdoc was updated
##[group]Run src/ci/scripts/verify-channel.sh
src/ci/scripts/verify-channel.sh
shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
env:
---
   Compiling idna v0.2.0
error: the feature `let_else` has been stable since 1.60.0 and no longer requires an attribute to enable
 --> src/tools/clippy/clippy_utils/src/lib.rs:3:12
  |
3 | #![feature(let_else)]
  |
  |
  = note: `-D stable-features` implied by `-D warnings`
error: could not compile `clippy_utils` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed
Building stage2 tool rls (x86_64-unknown-linux-gnu)
---
   Compiling strip-ansi-escapes v0.1.0
warning: the feature `let_else` has been stable since 1.60.0 and no longer requires an attribute to enable
 --> src/tools/clippy/clippy_utils/src/lib.rs:3:12
  |
3 | #![feature(let_else)]
  |
  = note: `#[warn(stable_features)]` on by default

   Compiling aho-corasick v0.7.18
---
   Compiling cargo v0.61.0 (/checkout/src/tools/cargo)
warning: the feature `let_else` has been stable since 1.60.0 and no longer requires an attribute to enable
 --> src/tools/clippy/clippy_lints/src/lib.rs:8:12
  |
8 | #![feature(let_else)]
  |
  = note: `#[warn(stable_features)]` on by default

   Compiling rls-rustc v0.6.0 (/checkout/src/tools/rls/rls-rustc)
---
-hello dup fd
-

The actual stdout differed from the expected stdout.
Actual stdout saved to /tmp/compiletestHOBcQy/fs.stage-id.stdout

-hello dup fd
+error: unsupported operation: can't call foreign function: readdir64
+   --> /checkout/library/std/src/sys/unix/fs.rs:482:33
---
+
 

The actual stderr differed from the expected stderr.
Actual stderr saved to /tmp/compiletestHOBcQy/fs.stage-id.stderr
To only update this specific test, also pass `--test-args fs.rs`

error: 2 errors occurred comparing output.
status: exit status: 1
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools-bin/miri" "tests/run-pass/fs.rs" "-L" "/tmp/compiletestHOBcQy" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-C" "prefer-dynamic" "-o" "/tmp/compiletestHOBcQy/fs.stage-id" "-A" "unused" "--edition" "2018" "-Astable-features" "--sysroot" "/home/user/.cache/miri/HOST" "-Zmiri-disable-isolation" "-L" "/tmp/compiletestHOBcQy/fs.stage-id.aux"
------------------------------------------

------------------------------------------
stderr:
---



The actual stderr differed from the expected stderr.
Actual stderr saved to /tmp/compiletestHOBcQy/portable-simd.stage-id.stderr
To only update this specific test, also pass `--test-args portable-simd.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools-bin/miri" "tests/run-pass/portable-simd.rs" "-L" "/tmp/compiletestHOBcQy" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-C" "prefer-dynamic" "-o" "/tmp/compiletestHOBcQy/portable-simd.stage-id" "-A" "unused" "--edition" "2018" "-Astable-features" "--sysroot" "/home/user/.cache/miri/HOST" "-L" "/tmp/compiletestHOBcQy/portable-simd.stage-id.aux"
------------------------------------------

------------------------------------------
stderr:
---
Building stage2 tool clippy-driver (x86_64-unknown-linux-gnu)
warning: the feature `let_else` has been stable since 1.60.0 and no longer requires an attribute to enable
 --> src/tools/clippy/clippy_utils/src/lib.rs:3:12
  |
3 | #![feature(let_else)]
  |
  = note: `#[warn(stable_features)]` on by default

warning: `clippy_utils` (lib) generated 1 warning
warning: `clippy_utils` (lib) generated 1 warning
   Compiling cargo_metadata v0.14.0
   Compiling clippy_lints v0.1.60 (/checkout/src/tools/clippy/clippy_lints)
error: the feature `let_else` has been stable since 1.60.0 and no longer requires an attribute to enable
 --> src/tools/clippy/clippy_lints/src/lib.rs:8:12
  |
8 | #![feature(let_else)]
  |
  |
  = note: `-D stable-features` implied by `-D warnings`
error: could not compile `clippy_lints` due to previous error
error: could not compile `clippy_lints` due to previous error
thread 'main' panicked at 'in-tree tool', src/bootstrap/test.rs:658:14
Build completed unsuccessfully in 0:00:16

rust-log-analyzer avatar Feb 03 '22 21:02 rust-log-analyzer

On the topic of whether to block stability on rustfmt:

Ember has an interesting addition to their process. In their model, stabilization is not the "end point" for a feature, it's one step before the end. The final step is "recommended", and that stage is reached when the feature is documented and has good support for tooling. The goal is precisely to avoid the kind of "deadlock" that we've seen sometimes and that @calebcartwright is describing. Maybe we should consider adopting a similar strategy?

All of that said, when I used let-else on a project recently, it seemed to me that it was being formatted in the "expected" way. I didn't go through the effort to create torture tests. I really value how rustfmt takes whatever garbage I throw at it and makes something nice out of it -- I've gotten very used to just typing things without thinking about how it should look -- so I would definitely want let-else to continue in that tradition.

(I almost wrote a 'recommended' stage into the initiative process, but I decided to simplify and avoid introducing too many new things at once.)

nikomatsakis avatar Feb 03 '22 23:02 nikomatsakis

One thing I noticed from using let-else that I didn't expect:

At first, I was annoyed that I had to introduce a block in the "else" clause, since I wanted to basically write

let Some(foo) = bar else return;

and be very concise. But I found that actually I quite like the {} and the way that rustfmt puts that onto the next line:

let Some(foo) = bar else {
    return;
}

I found that this indentation made the else case stand out just a bit, which seemed good, because otherwise it would be easy to miss.

nikomatsakis avatar Feb 03 '22 23:02 nikomatsakis

@rfcbot concern stabilization-report

Thanks for putting this PR together! I am generally favorable on stabilizing, but I would like to see a stabilization report (can't find the link just now...) In particular I would appreciate a write-up that summarizes the design ultimately implemented (especially if it changed since the RFC) and answers the unresolved questions.

nikomatsakis avatar Feb 04 '22 00:02 nikomatsakis

The final step is "recommended", and that stage is reached when the feature is documented and has good support for tooling. The goal is precisely to avoid the kind of "deadlock" that we've seen sometimes and that @calebcartwright is describing. Maybe we should consider adopting a similar strategy?

That type of progressive rollout/shades of grey approach would be helpful for rustfmt, but it's vastly different from the constraints we've been bounded by historically.

Once rustfmt starts rewriting some input R to some output R1, the formatting stability means that rustfmt is never supposed to subsequently start rewriting the previously formatted R1 as some other R2 (yes we've failed at this before, but that's a bug not a feature). Maddeningly, at least for me, this expectation gets applied across all channels including nightly since users developing on nightly, understandably, don't want to deal with formatting churn either. That's why we try to take a very conservative approach to adding the initial R->R1 reformatting because up until that point R has never been "correctly formatted".

So absent some such significant changing of process and/or constraints, incorporating rustfmt into the feature stabilization process would have significant, IMO undesirable, side effects and I suspect would be largely impractical.

We actually are in a far better position than normal with let else because @camsteffen has been particularly helpful on the formatting side. However, I'd have grave concerns with this setting a precedent for gating feature stabilization on rustfmt moving forward.

calebcartwright avatar Feb 04 '22 00:02 calebcartwright

@nikomatsakis FWIW I think rustfmt will allow else { .. }; on the same line if it fits. This would be consistent with if/else (edit: actually not so when in statement position). See https://github.com/rust-dev-tools/fmt-rfcs/pull/165.

I feel I should note that in my usage I very often forget the required semicolon at the end (like @nikomatsakis did above). It seems inconsistent with while, loop, if/else.

camsteffen avatar Feb 04 '22 11:02 camsteffen

Thanks for the extra context, @calebcartwright ! I was unaware of that, so will

@rfcbot resolve not-while-rustfmt-breaks-on-it

(We had a helpful conversation in the lang team meeting about it too https://github.com/rust-lang/lang-team/blob/master/minutes/2022-02-08.md#stabilize-let-else-rust93628, and how the difference between "we leave whatever you wrote alone" and "we're actually formatting it" makes an important difference for a later change to "here's the official one".)

One additional question I have about it, then:

Can we have the body of the block get formatted still?

If I use a simpler example https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=ccf2d2eae6c3c900055357ce0da94d05, it would be nice to have the expressions inside the block get formatted as normal even if we have yet to decide on the official format for the let-else part and thus leave that layout alone.

scottmcm avatar Feb 08 '22 18:02 scottmcm

I feel I should note that in my usage I very often forget the required semicolon at the end (like @nikomatsakis did above). It seems inconsistent with while, loop, if/else.

let else is closer to let than it is to those other patterns, probably closest to let v = if let Pat(v) = expr { v } else { ...};, which has a ; at the end too.

est31 avatar Feb 09 '22 02:02 est31

Stabilization report

edit: moved to the top / OP

old report

Summary

The feature allows refutable patterns in let statements if the expression is followed by a diverging else:

fn get_count_item(s: &str) -> (u64, &str) {
    let mut it = s.split(' ');
    let (Some(count_str), Some(item)) = (it.next(), it.next()) else {
        panic!("Can't segment count item pair: '{s}'");
    };
    let Ok(count) = u64::from_str(count_str) else {
        panic!("Can't parse integer: '{count_str}'");
    };
    (count, item)
}
assert_eq!(get_count_item("3 chairs"), (3, "chairs"));

Differences from the RFC

I don't know about any differences between the implementation and the RFC outside of the desugaring. The chosen desugaring has been changed from the RFC's original. You can read a detailed discussion of the implementation history of it in @cormacrelf 's summary in this thread.

Test cases

Added by df9a2e0687895731e12f4a2651e8d70acd08872d:

Added by 5b95df4bdc330f34213812ad65cae86ced90d80c:

Added by bf7c32a4477a76bfd18fdcd8f45a939cbed82d34:

  • ui/let-else/issue-89960.rs as a regression test for the ICE-on-error bug #89960 . Later in 102b9125e1cefbb8ed8408d2db3f9f7d5afddbf0 this got removed in favour of more comprehensive tests.

Added by 856541963ce95ef4f7d4a81784bb5002ccf63c93:

Added by 9b45713b6c1775f0103a1ebee6ab7c6d9b781a21:

  • ui/let-else/let-else-allow-unused.rs as a regression test for #89807, to ensure that #[allow(...)] attributes added to the entire let statement apply for bindings created by the let else pattern.

Added by 61bcd8d3075471b3867428788c49f54fffe53f52:

  • ui/let-else/let-else-non-copy.rs to ensure that a copy is performed out of non-copy wrapper types. This mirrors if let behaviour. The test case bases on rustc internal changes originally meant for #89933 but then removed from the PR due to the error prior to the improvements of #89841.
  • ui/let-else/let-else-source-expr-nomove-pass.rs to ensure that while there is a move of the binding in the successful case, the else case can still access the non-matching value. This mirrors if let behaviour.

Added by 102b9125e1cefbb8ed8408d2db3f9f7d5afddbf0:

Added by 2715c5f984fda7faa156d1c9cf91aa4934f0e00f:

  • Match ergonomic tests adapted from the rfc2005 test suite.

Added by fec8a507a27de1b08a0b95592dc8ec93bf0a321a:

Added by this PR:

  • ui/let-else/let-else.rs, a simple run-pass check, similar to ui/let-else/let-else-run-pass.rs.

Things not currently tested

  • The #[allow(...)] tests check whether allow works, but they don't check whether the non-presence of allow causes a lint to fire.
  • There is no #[allow(...)] test for the expression, as there are tests for the pattern and the else block.
  • let-else-brace-before-else.rs forbids the let ... = {} else {} pattern and there is a rustfix to obtain let ... = ({}) else {}. I'm not sure whether the .fixed files are checked by the tooling that they compile. But if there is no such check, it would be neat to make sure that let ... = ({}) else {} compiles.
  • #92069 got closed as fixed, but no regression test was added. Not sure it's worth to add one.

Don't think these missing tests should block stabilization, they are rather details. But feel free to disagree.

est31 avatar Feb 09 '22 02:02 est31

@rfcbot resolve stabilization-report

Thanks @est31! Very excited for this to hit stable.

nikomatsakis avatar Feb 09 '22 14:02 nikomatsakis

@rfcbot reviewed

nikomatsakis avatar Feb 09 '22 14:02 nikomatsakis

On the topic of stabilization phases:

I think we can separate that discussion out. I do believe it would be useful for us to distinguish stabilized from recommended for use, where the former means "code that uses this will keep compiling and retain its same meaning" and the latter means "it is documented in the reference; code that uses this is well formatted; no horrifying diagnostics".

I'm not clear @calebcartwright on why this would be impractical: it seems to me to be formalizing and tweaking conventions that we already have, where stabilization is generally blocked on having an open PR to the reference (https://github.com/rust-lang/reference/pull/1156, in this case).

When it comes to rustfmt, we could conceptually follow that same rule: to stabilize, there must be a pending PR to rustfmt.

That said, I know that @joshtriplett has concerns, though I forget what they are. I do see the value in having a "forcing function" that encourages us to do the detailed work post stabilization. On that note, I think it would be reasonable to require a pending (but not merged) rustfmt PR before we stabilize a new feature. This would also help grow the rustfmt contributors, since people who are psyched to stabilize a feature might also be motivated to come and contribute to rustfmt.

nikomatsakis avatar Feb 09 '22 15:02 nikomatsakis

Can we have the body of the block get formatted still?

Unfortunately no @scottmcm

Though technically I'm sure we could create artificial spans to capture the parts we want to format and the parts we won't, we still don't have any rules finalized for the else block either.

At the same time, any attempts to format the else block would be directly influened by the pre-else content (e.g. column position, whether to wrap, etc.). That would inevitably create a scenario where some users would experience multiple breaking formatting changes after updating toolchains, the first being the initial introduction of let-else support with else-block only changes, and the second would come later once rustfmt started handling the pre-else content because that impacts the else block.

The actual rustfmt piece of the equation is the easy part. What we really need is greater participation and feedback on the Style Guide that defines what the resultant formatting is supposed to look like.

calebcartwright avatar Feb 10 '22 00:02 calebcartwright

I'm not clear @calebcartwright on why this would be impractical

I think we may be referring to two different things @nikomatsakis

My sense of the thread was that we were starting to head down the path of making rustfmt support a hard, blocking gate on feature stabilization. That's what I think would have been impractical, so long as rustfmt is bound by the historical constraints I described in https://github.com/rust-lang/rust/pull/93628#issuecomment-1029525873. I'm happy to elaborate on why I think that's the case, though not sure that's necessary anymore given that no longer seems to be on the table here.

The proposals you're making sound to me more like process improvements/goals/soft-gates, and I do think those could be practical and worth additional discussion. What would be the best channel to continue the dialog, perhaps Zulip? I feel like the discussion is potentially heading towards a more general process around the dev tool relationship with the feature stabilization and imagine other dev tool teams (at least Clippy) would be interested as well.

On that note, I think it would be reasonable to require a pending (but not merged) rustfmt PR before we stabilize a new feature. This would also help grow the rustfmt contributors, since people who are psyched to stabilize a feature might also be motivated to come and contribute to rustfmt.

Happy to consider something like this, though the rustfmt implementation PR is by far one of the easiest and least time consuming formatting elements (typically just a small bit of code to handle taking some new variant of an AST node and applying some basic logic to it, typically by reusing helper functions). I feel like the bigger opportunity would be finding a way to get formatting discussions and considerations for new features translated into the Style Guide more quickly.

I actually feel like many new features get their due ruminations on formatting, and sure there's often good discussions as well. However, I also feel like those rarely make their way to us in the Style Guide/rustfmt. I'd love to see formatting proposals be made and discussed on the Style Guide and done so earlier to help us go faster and to have things better consolidated for posterity vs. today where it feels like the formatting piece may simply be presumed, or if discussed explicitly, has discussion scattered across various GitHub Issues and Pull Requests, chat tools, etc. leaving us with a lot of catch up to play.

If, when relevant, we could start incorporating a Style Guide PR as a target exercise for RFCs once they reach a certain point (or even initial implementation PRs) then I think that would allow us to greatly expedite things on the formatting side.

calebcartwright avatar Feb 10 '22 00:02 calebcartwright

removing T-compiler from this FCP (as per Zulip comment)

@rustbot label -T-compiler

apiraino avatar Feb 10 '22 16:02 apiraino

FTR the label is present because of tooling. It's been removed twice already, the first time rustbot has added it back when I updated the code. Rustbot will probably add it again if I should ever rebase or update the code or something. I think it's adding it because the PR is modifying compiler sources? Not sure.

est31 avatar Feb 10 '22 16:02 est31

@calebcartwright I feel like we should have a short discussion about the ideal process in a lang-team design meeting or some other similar forum, rather than on this PR =)

nikomatsakis avatar Feb 10 '22 18:02 nikomatsakis

was there some discussion about the interaction with destructuring assignments, and if so, can the results of that discussion be mentioned in the stabilization report?

#[derive(Debug)]
enum Foo {
    Done,
    Nested(Option<&'static Foo>),
}

fn walk(mut value: &Foo) {
    loop {
        println!("{:?}", value);
        &Foo::Nested(Some(value)) = value else { break };
    }
}

cc #93995 edit: fixed this so it would actually typeck if destructuring assignment + let else worked together

lcnr avatar Feb 14 '22 16:02 lcnr

can you also add the used desugaring to the stabilization report? especially as it has some surprising results: (#93951)

I think it's important to state why this desugaring was chosen, esp as it is different from the one in the RFC.

lcnr avatar Feb 14 '22 16:02 lcnr

@lcnr I can't find anything about destructuring assignments. Note though that I wasn't involved in the RFC's discussions so maybe @Fishrock123 or someone else can tell more about this.

Destructuring assignments allow irrefutable patterns to be used in assignment position. Same goes for let which also allows irrefutable pattern usage. let else also allows refutable patterns, in fact warns if you use an irrefutable pattern with it. To me, the natural extension of destructuring assignments would not be some "destructuring assignment ... else" construct, but instead just making the destructuring assignment conditional. Or in other words, if the pattern does not match, then no assignment is conducted. I don't think it's a good idea to have refutable destructuring assignments without making it visible syntactically that the assignment does not neccessarily get performed, but the syntax to make this obvious doesn't need to be an else clause. Instead maybe maybe or something, so maybe Some(foo) = bar.get(42).

As for the desugaring, with #93951 I think that it's a bug, but one that can be fixed after stabilization. That is, it is not a blocker, as IIRC borrow checker changes are allowed per rust's stability guarantees. Originally the RFC described the lowering in form of a match statement. I'm not sure why @cormacrelf chose the currently used desugaring in their PR. If they wrote up their reasooning I'd love to link it from the stabilization report.

est31 avatar Feb 14 '22 19:02 est31

@lcnr That destructuring assignment is missing a let as a I have mentioned with a playground link in your issue: https://github.com/rust-lang/rust/issues/93995#issuecomment-1039503525

@est31 I am really not sure what you are meaning to say, let <destructuring assignment> … else works.

Fishrock123 avatar Feb 14 '22 20:02 Fishrock123

I see. To restate the issue with the desugaring pointed out in #93951: if you desugar per the RFC's way, it was impossible to get that error, because the init expression would not be part of one big return expression. That is a bit of a problem. If-let and match are equivalent here, the actual deviation is that the trailing statements are now moved inside the if-branch.

I didn't personally choose that route, I only adapted existing work, but AFAICT it was done to avoid some complicated duplication of the identifiers introduced in the pattern (let (a, b) = if let Ok([ref a, ref b]) = ... { (a, b) } else { return };), that was required to get them into the outer scope. I can't comment on whether that was actually going to be infeasible. But the discussion was on the original implementation PR by @camsteffen with @cjgillot.

Now getting off the track in a stabilisation issue but it's possible there's a solution without reintroducing that complexity. If you make the desugaring let retval = if let Ok(s) = foo(&x) { /* trailing stmts */ } else { return; }; retval then you no longer have a temporary that borrowck worries will be dropped after x: playground. That is, if we can't think of any other borrowck issues.

cormacrelf avatar Feb 15 '22 02:02 cormacrelf

:bell: This is now entering its final comment period, as per the review above. :bell:

rfcbot avatar Feb 15 '22 18:02 rfcbot

@lcnr @cormacrelf I've changed the stabilization report to include desugaring. I've included a mention of #94012 but didn't describe its desugaring because I wasn't entirely certain which one it chose. Was it the original one from the RFC? Also, I'm not sure whether there will be changes to the PR before it gets merged.

est31 avatar Feb 15 '22 23:02 est31

To summarise it for the stabilisation report, I would put it like this:


The desugaring has gone through a number of revisions, mostly to express the RFC's intent through the type checker instead of in terms of existing syntax, to avoid the edge cases that had exhibited, and to provide let-else-specific error messages. Both the else-block's divergence and the optional type annotation are now done in the type checker, and the whole thing is now an if-let instead of a match expression. The most consequential choice has been how to put the bindings in scope for the remainder of the statements in the function. The RFC envisioned this similarly to how many Rust programmers presently simulate let-else:

let (each, binding) = match expr { Ok(Ty { each, binding }) => (each, binding), _ => return };
trailing_statements(a);
// ...

To avoid the complexity of programmatically duplicating the bindings, the current desugaring simply slurps up all the trailing statements and puts them in the appropriate branch. In all, it looks like this.

// type annotation is HIR-only on if-let, not real syntax
if let Some(Ty { each, binding }): Option<Ty> = expr {
    trailing_statements(each, binding);
    // ...
} else {
    return;
}

Multiple let-elses in a row will desugar in a nested fashion, each appearing in the tail position of the then-branch of the one before it.

There is one known problem with this approach, relating to the lifetime of temporaries storing expr in the big implicit return expression it produces #93951, but it does have a simple and promising solution in #94012. In the event that there are further borrowck problems, the exact approach envisioned by the RFC was actually explored, did work, and remains available.[^1]

[^1]: @camsteffen thumbs up 👍 if you approve this statement.


If that's still unclear...

There have been a lot of desugarings. They are made up of the following choices in roughly "evaluation order":

  1. Choice of if-let or match (almost completely inconsequential)
  2. Implementing type annotation via a temp variable vs via typeck
  3. Forcing divergence of else block via let nope: ! = ... vs via typeck
  4. Scoping of pattern match variables via extracting (via tuples + an outer let binding) into outer scope, vs. slurping up (à la paredit slurp) all of the statements after the let-else and putting them inside the "matched" / "then" branch of the matching mechanism. If so, then is the if-let/match in tail position or do we assign it to a temporary and then return that?

The history of choices is like so:

  • (match, ?, let nope: !, extract, _) in the original RFC (relevant section) which didn't address either multiple bindings (ie tuples) or type annotations.
  • (match, temp, typeck, extract) in Cam's initial run.
  • (if-let, temp, typeck, slurp/tail position) in Cam's final #87688.
  • (if-let, typeck, typeck, slurp/tail position) in my previous PR #89841.
  • (if-let, typeck, typeck, slurp/temporary) in my proposed PR #94012.

The current desugaring and my proposed one have no choices in common with the original RFC.

// sugar
let Some(Ty { a, b }): Option<Ty> = expr else { return };
trailing(a, b);

// Original RFC, which doesn't address either multiple bindings or type annotation
let a = match expr { Some(a) => a, _ => return };
trailing(a);

// camsteffen's initial run at it, which addresses both multiple bindings and type annotation (exhibits #89688)
let val: Option<Ty> = expr;
let (a, b) = match val { Some(Ty { a, b }) => (a, b), _ => return };
trailing(a, b);

// camsteffen's implementation (exhibits #89688 and #93951)
let val: Option<Ty> = expr;
if let Some(Ty { a, b }) = val { trailing(a, b); } else { return }

// my implementation, noting this is HIR not user-facing if-let syntax (exhibits #93951)
if let Some(Ty { a, b }): Option<Ty> = expr { trailing(a, b); } else { return }

// my open PR (fixes #93951)
let _var = if let Some(Ty { a, b }): Option<Ty> = expr { trailing(a, b); } else { return };
#[allow(unreachable_code)] _var

cormacrelf avatar Feb 16 '22 06:02 cormacrelf

@rfcbot concern summarize-concerns

I'm finding the back-and-forth here a bit confusing, but I'd definitely like to see the stabilization report extended to discuss (a) potential interactions with destructuring assignment and (b) desugaring. @cormacrelf's writeup seems like a great start there.

(Also, can we move to the stabilization report to the OP to make it easy to find?)

Thanks @est31!

nikomatsakis avatar Feb 16 '22 15:02 nikomatsakis

There is one known problem with this approach, relating to the lifetime of temporaries storing expr in the big implicit return expression it produces https://github.com/rust-lang/rust/issues/93951, but it does have a simple and promising solution in https://github.com/rust-lang/rust/pull/94012. In the event that there are further borrowck problems, the exact approach envisioned by the RFC was actually explored, did work, and remains available.1

This worries me a bit, I'd like to see the lifetime of temporaries better documented (pre-existing problem) and the interactions from this change in particular described. Hmm.

nikomatsakis avatar Feb 16 '22 15:02 nikomatsakis

@nikomatsakis Extending the writeup to incorporate discussion of desugaring does seem important, since that evolved over time. However, I don't think this needs to cover destructuring assignment; at most that just needs to be "possible future work".

joshtriplett avatar Feb 16 '22 19:02 joshtriplett

Is it too late to request (minor) design changes? I've just now come across this feature in the compiler while review a PR, and I find let ... else ... to be a disorienting because of the use of else -- I'm expecting a conditional somewhere, but all I get is a binding. I realize I'm a bit late to the dance, though...

mark-i-m avatar Feb 18 '22 16:02 mark-i-m

@mark-i-m That specific issue, along with other possible syntaxes, was discussed fairly extensively on the RFC thread. It's never too late as long as a feature hasn't been stabilized yet, but it would need a new angle not seen already on that thread.

joshtriplett avatar Feb 19 '22 03:02 joshtriplett

@nikomatsakis: This worries me a bit, I'd like to see the lifetime of temporaries better documented (pre-existing problem) and the interactions from this change in particular described. Hmm.

I have a little more to add on the dropping of temporaries. There is one particular respect in which the nested desugaring expands pretty dramatically on the RFC's capabilities. It allows you to match against temporaries and pull references out of them, just like a regular let statement, whereas the RFC's tuple-threading method does not. You can presently do this:

let Some(x) = &mut Some(5) else { return };
*x += 5;

That's because when the *x += 5; is moved into the desugared if branch, the temporary Some(5) has not yet been dropped: if let Some(x) = &mut Some(5) { *x += 5 } else { return }.

I just did a rough reprise of the original straight-line tuple-threading/re-binding method (just to see if it would work and alleviate #94176), and it fails to compile things like these, for the same reason that you can't do the tuple-threading equivalent with a temporary in stable rust today: playground

error[E0716]: temporary value dropped while borrowed
 --> src/main.rs:2:56  |
2 |     let (identifier,) = if let Some(identifier) = &mut Some(5) {
  |                                                        ^^^^^^^ creates a temporary which is freed while still in use
...
6 |     };
  |      - temporary value is freed at the end of this statement
7 |     *identifier = 10;
  |     ---------------- borrow later used here
  |
  = note: consider using a `let` binding to create a longer lived value

Allowing this is an improvement and better matches expectations. You can bind to parts of a temporary in a single let binding (let (a, b) = &mut (5, 8);) so I don't see why you should be unable to do so in a let-else binding. It should, in theory, be possible to get rustc to be a lot smarter about temporaries' lifetimes (extending them outside the expression they were born in), and to eliminate many more 'temporary freed while still in use' errors from other kinds of code, but that's for another day. For now, though, the nested desugaring has far less interaction with the lifetime of temporaries than the RFC. All it requires is that a temporary if-let scrutinee survives as long as the if branch.

cormacrelf avatar Feb 21 '22 08:02 cormacrelf

Hmm isn't it bad that temporaries are not dropped at the end of the let-else statement? That could be surprising for a temporary MutexGuard for example.

camsteffen avatar Feb 21 '22 18:02 camsteffen

The handling and lifetimes of temporaries should be exactly the same with let and with let else; any understanding or intuitions that people have about let should apply to let else.

joshtriplett avatar Feb 21 '22 18:02 joshtriplett

:umbrella: The latest upstream changes (presumably #94254) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Feb 22 '22 18:02 bors

The job mingw-check failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
configure: rust.debug-assertions := True
configure: rust.overflow-checks := True
configure: llvm.assertions      := True
configure: dist.missing-tools   := True
configure: build.configure-args := ['--enable-sccache', '--disable-manage-submodu ...
configure: writing `config.toml` in current directory
configure: 
configure: run `python /checkout/x.py --help`
configure: 

rust-log-analyzer avatar Feb 23 '22 05:02 rust-log-analyzer

Implementation-wise, this looks fine to me. Going to change this to waiting-on-fcp for now; please change back to waiting-on-review when FCP is done for a final review from me

jackh726 avatar Feb 24 '22 15:02 jackh726

The handling and lifetimes of temporaries should be exactly the same with let and with let else; any understanding or intuitions that people have about let should apply to let else.

I think we have a bug then. 😢 (see playground)

camsteffen avatar Feb 24 '22 16:02 camsteffen

@camsteffen I think this is what #94012 is about. Not 100% sure your bug is fixed with that PR applied to.

est31 avatar Feb 24 '22 17:02 est31

@camsteffen I think this is what #94012 is about. Not 100% sure your bug is fixed with that PR applied to.

I don't think so unfortunately, since the drop will still occur after the following statements.

camsteffen avatar Feb 24 '22 17:02 camsteffen

:umbrella: The latest upstream changes (presumably #94376) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Feb 26 '22 17:02 bors

The job mingw-check failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
configure: rust.debug-assertions := True
configure: rust.overflow-checks := True
configure: llvm.assertions      := True
configure: dist.missing-tools   := True
configure: build.configure-args := ['--enable-sccache', '--disable-manage-submodu ...
configure: writing `config.toml` in current directory
configure: 
configure: run `python /checkout/x.py --help`
configure: 

rust-log-analyzer avatar Feb 27 '22 06:02 rust-log-analyzer

:umbrella: The latest upstream changes (presumably #94431) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Feb 28 '22 04:02 bors

@nikomatsakis re your concerns, I have copied the stabilization report to the top. When it comes to the desugaring there is still a PR open about it, #94012. So the section can't be finalized yet. In fact, there is still ongoing discussion in that PR about the desugaring. I'd say progress is blocked on #94012 right now.

On the missing tests front, progress has happened by me adding a PR to add them: #94208 . Also, I've improved error messages for destructuring assignments with an else clause in #94211, as requested by @lcnr in #93995.

est31 avatar Feb 28 '22 07:02 est31

:umbrella: The latest upstream changes (presumably #94453) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Mar 01 '22 00:03 bors

:umbrella: The latest upstream changes (presumably #94477) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Mar 01 '22 14:03 bors

The handling and lifetimes of temporaries should be exactly the same with let and with let else; any understanding or intuitions that people have about let should apply to let else.

I think we have a bug then. 😢 (see playground)

@rfcbot concern need-consistency-rvalue-temporary-rules-between-let-and-let-else

We need to make sure that examples like the one given above, and variations like this:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=4c8e1cd80f50ed3c41eb426ae80c350c

(which currently is consistent, but one can imagine buggy fixes to the previous playground that subsequently break this case)

are all made consistent and are exercised in the test suite.

pnkfelix avatar Mar 01 '22 18:03 pnkfelix

Quick note on formatting:

I just encountered a case with a really long expression being matched. My usual rule was not very satisfactory:

let Some((fooooooo, baaaaaaaaaaaaaaaaaaaar, baaaaaaaaaaaaaaaaaaaaaaaaaaaz)) =
    something_that_creates_that() else {
    return Err(());
};

Hence I wrote what seemed natural for other cases where this happens:

let Some((fooooooo, baaaaaaaaaaaaaaaaaaaar, baaaaaaaaaaaaaaaaaaaaaaaaaaaz)) =
    something_that_creates_that()
else {
    return Err(());
};

and I realized, "Oh, although it seems less 'elegant', maybe having the else on the next line would just be clearer always". Food for thought when the style team takes this into consideration. (I guess that this is not news to most people, but I hadn't encountered the formatting edge cases yet.)

nikomatsakis avatar Mar 02 '22 10:03 nikomatsakis

@rfcbot resolve summarize-concerns

Thanks for the edits to the report, everyone, and to @pnkfelix for filing a more precise concern about temporary rvalues.

nikomatsakis avatar Mar 02 '22 10:03 nikomatsakis

@nikomatsakis re your point on putting else onto a separate line, there has been a similar suggestion in the dedicated rustfmt thread, although that suggestion wants to put it onto a new line more often (basically always unless the entire statement doesn't fit into a single line. if the else body is just too large but the else fits onto the same line as let, I think it should be in the same line).

This PR needs a rebase but I'm waiting until it's closer to FCP as @c410-f3r 's PRs keep causing conflicts, and I don't want to spam people subscribed to this PR with rebase related notifications.

est31 avatar Mar 02 '22 11:03 est31

Who?! Me?! 👀

Yesterday the last PR was introduced so you probably won't expect more future conflicts

c410-f3r avatar Mar 02 '22 11:03 c410-f3r

Thanks for the heads up! Yeah, your recent PRs have caused conflicts in the lib.rs files, but it's fine and only small disruption anyways, and very easy to fix. I just said I'm going to wait with rebasing because atm this PR is far away from being merged (blocked on FCP which is blocked on desugaring improvements), to let the triage people know.

est31 avatar Mar 02 '22 11:03 est31

re your point on putting else onto a separate line, there has been a similar suggestion in the dedicated rustfmt thread

I'll move any further replies there =)

nikomatsakis avatar Mar 02 '22 13:03 nikomatsakis

there has been a https://github.com/rust-lang/rustfmt/issues/4914#issuecomment-887104615 suggestion in the dedicated rustfmt thread

minor correction: That rustfmt implementation tracking issue is actually not the right place.

Thoughts/perspectives/etc. on the style/formatting rules should be directed to the style guide in https://github.com/rust-dev-tools/fmt-rfcs/pull/165 and I'd encourage anyone/everyone interested to participate; the more feedback and input provided on the rules the more quickly we'll be able to start the implementation in rustfmt

calebcartwright avatar Mar 02 '22 19:03 calebcartwright

@rfcbot concern semicolon

Several people have independently made the point that most braced blocks of code in Rust don't require a trailing semicolon, and that people are likely to regularly forget this. I'm finding myself starting to agree with that opinion.

I'm filing this as a concern for us to discuss in the next lang team meeting.

This concern should not be taken as a requirement to make this change, but rather, that we need to discuss and consider such a change before the stabilization goes through.

joshtriplett avatar Mar 05 '22 08:03 joshtriplett

IDK, personally, I see the ; to be consistent with traditional let which needs them too. Especially as let else is a replacement of this pattern:

let foo = if let Some(foo) = bar {
    foo
} else {
    panic!()
};

For other places with };, one can often find stuff like this:

let foo = {
    /* code that returns something */
};

Lastly, there are closures:

let bar = || {
    // Do something
};
bar();

I don't think let else is much different from these let IDENT = EXPR; constructs, where the } is part of the expr. But the same time, there is no precedent for an else where a trailing } is required as part of the construct that gives rise to the else.

est31 avatar Mar 05 '22 11:03 est31

IDK, personally, I see the ; to be consistent with traditional let which needs them too.

I want to make a small distinction here. In those examples, the brace at the end is part of an expression within the <expr> of a let statement. The closing brace is not part of the syntax of the outermost language construct that the statement consists of. let-else is the first whole-statement construct that ends with };. Comparing with if/else, while, loop. That's why I get tripped up. When writing a loop statement, I think "this closing brace ends the loop which is the whole statement, so I don't need a semicolon". I apply the same reasoning to let-else and...error.

camsteffen avatar Mar 05 '22 12:03 camsteffen

I think that making let-else less like other assignments would be a bad maneuver. Without the semicolon it looks like an expression which could possibly return a value, which is misleading.

Consider:

thing.map(|inner| let Some(a) = inner else { something })

Looks kinda like a construct which could return something. Ah, but you say, “there’s a let there so that looks odd and kinda obvious and should easily warn from the compiler” - while true, consider that there has been discussion of extending let-else behavior to destructuring assignments, which would end you up with code that really looks like it could plausibly return something:

let a, b;

thing.map(|inner| (a, b) = inner else { something })

To me, without the semicolon this looks like it should plausibly work, like something could be returned from the else. I think this will be more confusing for beginners than requiring a semicolon, and maybe it could leave us with extra options for a potential fallback extension for destructuring assignment without the let in particular. I suppose you could argue if this is about potential addition of this to destructuring assignments then let-else in specific does not need to abide by those but I think that would make consistency even worse.

Plus, as far as I know all other assignments require a semicolon at the end, which will probably also be confusing. On this note, the RFC mentions it in the context of consistency with let.

tl;dr: RFC author thinks that not requiring semicolon will be a mistake

Fishrock123 avatar Mar 05 '22 16:03 Fishrock123

@Fishrock123 Thank you for that detailed response!

While I don't think we're going to add destructuring-assignment-else (largely because it isn't as distinctly identified), even without that I agree with your assessment of the meaning and potential confusion of omitting the semicolon.

@rfcbot resolved semicolon

joshtriplett avatar Mar 05 '22 17:03 joshtriplett

Consider:

thing.map(|inner| let Some(a) = inner else { something })

I wouldn't expect that to compile in the same way that you can't write thing.map(|inner| struct X {}).

camsteffen avatar Mar 05 '22 20:03 camsteffen

Me, knowing better, would not expect it to compile either. I think it would look at a glance more ambiguous to newcomers without the semicolon however, especially if this were ever added to the destructuring assignment.

Fishrock123 avatar Mar 06 '22 03:03 Fishrock123

What's the current state of the consistency issue between let and let else for handling temporary lifetimes?

joshtriplett avatar Mar 08 '22 18:03 joshtriplett

There hasn't been much progress lately, since #94012 was filed at least, unless I've been missing something. Especially, this is unfixed: https://github.com/rust-lang/rust/pull/93628#issuecomment-1050037021

est31 avatar Mar 08 '22 19:03 est31

The job x86_64-gnu-llvm-12 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
................................................................................................i... 8900/12732
.................................................................................................... 9000/12732
.................................................................................................... 9100/12732
.................................................................................................... 9200/12732
.F.............................F.................................................................... 9300/12732
.....................................iiii.iiiii..................................................... 9500/12732
.............ii...............i.........................................................ii.......... 9600/12732
......................................................................................F............. 9700/12732
.................................................................................................... 9800/12732
---
.................................................................................................... 11900/12732
..............................................i..................................................... 12000/12732
.................................................................................................... 12100/12732
.................................................................................................... 12200/12732
......................................................................F...F......................... 12300/12732
.................................................................................................... 12500/12732
.................................................................................................... 12600/12732
...........................iii...................................................................... 12700/12732
................................
................................
failures:

---- [ui] ui/empty/empty-never-array.rs stdout ----
diff of stderr:

18    |
19 LL |     let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() };
20    |     ++++++++++                                     ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
22    |
23 LL |     let Helper::U(u) = Helper::T(t, []) else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array/empty-never-array.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array/empty-never-array.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args empty/empty-never-array.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/empty/empty-never-array.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array/auxiliary"
Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
   |
   |
LL |     let Helper::U(u) = Helper::T(t, []);
   |         ^^^^^^^^^^^^ pattern `T(_, _)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Helper<T, U>` defined here
   |
   |
LL | enum Helper<T, U> {
   |      ------
LL |     T(T, [!; 0]),
   |     ^ not covered
   = note: the matched value is of type `Helper<T, U>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() };
   |     ++++++++++                                     ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Helper::U(u) = Helper::T(t, []) else { todo!() };

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] ui/error-codes/E0005.rs stdout ----
diff of stderr:

24    |
25 LL |     let y = if let Some(y) = x { y } else { todo!() };
26    |     ++++++++++                 ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
28    |
29 LL |     let Some(y) = x else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005/E0005.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005/E0005.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args error-codes/E0005.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/error-codes/E0005.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `None` not covered
   |
   |
LL |     let Some(y) = x; //~ ERROR E0005
   |         ^^^^^^^ pattern `None` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Option<i32>` defined here
   |
LL | / pub enum Option<T> {
LL | |     /// No value.
LL | |     /// No value.
LL | |     #[lang = "None"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
LL | |     None,
...  |
...  |
LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
LL | | }
   | |_-
   = note: the matched value is of type `Option<i32>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let y = if let Some(y) = x { y } else { todo!() }; //~ ERROR E0005
   |     ++++++++++                 ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Some(y) = x else { todo!() }; //~ ERROR E0005

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] ui/feature-gates/feature-gate-exhaustive-patterns.rs stdout ----
diff of stderr:

23    |
24 LL |     let _x = if let Ok(_x) = foo() { _x } else { todo!() };
25    |     +++++++++++                    +++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
27    |
28 LL |     let Ok(_x) = foo() else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns/feature-gate-exhaustive-patterns.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns/feature-gate-exhaustive-patterns.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args feature-gates/feature-gate-exhaustive-patterns.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   |
   |
LL |     let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding
   |         ^^^^^^ pattern `Err(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, !>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, !>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let _x = if let Ok(_x) = foo() { _x } else { todo!() }; //~ ERROR refutable pattern in local binding
   |     +++++++++++                    +++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Ok(_x) = foo() else { todo!() }; //~ ERROR refutable pattern in local binding

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] ui/pattern/usefulness/issue-31561.rs stdout ----
diff of stderr:

21    |
22 LL |     let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() };
23    |     ++++++++++                                   ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variants that aren't matched
25    |
26 LL |     let Thing::Foo(y) = Thing::Foo(1) else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561/issue-31561.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561/issue-31561.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args pattern/usefulness/issue-31561.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/pattern/usefulness/issue-31561.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
   |
   |
LL |     let Thing::Foo(y) = Thing::Foo(1);
   |         ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Thing` defined here
   |
LL | enum Thing {
   |      -----
LL |     Foo(u8),
LL |     Foo(u8),
LL |     Bar,
   |     ^^^ not covered
LL |     Baz
   |     ^^^ not covered
   = note: the matched value is of type `Thing`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() };
   |     ++++++++++                                   ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variants that aren't matched
   |
LL |     let Thing::Foo(y) = Thing::Foo(1) else { todo!() };

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] ui/pattern/usefulness/non-exhaustive-defined-here.rs stdout ----
diff of stderr:

187    |
188 LL |     let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() };
189    |     +++++++++++                           +++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
191    |
192 LL |     let Opt::Some(ref _x) = e else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here/non-exhaustive-defined-here.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here/non-exhaustive-defined-here.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args pattern/usefulness/non-exhaustive-defined-here.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0004]: non-exhaustive patterns: `B` and `C` not covered
   |
   |
LL |     match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered
   |           ^^ patterns `B` and `C` not covered
note: `E` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:14:5
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `E`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL ~         E::A => {}
LL +         B | C => todo!()


error[E0005]: refutable pattern in local binding: `B` and `C` not covered
   |
   |
LL |     let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered
   |         ^^^^ patterns `B` and `C` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `E` defined here
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `E`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     if let E::A = e { todo!() } //~ ERROR refutable pattern in local binding: `B` and `C` not covered
   |     ++              ~~~~~~~~~~~

error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
   |
   |
LL |     match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered
   |           ^ patterns `&B` and `&C` not covered
note: `E` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:14:5
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&E`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL ~         E::A => {}
LL +         &B | &C => todo!()


error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered
   |
   |
LL |     let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
   |         ^^^^ patterns `&B` and `&C` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `E` defined here
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&E`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     if let E::A = e { todo!() } //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
   |     ++              ~~~~~~~~~~~

error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
   |
   |
LL |     match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
   |           ^ patterns `&&mut &B` and `&&mut &C` not covered
note: `E` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:14:5
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&&mut &E`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL ~         E::A => {}
LL +         &&mut &B | &&mut &C => todo!()


error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
   |
   |
LL |     let E::A = e;
   |         ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `E` defined here
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&&mut &E`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     if let E::A = e { todo!() }
   |     ++              ~~~~~~~~~~~
error[E0004]: non-exhaustive patterns: `None` not covered
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:92:11
   |
   |
LL |     match e {//~ ERROR non-exhaustive patterns: `None` not covered
   |           ^ pattern `None` not covered
note: `Opt` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:84:5
   |
LL | enum Opt {
LL | enum Opt {
   |      ---
...
LL |     None,
   |     ^^^^ not covered
   = note: the matched value is of type `Opt`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         Opt::Some(ref _x) => {}
LL +         None => todo!()


error[E0005]: refutable pattern in local binding: `None` not covered
   |
   |
LL |     let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered
   |         ^^^^^^^^^^^^^^^^^ pattern `None` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Opt` defined here
   |
LL | enum Opt {
   |      ---
...
...
LL |     None,
   |     ^^^^ not covered
   = note: the matched value is of type `Opt`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() }; //~ ERROR refutable pattern in local binding: `None` not covered
   |     +++++++++++                           +++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Opt::Some(ref _x) = e else { todo!() }; //~ ERROR refutable pattern in local binding: `None` not covered

error: aborting due to 8 previous errors

Some errors have detailed explanations: E0004, E0005.
---
---- [ui] ui/recursion/recursive-types-are-not-uninhabited.rs stdout ----
diff of stderr:

23    |
24 LL |     let x = if let Ok(x) = res { x } else { todo!() };
25    |     ++++++++++                 ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
27    |
28 LL |     let Ok(x) = res else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited/recursive-types-are-not-uninhabited.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited/recursive-types-are-not-uninhabited.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args recursion/recursive-types-are-not-uninhabited.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   |
   |
LL |     let Ok(x) = res;
   |         ^^^^^ pattern `Err(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, &R>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, &R>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let x = if let Ok(x) = res { x } else { todo!() };
   |     ++++++++++                 ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Ok(x) = res else { todo!() };

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] ui/uninhabited/uninhabited-irrefutable.rs stdout ----
diff of stderr:

18    |
19 LL |     let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() };
20    |     +++++++++++++++++                        +++++++++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
22    |
23 LL |     let Foo::D(_y, _z) = x else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable/uninhabited-irrefutable.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable/uninhabited-irrefutable.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args uninhabited/uninhabited-irrefutable.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/uninhabited/uninhabited-irrefutable.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `A(_)` not covered
   |
   |
LL |     let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
   |         ^^^^^^^^^^^^^^ pattern `A(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Foo` defined here
   |
LL | enum Foo {
   |      ---
   |      ---
LL |     A(foo::SecretlyEmpty),
   = note: the matched value is of type `Foo`
   = note: the matched value is of type `Foo`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() }; //~ ERROR refutable pattern in local binding: `A(_)` not covered
   |     +++++++++++++++++                        +++++++++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Foo::D(_y, _z) = x else { todo!() }; //~ ERROR refutable pattern in local binding: `A(_)` not covered

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] ui/uninhabited/uninhabited-matches-feature-gated.rs stdout ----
diff of stderr:

134    |
135 LL |     let x = if let Ok(x) = x { x } else { todo!() };
136    |     ++++++++++               ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
138    |
139 LL |     let Ok(x) = x else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated/uninhabited-matches-feature-gated.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated/uninhabited-matches-feature-gated.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args uninhabited/uninhabited-matches-feature-gated.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/uninhabited/uninhabited-matches-feature-gated.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0004]: non-exhaustive patterns: `Err(_)` not covered
   |
   |
LL |     let _ = match x {   //~ ERROR non-exhaustive
   |                   ^ pattern `Err(_)` not covered
   |
note: `Result<u32, &Void>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, &Void>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         Ok(n) => n,
LL ~         Err(_) => todo!(),


error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
   |
   |
LL |     let _ = match x {}; //~ ERROR non-exhaustive
   |
   |
note: `Void` defined here
   |
   |
LL | enum Void {}
   = note: the matched value is of type `&Void`
   = note: references are always considered inhabited
   = note: references are always considered inhabited
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
   |
LL ~     let _ = match x {
LL +         _ => todo!(),
LL ~     }; //~ ERROR non-exhaustive


error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
   |
   |
LL |     let _ = match x {}; //~ ERROR non-exhaustive
   |
   |
   = note: the matched value is of type `(Void,)`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
   |
LL ~     let _ = match x {
LL +         _ => todo!(),
LL ~     }; //~ ERROR non-exhaustive


error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
   |
   |
LL |     let _ = match x {}; //~ ERROR non-exhaustive
   |
   |
   = note: the matched value is of type `[Void; 1]`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
   |
LL ~     let _ = match x {
LL +         _ => todo!(),
LL ~     }; //~ ERROR non-exhaustive


error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
   |
   |
LL |     let _ = match x {   //~ ERROR non-exhaustive
   |                   ^ pattern `&[_, ..]` not covered
   |
   = note: the matched value is of type `&[Void]`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         &[] => (),
LL ~         &[_, ..] => todo!(),


error[E0004]: non-exhaustive patterns: `Err(_)` not covered
   |
   |
LL |     let _ = match x {   //~ ERROR non-exhaustive
   |                   ^ pattern `Err(_)` not covered
   |
note: `Result<u32, Void>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, Void>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         Ok(x) => x,
LL ~         Err(_) => todo!(),


error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   |
   |
LL |     let Ok(x) = x;
   |         ^^^^^ pattern `Err(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, Void>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, Void>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let x = if let Ok(x) = x { x } else { todo!() };
   |     ++++++++++               ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Ok(x) = x else { todo!() };

error: aborting due to 7 previous errors

Some errors have detailed explanations: E0004, E0005.

rust-log-analyzer avatar Mar 13 '22 22:03 rust-log-analyzer

:umbrella: The latest upstream changes (presumably #95250) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Mar 24 '22 01:03 bors

The job x86_64-gnu-llvm-12 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
   Compiling rustc-demangle v0.1.21
error: the feature `let_else` has been stable since 1.61.0 and no longer requires an attribute to enable
   --> library/alloc/src/lib.rs:156:12
    |
156 | #![feature(let_else)]
    |
    |
    = note: `-D stable-features` implied by `-D warnings`
error: could not compile `alloc` due to previous error
warning: build failed, waiting for other jobs to finish...
Build completed unsuccessfully in 0:03:40

rust-log-analyzer avatar Apr 12 '22 14:04 rust-log-analyzer

The job x86_64-gnu-llvm-12 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
...................................i.................................................... 12144/12921
........................................................................................ 12232/12921
........................................................................................ 12320/12921
........................................................................................ 12408/12921
.............................F......F................................................... 12496/12921
........................................................................................ 12672/12921
........................................................................................ 12760/12921
......................................................iii............................... 12848/12921
.........................................................................
.........................................................................
failures:

---- [ui] src/test/ui/empty/empty-never-array.rs stdout ----
diff of stderr:

18    |
19 LL |     let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() };
20    |     ++++++++++                                     ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
22    |
23 LL |     let Helper::U(u) = Helper::T(t, []) else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array/empty-never-array.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array/empty-never-array.stderr
Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args empty/empty-never-array.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/empty/empty-never-array.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
   |
   |
LL |     let Helper::U(u) = Helper::T(t, []);
   |         ^^^^^^^^^^^^ pattern `T(_, _)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Helper<T, U>` defined here
   |
   |
LL | enum Helper<T, U> {
   |      ------
LL |     T(T, [!; 0]),
   |     ^ not covered
   = note: the matched value is of type `Helper<T, U>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() };
   |     ++++++++++                                     ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Helper::U(u) = Helper::T(t, []) else { todo!() };

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/error-codes/E0005.rs stdout ----
diff of stderr:

24    |
25 LL |     let y = if let Some(y) = x { y } else { todo!() };
26    |     ++++++++++                 ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
28    |
29 LL |     let Some(y) = x else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005/E0005.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005/E0005.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args error-codes/E0005.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/error-codes/E0005.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `None` not covered
   |
   |
LL |     let Some(y) = x; //~ ERROR E0005
   |         ^^^^^^^ pattern `None` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Option<i32>` defined here
   |
LL | / pub enum Option<T> {
LL | |     /// No value.
LL | |     /// No value.
LL | |     #[lang = "None"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
LL | |     None,
...  |
...  |
LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
LL | | }
   | |_-
   = note: the matched value is of type `Option<i32>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let y = if let Some(y) = x { y } else { todo!() }; //~ ERROR E0005
   |     ++++++++++                 ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Some(y) = x else { todo!() }; //~ ERROR E0005

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs stdout ----
diff of stderr:

23    |
24 LL |     let _x = if let Ok(_x) = foo() { _x } else { todo!() };
25    |     +++++++++++                    +++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
27    |
28 LL |     let Ok(_x) = foo() else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns/feature-gate-exhaustive-patterns.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns/feature-gate-exhaustive-patterns.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args feature-gates/feature-gate-exhaustive-patterns.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   |
   |
LL |     let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding
   |         ^^^^^^ pattern `Err(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, !>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, !>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let _x = if let Ok(_x) = foo() { _x } else { todo!() }; //~ ERROR refutable pattern in local binding
   |     +++++++++++                    +++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Ok(_x) = foo() else { todo!() }; //~ ERROR refutable pattern in local binding

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/pattern/usefulness/issue-31561.rs stdout ----
diff of stderr:

21    |
22 LL |     let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() };
23    |     ++++++++++                                   ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variants that aren't matched
25    |
26 LL |     let Thing::Foo(y) = Thing::Foo(1) else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561/issue-31561.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561/issue-31561.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args pattern/usefulness/issue-31561.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/pattern/usefulness/issue-31561.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
   |
   |
LL |     let Thing::Foo(y) = Thing::Foo(1);
   |         ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Thing` defined here
   |
LL | enum Thing {
   |      -----
LL |     Foo(u8),
LL |     Foo(u8),
LL |     Bar,
   |     ^^^ not covered
LL |     Baz
   |     ^^^ not covered
   = note: the matched value is of type `Thing`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() };
   |     ++++++++++                                   ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variants that aren't matched
   |
LL |     let Thing::Foo(y) = Thing::Foo(1) else { todo!() };

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs stdout ----
diff of stderr:

187    |
188 LL |     let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() };
189    |     +++++++++++                           +++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
191    |
192 LL |     let Opt::Some(ref _x) = e else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here/non-exhaustive-defined-here.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here/non-exhaustive-defined-here.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args pattern/usefulness/non-exhaustive-defined-here.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0004]: non-exhaustive patterns: `B` and `C` not covered
   |
   |
LL |     match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered
   |           ^^ patterns `B` and `C` not covered
note: `E` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:14:5
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `E`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL ~         E::A => {}
LL +         B | C => todo!()


error[E0005]: refutable pattern in local binding: `B` and `C` not covered
   |
   |
LL |     let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered
   |         ^^^^ patterns `B` and `C` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `E` defined here
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `E`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     if let E::A = e { todo!() } //~ ERROR refutable pattern in local binding: `B` and `C` not covered
   |     ++              ~~~~~~~~~~~

error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
   |
   |
LL |     match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered
   |           ^ patterns `&B` and `&C` not covered
note: `E` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:14:5
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&E`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL ~         E::A => {}
LL +         &B | &C => todo!()


error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered
   |
   |
LL |     let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
   |         ^^^^ patterns `&B` and `&C` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `E` defined here
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&E`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     if let E::A = e { todo!() } //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
   |     ++              ~~~~~~~~~~~

error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
   |
   |
LL |     match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
   |           ^ patterns `&&mut &B` and `&&mut &C` not covered
note: `E` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:14:5
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&&mut &E`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL ~         E::A => {}
LL +         &&mut &B | &&mut &C => todo!()


error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
   |
   |
LL |     let E::A = e;
   |         ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `E` defined here
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&&mut &E`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     if let E::A = e { todo!() }
   |     ++              ~~~~~~~~~~~
error[E0004]: non-exhaustive patterns: `None` not covered
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:92:11
   |
   |
LL |     match e {//~ ERROR non-exhaustive patterns: `None` not covered
   |           ^ pattern `None` not covered
note: `Opt` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:84:5
   |
LL | enum Opt {
LL | enum Opt {
   |      ---
...
LL |     None,
   |     ^^^^ not covered
   = note: the matched value is of type `Opt`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         Opt::Some(ref _x) => {}
LL +         None => todo!()


error[E0005]: refutable pattern in local binding: `None` not covered
   |
   |
LL |     let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered
   |         ^^^^^^^^^^^^^^^^^ pattern `None` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Opt` defined here
   |
LL | enum Opt {
   |      ---
...
...
LL |     None,
   |     ^^^^ not covered
   = note: the matched value is of type `Opt`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() }; //~ ERROR refutable pattern in local binding: `None` not covered
   |     +++++++++++                           +++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Opt::Some(ref _x) = e else { todo!() }; //~ ERROR refutable pattern in local binding: `None` not covered

error: aborting due to 8 previous errors

Some errors have detailed explanations: E0004, E0005.
---
---- [ui] src/test/ui/recursion/recursive-types-are-not-uninhabited.rs stdout ----
diff of stderr:

23    |
24 LL |     let x = if let Ok(x) = res { x } else { todo!() };
25    |     ++++++++++                 ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
27    |
28 LL |     let Ok(x) = res else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited/recursive-types-are-not-uninhabited.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited/recursive-types-are-not-uninhabited.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args recursion/recursive-types-are-not-uninhabited.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   |
   |
LL |     let Ok(x) = res;
   |         ^^^^^ pattern `Err(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, &R>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, &R>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let x = if let Ok(x) = res { x } else { todo!() };
   |     ++++++++++                 ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Ok(x) = res else { todo!() };

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs stdout ----
diff of stderr:

73    |
74    = note: only supported directly in conditions of `if` and `while` expressions
75 
+ warning: the feature `let_else` has been stable since 1.61.0 and no longer requires an attribute to enable
+   --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:1:24
+    |
+ LL | #![feature(let_chains, let_else)]
+    |
+    = note: `#[warn(stable_features)]` on by default
+ 
76 error[E0308]: mismatched types
---
To only update this specific test, also pass `--test-args rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains/auxiliary"
stdout: none
--- stderr -------------------------------
error: a `&&` expression cannot be directly assigned in `let...else`
   |
   |
LL |     let Some(n) = opt && n == 1 else {
   |
help: wrap the expression in parentheses
   |
   |
LL |     let Some(n) = (opt && n == 1) else {


error: a `&&` expression cannot be directly assigned in `let...else`
   |
   |
LL |     let Some(n) = opt && let another = n else {
   |
help: wrap the expression in parentheses
   |
   |
LL |     let Some(n) = (opt && let another = n) else {

error: missing condition for `if` expression
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:23:7
   |
   |
LL |     if let Some(n) = opt else {
   |       ^ expected if condition here
error: missing condition for `if` expression
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:27:7
   |
   |
LL |     if let Some(n) = opt && n == 1 else {
   |       ^ expected if condition here
error: missing condition for `if` expression
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:31:7
   |
   |
LL |     if let Some(n) = opt && let another = n else {
   |       ^ expected if condition here

error: expected `{`, found keyword `else`
   |
   |
LL |         while let Some(n) = opt else {
   |         ----- ----------------- ^^^^ expected `{`
   |         |     |
   |         |     this `while` condition successfully parsed
   |         while parsing the body of this `while` expression

error: expected `{`, found keyword `else`
   |
   |
LL |         while let Some(n) = opt && n == 1 else {
   |         ----- --------------------------- ^^^^ expected `{`
   |         |     |
   |         |     this `while` condition successfully parsed
   |         while parsing the body of this `while` expression

error: expected `{`, found keyword `else`
   |
   |
LL |         while let Some(n) = opt && let another = n else {
   |         ----- ------------------------------------ ^^^^ expected `{`
   |         |     |
   |         |     this `while` condition successfully parsed
   |         while parsing the body of this `while` expression
error: `let` expressions are not supported here
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:26
   |
   |
LL |     let Some(n) = opt && let another = n else {
   |
   |
   = note: only supported directly in conditions of `if` and `while` expressions
warning: the feature `let_else` has been stable since 1.61.0 and no longer requires an attribute to enable
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:1:24
   |
   |
LL | #![feature(let_chains, let_else)]
   |
   = note: `#[warn(stable_features)]` on by default

error[E0308]: mismatched types
error[E0308]: mismatched types
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:19
   |
LL |     let Some(n) = opt && n == 1 else {
   |                   ^^^ expected `bool`, found enum `Option`
   = note: expected type `bool`
              found enum `Option<i32>`

error[E0308]: mismatched types
error[E0308]: mismatched types
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:9
   |
LL |     let Some(n) = opt && n == 1 else {
   |         ^^^^^^^   ------------- this expression has type `bool`
   |         expected `bool`, found enum `Option`
   |
   = note: expected type `bool`
              found enum `Option<_>`
              found enum `Option<_>`

error[E0308]: mismatched types
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:19
   |
LL |     let Some(n) = opt && let another = n else {
   |                   ^^^ expected `bool`, found enum `Option`
   = note: expected type `bool`
              found enum `Option<i32>`

error[E0308]: mismatched types
error[E0308]: mismatched types
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:9
   |
LL |     let Some(n) = opt && let another = n else {
   |         ^^^^^^^   ---------------------- this expression has type `bool`
   |         expected `bool`, found enum `Option`
   |
   = note: expected type `bool`
              found enum `Option<_>`
---
---- [ui] src/test/ui/uninhabited/uninhabited-irrefutable.rs stdout ----
diff of stderr:

18    |
19 LL |     let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() };
20    |     +++++++++++++++++                        +++++++++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
22    |
23 LL |     let Foo::D(_y, _z) = x else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable/uninhabited-irrefutable.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable/uninhabited-irrefutable.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args uninhabited/uninhabited-irrefutable.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/uninhabited/uninhabited-irrefutable.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `A(_)` not covered
   |
   |
LL |     let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
   |         ^^^^^^^^^^^^^^ pattern `A(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Foo` defined here
   |
LL | enum Foo {
   |      ---
   |      ---
LL |     A(foo::SecretlyEmpty),
   = note: the matched value is of type `Foo`
   = note: the matched value is of type `Foo`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() }; //~ ERROR refutable pattern in local binding: `A(_)` not covered
   |     +++++++++++++++++                        +++++++++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Foo::D(_y, _z) = x else { todo!() }; //~ ERROR refutable pattern in local binding: `A(_)` not covered

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/uninhabited/uninhabited-matches-feature-gated.rs stdout ----
diff of stderr:

134    |
135 LL |     let x = if let Ok(x) = x { x } else { todo!() };
136    |     ++++++++++               ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
138    |
139 LL |     let Ok(x) = x else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated/uninhabited-matches-feature-gated.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated/uninhabited-matches-feature-gated.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args uninhabited/uninhabited-matches-feature-gated.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/uninhabited/uninhabited-matches-feature-gated.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0004]: non-exhaustive patterns: `Err(_)` not covered
   |
   |
LL |     let _ = match x {   //~ ERROR non-exhaustive
   |                   ^ pattern `Err(_)` not covered
   |
note: `Result<u32, &Void>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, &Void>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         Ok(n) => n,
LL ~         Err(_) => todo!(),


error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
   |
   |
LL |     let _ = match x {}; //~ ERROR non-exhaustive
   |
   |
note: `Void` defined here
   |
   |
LL | enum Void {}
   = note: the matched value is of type `&Void`
   = note: references are always considered inhabited
   = note: references are always considered inhabited
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
   |
LL ~     let _ = match x {
LL +         _ => todo!(),
LL ~     }; //~ ERROR non-exhaustive


error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
   |
   |
LL |     let _ = match x {}; //~ ERROR non-exhaustive
   |
   |
   = note: the matched value is of type `(Void,)`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
   |
LL ~     let _ = match x {
LL +         _ => todo!(),
LL ~     }; //~ ERROR non-exhaustive


error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
   |
   |
LL |     let _ = match x {}; //~ ERROR non-exhaustive
   |
   |
   = note: the matched value is of type `[Void; 1]`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
   |
LL ~     let _ = match x {
LL +         _ => todo!(),
LL ~     }; //~ ERROR non-exhaustive


error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
   |
   |
LL |     let _ = match x {   //~ ERROR non-exhaustive
   |                   ^ pattern `&[_, ..]` not covered
   |
   = note: the matched value is of type `&[Void]`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         &[] => (),
LL ~         &[_, ..] => todo!(),


error[E0004]: non-exhaustive patterns: `Err(_)` not covered
   |
   |
LL |     let _ = match x {   //~ ERROR non-exhaustive
   |                   ^ pattern `Err(_)` not covered
   |
note: `Result<u32, Void>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, Void>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         Ok(x) => x,
LL ~         Err(_) => todo!(),


error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   |
   |
LL |     let Ok(x) = x;
   |         ^^^^^ pattern `Err(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, Void>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, Void>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let x = if let Ok(x) = x { x } else { todo!() };
   |     ++++++++++               ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Ok(x) = x else { todo!() };

error: aborting due to 7 previous errors

Some errors have detailed explanations: E0004, E0005.

rust-log-analyzer avatar Apr 12 '22 16:04 rust-log-analyzer

:umbrella: The latest upstream changes (presumably #96087) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Apr 15 '22 21:04 bors

@dingxiangfei2009, @pnkfelix, and I got together to discuss alternatives around adjusting the desugaring. We concluded that there is no way to represent the desired temporary lifetimes if we desugar let-else in the existing HIR, and that we ought to extend the HIR with a specific let-else construct. Here are our notes:

https://hackmd.io/@nikomatsakis/r1CpZqc8c

Personally, I think we desugar too much at the HIR level and make our lives harder than they have to be (e.g., I don't think we should desugar for either until MIR construction), but @pnkfelix felt a bit sad about the idea of adding let-else. =) Anyway, if people have other ideas for how to manage the desugaring, we're all ears!

In the meantime, @dingxiangfei2009 is going to start exploring what it would like to extend HIR with let-else as a native construct -- we will see how cleanly it works out.

nikomatsakis avatar May 12 '22 14:05 nikomatsakis

we ought to extend the HIR with a specific let-else construct.

Just so it isn't lost in the ether: the concrete idea is to add support for let-else on the existing HIR node for Let, by adding the expression as an Option field. (Rather than, say, adding a totally new and separate variant somewhere.)

pnkfelix avatar May 12 '22 14:05 pnkfelix

The job x86_64-gnu-llvm-12 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
........................................................................................ 3080/13089
........................................................................................ 3168/13089
...............iiiii.................................................................... 3256/13089
........................................................................................ 3344/13089
..F.........................................................F........................... 3432/13089
........................................................................................ 3608/13089
........................................................................................ 3696/13089
.................................i..........i..........i................................ 3784/13089
..................................................................F..................... 3872/13089
---
........................................................................................ 9064/13089
...........i............................................................................ 9152/13089
........................................................................................ 9240/13089
........................................................................................ 9328/13089
..................................................F...................................F. 9416/13089
........................................................................................ 9592/13089
........................................................................................ 9680/13089
.....ii...............i..........................................................ii..... 9768/13089
........................................................................................ 9856/13089
---
...................i.................................................................... 12320/13089
........................................................................................ 12408/13089
........................................................................................ 12496/13089
........................................................................................ 12584/13089
........................F...F........................................................... 12672/13089
........................................................................................ 12848/13089
........................................................................................ 12936/13089
..............................................iii....................................... 13024/13089
.................................................................
.................................................................
failures:

---- [ui] src/test/ui/empty/empty-never-array.rs stdout ----
diff of stderr:

18    |
19 LL |     let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() };
20    |     ++++++++++                                     ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
22    |
23 LL |     let Helper::U(u) = Helper::T(t, []) else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array/empty-never-array.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array/empty-never-array.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args empty/empty-never-array.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/empty/empty-never-array.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/empty/empty-never-array/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
   |
Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu
Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu
LL |     let Helper::U(u) = Helper::T(t, []);
   |         ^^^^^^^^^^^^ pattern `T(_, _)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Helper<T, U>` defined here
   |
   |
LL | enum Helper<T, U> {
   |      ------
LL |     T(T, [!; 0]),
   |     ^ not covered
   = note: the matched value is of type `Helper<T, U>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() };
   |     ++++++++++                                     ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Helper::U(u) = Helper::T(t, []) else { todo!() };

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/error-codes/E0005.rs stdout ----
diff of stderr:

24    |
25 LL |     let y = if let Some(y) = x { y } else { todo!() };
26    |     ++++++++++                 ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
28    |
29 LL |     let Some(y) = x else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005/E0005.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005/E0005.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args error-codes/E0005.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/error-codes/E0005.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/error-codes/E0005/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `None` not covered
   |
   |
LL |     let Some(y) = x; //~ ERROR E0005
   |         ^^^^^^^ pattern `None` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Option<i32>` defined here
   |
LL | / pub enum Option<T> {
LL | |     /// No value.
LL | |     /// No value.
LL | |     #[lang = "None"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
LL | |     None,
...  |
...  |
LL | |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
LL | | }
   | |_-
   = note: the matched value is of type `Option<i32>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let y = if let Some(y) = x { y } else { todo!() }; //~ ERROR E0005
   |     ++++++++++                 ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Some(y) = x else { todo!() }; //~ ERROR E0005

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs stdout ----
diff of stderr:

23    |
24 LL |     let _x = if let Ok(_x) = foo() { _x } else { todo!() };
25    |     +++++++++++                    +++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
27    |
28 LL |     let Ok(_x) = foo() else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns/feature-gate-exhaustive-patterns.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns/feature-gate-exhaustive-patterns.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args feature-gates/feature-gate-exhaustive-patterns.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/feature-gates/feature-gate-exhaustive-patterns/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   |
   |
LL |     let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding
   |         ^^^^^^ pattern `Err(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, !>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, !>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let _x = if let Ok(_x) = foo() { _x } else { todo!() }; //~ ERROR refutable pattern in local binding
   |     +++++++++++                    +++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Ok(_x) = foo() else { todo!() }; //~ ERROR refutable pattern in local binding

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/pattern/usefulness/issue-31561.rs stdout ----
diff of stderr:

21    |
22 LL |     let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() };
23    |     ++++++++++                                   ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variants that aren't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variants that aren't matched
25    |
26 LL |     let Thing::Foo(y) = Thing::Foo(1) else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561/issue-31561.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561/issue-31561.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args pattern/usefulness/issue-31561.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/pattern/usefulness/issue-31561.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/issue-31561/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
   |
   |
LL |     let Thing::Foo(y) = Thing::Foo(1);
   |         ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Thing` defined here
   |
LL | enum Thing {
   |      -----
LL |     Foo(u8),
LL |     Foo(u8),
LL |     Bar,
   |     ^^^ not covered
LL |     Baz
   |     ^^^ not covered
   = note: the matched value is of type `Thing`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() };
   |     ++++++++++                                   ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variants that aren't matched
   |
LL |     let Thing::Foo(y) = Thing::Foo(1) else { todo!() };

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs stdout ----
diff of stderr:

187    |
188 LL |     let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() };
189    |     +++++++++++                           +++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
191    |
192 LL |     let Opt::Some(ref _x) = e else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here/non-exhaustive-defined-here.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here/non-exhaustive-defined-here.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args pattern/usefulness/non-exhaustive-defined-here.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/pattern/usefulness/non-exhaustive-defined-here/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0004]: non-exhaustive patterns: `B` and `C` not covered
   |
   |
LL |     match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered
   |           ^^ patterns `B` and `C` not covered
note: `E` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:14:5
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `E`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL ~         E::A => {}
LL +         B | C => todo!()


error[E0005]: refutable pattern in local binding: `B` and `C` not covered
   |
   |
LL |     let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered
   |         ^^^^ patterns `B` and `C` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `E` defined here
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `E`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     if let E::A = e { todo!() } //~ ERROR refutable pattern in local binding: `B` and `C` not covered
   |     ++              ~~~~~~~~~~~

error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
   |
   |
LL |     match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered
   |           ^ patterns `&B` and `&C` not covered
note: `E` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:14:5
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&E`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL ~         E::A => {}
LL +         &B | &C => todo!()


error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered
   |
   |
LL |     let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
   |         ^^^^ patterns `&B` and `&C` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `E` defined here
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&E`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     if let E::A = e { todo!() } //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
   |     ++              ~~~~~~~~~~~

error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
   |
   |
LL |     match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
   |           ^ patterns `&&mut &B` and `&&mut &C` not covered
note: `E` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:14:5
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&&mut &E`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL ~         E::A => {}
LL +         &&mut &B | &&mut &C => todo!()


error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
   |
   |
LL |     let E::A = e;
   |         ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `E` defined here
   |
   |
LL | enum E {
...
LL |     B,
   |     ^ not covered
...
...
LL |     C
   |     ^ not covered
   = note: the matched value is of type `&&mut &E`
help: you might want to use `if let` to ignore the variants that aren't matched
   |
LL |     if let E::A = e { todo!() }
   |     ++              ~~~~~~~~~~~
error[E0004]: non-exhaustive patterns: `None` not covered
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:92:11
   |
   |
LL |     match e {//~ ERROR non-exhaustive patterns: `None` not covered
   |           ^ pattern `None` not covered
note: `Opt` defined here
  --> /checkout/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs:84:5
   |
LL | enum Opt {
LL | enum Opt {
   |      ---
...
LL |     None,
   |     ^^^^ not covered
   = note: the matched value is of type `Opt`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         Opt::Some(ref _x) => {}
LL +         None => todo!()


error[E0005]: refutable pattern in local binding: `None` not covered
   |
   |
LL |     let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered
   |         ^^^^^^^^^^^^^^^^^ pattern `None` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Opt` defined here
   |
LL | enum Opt {
   |      ---
...
...
LL |     None,
   |     ^^^^ not covered
   = note: the matched value is of type `Opt`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() }; //~ ERROR refutable pattern in local binding: `None` not covered
   |     +++++++++++                           +++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Opt::Some(ref _x) = e else { todo!() }; //~ ERROR refutable pattern in local binding: `None` not covered

error: aborting due to 8 previous errors

Some errors have detailed explanations: E0004, E0005.
---
---- [ui] src/test/ui/recursion/recursive-types-are-not-uninhabited.rs stdout ----
diff of stderr:

23    |
24 LL |     let x = if let Ok(x) = res { x } else { todo!() };
25    |     ++++++++++                 ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
27    |
28 LL |     let Ok(x) = res else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited/recursive-types-are-not-uninhabited.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited/recursive-types-are-not-uninhabited.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args recursion/recursive-types-are-not-uninhabited.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/recursion/recursive-types-are-not-uninhabited.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/recursion/recursive-types-are-not-uninhabited/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   |
   |
LL |     let Ok(x) = res;
   |         ^^^^^ pattern `Err(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, &R>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, &R>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let x = if let Ok(x) = res { x } else { todo!() };
   |     ++++++++++                 ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Ok(x) = res else { todo!() };

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs stdout ----
diff of stderr:

73    |
74    = note: only supported directly in conditions of `if` and `while` expressions
75 
+ warning: the feature `let_else` has been stable since 1.61.0 and no longer requires an attribute to enable
+   --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:1:24
+    |
+ LL | #![feature(let_chains, let_else)]
+    |
+    = note: `#[warn(stable_features)]` on by default
+ 
76 error[E0308]: mismatched types
---
To only update this specific test, also pass `--test-args rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains/auxiliary"
stdout: none
--- stderr -------------------------------
error: a `&&` expression cannot be directly assigned in `let...else`
   |
   |
LL |     let Some(n) = opt && n == 1 else {
   |
help: wrap the expression in parentheses
   |
   |
LL |     let Some(n) = (opt && n == 1) else {


error: a `&&` expression cannot be directly assigned in `let...else`
   |
   |
LL |     let Some(n) = opt && let another = n else {
   |
help: wrap the expression in parentheses
   |
   |
LL |     let Some(n) = (opt && let another = n) else {

error: missing condition for `if` expression
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:23:7
   |
   |
LL |     if let Some(n) = opt else {
   |       ^ expected if condition here
error: missing condition for `if` expression
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:27:7
   |
   |
LL |     if let Some(n) = opt && n == 1 else {
   |       ^ expected if condition here
error: missing condition for `if` expression
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:31:7
   |
   |
LL |     if let Some(n) = opt && let another = n else {
   |       ^ expected if condition here

error: expected `{`, found keyword `else`
   |
   |
LL |         while let Some(n) = opt else {
   |         ----- ----------------- ^^^^ expected `{`
   |         |     |
   |         |     this `while` condition successfully parsed
   |         while parsing the body of this `while` expression

error: expected `{`, found keyword `else`
   |
   |
LL |         while let Some(n) = opt && n == 1 else {
   |         ----- --------------------------- ^^^^ expected `{`
   |         |     |
   |         |     this `while` condition successfully parsed
   |         while parsing the body of this `while` expression

error: expected `{`, found keyword `else`
   |
   |
LL |         while let Some(n) = opt && let another = n else {
   |         ----- ------------------------------------ ^^^^ expected `{`
   |         |     |
   |         |     this `while` condition successfully parsed
   |         while parsing the body of this `while` expression
error: `let` expressions are not supported here
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:26
   |
   |
LL |     let Some(n) = opt && let another = n else {
   |
   |
   = note: only supported directly in conditions of `if` and `while` expressions
warning: the feature `let_else` has been stable since 1.61.0 and no longer requires an attribute to enable
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:1:24
   |
   |
LL | #![feature(let_chains, let_else)]
   |
   = note: `#[warn(stable_features)]` on by default

error[E0308]: mismatched types
error[E0308]: mismatched types
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:19
   |
LL |     let Some(n) = opt && n == 1 else {
   |                   ^^^ expected `bool`, found enum `Option`
   = note: expected type `bool`
              found enum `Option<i32>`

error[E0308]: mismatched types
error[E0308]: mismatched types
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:9
   |
LL |     let Some(n) = opt && n == 1 else {
   |         ^^^^^^^   ------------- this expression has type `bool`
   |         expected `bool`, found enum `Option`
   |
   = note: expected type `bool`
              found enum `Option<_>`
              found enum `Option<_>`

error[E0308]: mismatched types
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:19
   |
LL |     let Some(n) = opt && let another = n else {
   |                   ^^^ expected `bool`, found enum `Option`
   = note: expected type `bool`
              found enum `Option<i32>`

error[E0308]: mismatched types
error[E0308]: mismatched types
  --> /checkout/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs:15:9
   |
LL |     let Some(n) = opt && let another = n else {
   |         ^^^^^^^   ---------------------- this expression has type `bool`
   |         expected `bool`, found enum `Option`
   |
   = note: expected type `bool`
              found enum `Option<_>`
---
---- [ui] src/test/ui/uninhabited/uninhabited-irrefutable.rs stdout ----
diff of stderr:

18    |
19 LL |     let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() };
20    |     +++++++++++++++++                        +++++++++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
22    |
23 LL |     let Foo::D(_y, _z) = x else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable/uninhabited-irrefutable.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable/uninhabited-irrefutable.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args uninhabited/uninhabited-irrefutable.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/uninhabited/uninhabited-irrefutable.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-irrefutable/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0005]: refutable pattern in local binding: `A(_)` not covered
   |
   |
LL |     let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
   |         ^^^^^^^^^^^^^^ pattern `A(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Foo` defined here
   |
LL | enum Foo {
   |      ---
   |      ---
LL |     A(foo::SecretlyEmpty),
   = note: the matched value is of type `Foo`
   = note: the matched value is of type `Foo`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() }; //~ ERROR refutable pattern in local binding: `A(_)` not covered
   |     +++++++++++++++++                        +++++++++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Foo::D(_y, _z) = x else { todo!() }; //~ ERROR refutable pattern in local binding: `A(_)` not covered

error: aborting due to previous error

For more information about this error, try `rustc --explain E0005`.
For more information about this error, try `rustc --explain E0005`.
------------------------------------------


---- [ui] src/test/ui/uninhabited/uninhabited-matches-feature-gated.rs stdout ----
diff of stderr:

134    |
135 LL |     let x = if let Ok(x) = x { x } else { todo!() };
136    |     ++++++++++               ++++++++++++++++++++++
- help: alternatively, on nightly, you might want to use `#![feature(let_else)]` to handle the variant that isn't matched
+ help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
138    |
139 LL |     let Ok(x) = x else { todo!() };


The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated/uninhabited-matches-feature-gated.stderr
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated/uninhabited-matches-feature-gated.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args uninhabited/uninhabited-matches-feature-gated.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/uninhabited/uninhabited-matches-feature-gated.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/uninhabited/uninhabited-matches-feature-gated/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0004]: non-exhaustive patterns: `Err(_)` not covered
   |
   |
LL |     let _ = match x {   //~ ERROR non-exhaustive
   |                   ^ pattern `Err(_)` not covered
   |
note: `Result<u32, &Void>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, &Void>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         Ok(n) => n,
LL ~         Err(_) => todo!(),


error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
   |
   |
LL |     let _ = match x {}; //~ ERROR non-exhaustive
   |
   |
note: `Void` defined here
   |
   |
LL | enum Void {}
   = note: the matched value is of type `&Void`
   = note: references are always considered inhabited
   = note: references are always considered inhabited
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
   |
LL ~     let _ = match x {
LL +         _ => todo!(),
LL ~     }; //~ ERROR non-exhaustive


error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
   |
   |
LL |     let _ = match x {}; //~ ERROR non-exhaustive
   |
   |
   = note: the matched value is of type `(Void,)`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
   |
LL ~     let _ = match x {
LL +         _ => todo!(),
LL ~     }; //~ ERROR non-exhaustive


error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
   |
   |
LL |     let _ = match x {}; //~ ERROR non-exhaustive
   |
   |
   = note: the matched value is of type `[Void; 1]`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
   |
LL ~     let _ = match x {
LL +         _ => todo!(),
LL ~     }; //~ ERROR non-exhaustive


error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
   |
   |
LL |     let _ = match x {   //~ ERROR non-exhaustive
   |                   ^ pattern `&[_, ..]` not covered
   |
   = note: the matched value is of type `&[Void]`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         &[] => (),
LL ~         &[_, ..] => todo!(),


error[E0004]: non-exhaustive patterns: `Err(_)` not covered
   |
   |
LL |     let _ = match x {   //~ ERROR non-exhaustive
   |                   ^ pattern `Err(_)` not covered
   |
note: `Result<u32, Void>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, Void>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
   |
LL ~         Ok(x) => x,
LL ~         Err(_) => todo!(),


error[E0005]: refutable pattern in local binding: `Err(_)` not covered
   |
   |
LL |     let Ok(x) = x;
   |         ^^^^^ pattern `Err(_)` not covered
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, Void>` defined here
   |
LL | / pub enum Result<T, E> {
LL | |     /// Contains the success value
LL | |     /// Contains the success value
LL | |     #[lang = "Ok"]
LL | |     #[stable(feature = "rust1", since = "1.0.0")]
...  |
LL | |     Err(#[stable(feature = "rust1", since = "1.0.0")] E),
LL | | }
   | |_-
   | |_-
   = note: the matched value is of type `Result<u32, Void>`
help: you might want to use `if let` to ignore the variant that isn't matched
   |
LL |     let x = if let Ok(x) = x { x } else { todo!() };
   |     ++++++++++               ++++++++++++++++++++++
help: alternatively, on nightly, you might want to use `#![cfg_attr(bootstrap, feature(let_else))]` to handle the variant that isn't matched
   |
LL |     let Ok(x) = x else { todo!() };

error: aborting due to 7 previous errors

Some errors have detailed explanations: E0004, E0005.

rust-log-analyzer avatar May 12 '22 21:05 rust-log-analyzer

:umbrella: The latest upstream changes (presumably #96885) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar May 15 '22 14:05 bors

The job x86_64-gnu-llvm-12 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
   Compiling gimli v0.26.1
error: the feature `let_else` has been stable since 1.61.0 and no longer requires an attribute to enable
  --> compiler/rustc_serialize/src/lib.rs:18:12
   |
18 | #![feature(let_else)]
   |
   |
   = note: `-D stable-features` implied by `-D warnings`
   Compiling sha-1 v0.10.0
   Compiling md-5 v0.10.0
   Compiling sha2 v0.10.1
error: could not compile `rustc_serialize` due to previous error

rust-log-analyzer avatar May 16 '22 05:05 rust-log-analyzer

:umbrella: The latest upstream changes (presumably #97239) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar May 21 '22 09:05 bors

The job x86_64-gnu-llvm-12 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
   Compiling rustc_macros v0.1.0 (/checkout/compiler/rustc_macros)
error: unexpected `cfg` condition name
 --> compiler/rustc_macros/src/lib.rs:2:13
  |
2 | #![cfg_attr(bootstrap, feature(let_else))]
  |
  |
  = note: `-D unexpected-cfgs` implied by `-D warnings`
   Compiling tracing-tree v0.2.0
   Compiling chalk-solve v0.80.0
   Compiling rustc_log v0.0.0 (/checkout/compiler/rustc_log)
error: could not compile `rustc_macros` due to previous error

rust-log-analyzer avatar Jun 14 '22 03:06 rust-log-analyzer

Hmm this is a weird build failure:

error: unexpected `cfg` condition name
 --> compiler/rustc_macros/src/lib.rs:2:13
  |
2 | #![cfg_attr(bootstrap, feature(let_else))]
  |
  |
  = note: `-D unexpected-cfgs` implied by `-D warnings`

I can reproduce it locally if I do ./x.py test clippy -v. cargo is invoked with -Zcheck-cfg and thus adds all the corresponding flags to rustc, including the ones to enable cfg checking. But somehow the additional flags added for the rustc custom cfg flags that are set in bootstrap are missing. I've filed #98080 to make the code emit nicer flags, but that PR does not fix the build issue. I feel that the rustflags are added (because that code is the only place that enables cargo's -Zcheck-cfg flag), and then later discarded... While that code is not the cause of the build issue, I think it's somewhere else in bootstrap.

est31 avatar Jun 14 '22 04:06 est31

I recently came across RUSTDOCFLAGS (and RUSTFLAGS) not being passed along by cargo if a specific nightly feature is active: https://github.com/rust-lang/cargo/issues/10744

Maybe bootstrap also uses this, or some other nightly Cargo feature(s) that trigger the same bug?

jplatte avatar Jun 14 '22 06:06 jplatte

I investigated the build issue and contrary to what I originally though this is a legitimate build error because bootstrap is never set for proc-macro crates.

The reason why is because when cargo compiles a proc-macro crate it doesn't forward the RUSTFLAGS if --target is also passed to cargo (which is always the case with bootstrap); this means that none of the --check-cfg arguments are passed to rustc except for the one explicitly set by cargo -Zcheck-cfg AND because of this --cfg=bootstrap is also not passed to rustc which means that bootstrap cfg key is not accessible when compiling a proc-macro crate which means that the build error is legitimate.

Urgau avatar Jun 14 '22 11:06 Urgau

Yes, that's https://github.com/rust-lang/cargo/issues/4423 and what I really should have linked to. I guess the other issue only affects cargo doc. Is the compiler using unstable cargo features? -Ztarget-applies-to-host + CARGO_TARGET_APPLIES_TO_HOST=false (or the equivalent .cargo/config.toml entry) should fix this.

jplatte avatar Jun 14 '22 11:06 jplatte

Brief update: @dingxiangfei2009 and I have been working on a refactoring to fix the temporary scope issues as discussed here. Progress is being made! Still working on it, though.

nikomatsakis avatar Jun 14 '22 17:06 nikomatsakis

Thanks @jplatte and @Urgau for the help. I have allowed lint for that crate for now, which can go to master until a better approach is found. Maybe I'll send that as a separate PR to this one, as I don't know when this one will be merged and others might run into the same issue with rustc_macros. I have also made a comment on the dedicated cargo --check-cfg tracking issue so that this discovery is not forgotten about from the --check-cfg stabilization for cargo point of view (it's a cargo bug so doesn't block stabilization of the rustc side of things). Ideally that's discussed in the dedicated cargo issue though.

I would also like to thank @nikomatsakis for the update. Very glad that there is progress.

est31 avatar Jun 14 '22 23:06 est31

The job mingw-check failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
configure: rust.debug-assertions := True
configure: rust.overflow-checks := True
configure: llvm.assertions      := True
configure: dist.missing-tools   := True
configure: build.configure-args := ['--enable-sccache', '--disable-manage-submodu ...
configure: writing `config.toml` in current directory
configure: 
configure: run `python /checkout/x.py --help`
configure: 
---
skip untracked path cpu-usage.csv during rustfmt invocations
skip untracked path src/doc/book/ during rustfmt invocations
skip untracked path src/doc/rust-by-example/ during rustfmt invocations
skip untracked path src/llvm-project/ during rustfmt invocations
Diff in /checkout/compiler/rustc_macros/src/lib.rs at line 5:
 #![feature(proc_macro_span)]
 #![allow(rustc::default_hash_types)]
 #![recursion_limit = "128"]
-
 // We allow the unexpected_cfgs feature for this crate, as RUSTFLAGS don't make
 // it into host scripts like build.rs or proc macros, at least during cross
 // compilation: https://github.com/rust-lang/cargo/issues/4423
Running `"/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/rustfmt" "--config-path" "/checkout" "--edition" "2021" "--unstable-features" "--skip-children" "--check" "/checkout/compiler/rustc_macros/src/lib.rs" "/checkout/src/librustdoc/html/markdown.rs" "/checkout/src/librustdoc/html/length_limit.rs" "/checkout/src/librustdoc/html/escape.rs" "/checkout/src/librustdoc/html/highlight.rs" "/checkout/src/librustdoc/html/url_parts_builder/tests.rs" "/checkout/src/librustdoc/html/render/tests.rs" "/checkout/src/librustdoc/html/length_limit/tests.rs"` failed.
If you're running `tidy`, try again with `--bless`. Or, if you just want to format code, run `./x.py fmt` instead.

rust-log-analyzer avatar Jun 15 '22 01:06 rust-log-analyzer

Thanks @jplatte and @Urgau for the help. I have allowed lint for that crate for now, which can go to master until a better approach is found.

This is wrong! Because if the --check-cfg arguments are not set that also means that the --cfg arguments aren't also. Allowing the lint is not right, this only hides the fact that you simply can't currently use cfg(bootstrap) in a proc-macro crate in the codebase.

For once the --check-cfg integration is working as expected, bootstrap IS unexpected because as I've noted in https://github.com/rust-lang/rust/pull/93628#issuecomment-1155042688 the RUSTFLAGS set by bootstrap aren't forwarded to the proc-macro crates, that includes --cfg=bootstrap.

EDIT: This later appears to not be true, as bootstrap use a very ugly hack to force --cfg=bootstrap to be passed to rustc.

Urgau avatar Jun 15 '22 09:06 Urgau

@Urgau try adding this to rustc_macros, and then do x.py check:

#[cfg(bootstrap)]
compile_error!("bootstrap was hit!");

You will get a compiler error (at least I do). Same goes for removing the line which is what you suggest. That it errors is weird though because when I add the -v parameter, no --cfg=bootstrap is part of the invocation (while it is for other compiler crates). How this works? No idea, I need to investigate.

est31 avatar Jun 15 '22 17:06 est31

Ahh apparently it is a bug in bootstrap after all, namely the rustc shim, because here the bootstrap cfg flag is set even for proc macros: https://github.com/rust-lang/rust/blob/c3605f8c8020dbbe8f0d1961c7b33c4c4b78ad0d/src/bootstrap/bin/rustc.rs#L130-L135

Outside of that the argument of cfg in RUSTFLAGS not getting passed to proc macros either makes a lot of sense, so I think it's not an issue that should affect the --check-cfg feature.

I will send a separate PR for this.

est31 avatar Jun 15 '22 19:06 est31

Hum... okay! I didn't see that coming. Sorry for the later comment and thanks for the future PR.

Urgau avatar Jun 15 '22 20:06 Urgau

@Urgau it's fine, to be honest I have missed the part in your initial comment where you said that the lint's error was accurate, so I didn't reply to it before you repeated it. It actually cleared up some of the misconceptions I had. Thanks for your work on --check-cfg, it's not an easy feature to get right.

As to why this is only an issue now, and hasn't been one before I rebased, because rustc had been using --check-cfg before my rebase one month ago as well, it's because let_else has been introduced to rustc_macro after my last rebase: 49ec909ca7d6.

PR is filed: #98147

est31 avatar Jun 15 '22 20:06 est31

:umbrella: The latest upstream changes (presumably #98161) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Jun 16 '22 10:06 bors

I opened #98672 for the temporaries issue.

camsteffen avatar Jun 29 '22 13:06 camsteffen

:umbrella: The latest upstream changes (presumably #98706) made this pull request unmergeable. Please resolve the merge conflicts.

bors avatar Jul 01 '22 04:07 bors