rust icon indicating copy to clipboard operation
rust copied to clipboard

Make typeck aware of uninhabited types

Open camsteffen opened this issue 2 years ago • 47 comments

It was previously assumed in #85556 that we can't check if an expression has an uninhabited type in typeck. So an unreachable_code case was added to the liveness pass instead. This PR moves that case back into typeck. It just requires adding cycle_delay_bug to the uninhabited query.

Incidentally this leads to some new cases for unreachable_code. But it should simply be consistent with how ! is currently handled.

My original motivation is to remove a blocker to doing some refactoring on liveness.

r? rust-lang/compiler

camsteffen avatar Aug 08 '22 20:08 camsteffen

I'm not entirely confident in the test changes tbh. Maybe a few corner cases need some ironing.

camsteffen avatar Aug 08 '22 20:08 camsteffen

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)
Successfully built 0be3437e3ddb
Successfully tagged rust-ci:latest
Built container sha256:0be3437e3ddbe9c806a31304ec47c991fbe691b9df66334f35cd94b8c9414b64
Uploading finished image to https://ci-caches.rust-lang.org/docker/55e0616340de9767316ac8a2060e4b2402700344c201ac04865af7e91102302ab3c0bf7f297a771d5ca396e00e9848a4e4279034a0339b65793190c46eafc724
upload failed: - to s3://rust-lang-ci-sccache2/docker/55e0616340de9767316ac8a2060e4b2402700344c201ac04865af7e91102302ab3c0bf7f297a771d5ca396e00e9848a4e4279034a0339b65793190c46eafc724 Unable to locate credentials
[CI_JOB_NAME=x86_64-gnu-llvm-12]
---
   Compiling rustc_target v0.0.0 (/checkout/compiler/rustc_target)
error: unreachable call
   --> compiler/rustc_target/src/asm/mod.rs:314:39
    |
314 |             InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse(name)?),
    |                                       ^^^^^^^^^^^ ------------------------------- any code following this expression is unreachable
    |                                       unreachable call
    |
    |
    = note: `-D unreachable-code` implied by `-D warnings`
error: unreachable call
   --> compiler/rustc_target/src/asm/mod.rs:323:37
    |
    |
323 |             InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(name)?),
    |                                     ^^^^^^^^^^^ ------------------------------- any code following this expression is unreachable
    |                                     unreachable call

error: unreachable call
   --> compiler/rustc_target/src/asm/mod.rs:325:17
   --> compiler/rustc_target/src/asm/mod.rs:325:17
    |
325 |                 Self::Wasm(WasmInlineAsmReg::parse(name)?)
    |                 ^^^^^^^^^^ ------------------------------ any code following this expression is unreachable
    |                 unreachable call

   Compiling rustc_ast_pretty v0.0.0 (/checkout/compiler/rustc_ast_pretty)
error: could not compile `rustc_target` due to 3 previous errors

rust-log-analyzer avatar Aug 08 '22 23:08 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)
Successfully built 8a3c8a7d04a5
Successfully tagged rust-ci:latest
Built container sha256:8a3c8a7d04a57627a3d436d085956ff5e3c1cc128e4191fc4b1ac2df41eedeec
Uploading finished image to https://ci-caches.rust-lang.org/docker/55e0616340de9767316ac8a2060e4b2402700344c201ac04865af7e91102302ab3c0bf7f297a771d5ca396e00e9848a4e4279034a0339b65793190c46eafc724
upload failed: - to s3://rust-lang-ci-sccache2/docker/55e0616340de9767316ac8a2060e4b2402700344c201ac04865af7e91102302ab3c0bf7f297a771d5ca396e00e9848a4e4279034a0339b65793190c46eafc724 Unable to locate credentials
[CI_JOB_NAME=x86_64-gnu-llvm-12]
---
   Compiling hir-ty v0.0.0 (/checkout/src/tools/rust-analyzer/crates/hir-ty)
error: unreachable expression
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:276:5
    |
274 | #[derive(Copy, Clone, Debug, PartialEq, Eq)]
275 | pub(super) struct Slice {
276 |     _unimplemented: Void,
    |     ^^^^^^^^^^^^^^^^^^^^
    |     |
---
    |
698 |     pub macro Debug($item:item) {
    |     --------------- in this expansion of `#[derive(Debug)]`
    |
    = note: `-D unreachable-code` implied by `-D warnings`
error: unreachable expression
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:281:15
    |
281 |         match self._unimplemented {}
---

error: unreachable call
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:348:29
    |
348 |             Slice(slice) => Some(*slice),
    |                             ^^^^ ------ any code following this expression is unreachable
    |                             unreachable call

error: unreachable call
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:470:67
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:470:67
    |
470 |             (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice),
    |                                                                   ^^^^^^^^^^^^^ ------------ any code following this expression is unreachable
    |                                                                   unreachable call

error: unreachable call
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:505:36
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:505:36
    |
505 |                 .any(|other| slice.is_covered_by(other)),
    |                                    ^^^^^^^^^^^^^ ----- any code following this expression is unreachable
    |                                    unreachable call

error: unreachable expression
    --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:1020:36
    --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:1020:36
     |
1020 |             &Slice(slice) => match slice._unimplemented {},
     |                                    |
     |                                    unreachable expression
     |                                    any code following this expression is unreachable


error: could not compile `hir-ty` due to 7 previous errors
Build completed unsuccessfully in 0:26:01

rust-log-analyzer avatar Aug 09 '22 03:08 rust-log-analyzer

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

bors avatar Aug 09 '22 12:08 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)
diff of stderr:

2   --> $DIR/match-no-arms-unreachable-after.rs:8:5
3    |
4 LL |     match v { }
-    |           - any code following this expression is unreachable
+    |           - this expression has type `Void`, which is uninhabited
6 LL |     let x = 2;
7    |     ^^^^^^^^^^ unreachable statement


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

error: 1 errors occurred comparing output.
status: exit status: 1
Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/match/match-no-arms-unreachable-after.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/match/match-no-arms-unreachable-after" "-A" "unused" "-Crpath" "-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/match/match-no-arms-unreachable-after/auxiliary"
stdout: none
--- stderr -------------------------------
  --> /checkout/src/test/ui/match/match-no-arms-unreachable-after.rs:8:5
   |
LL |     match v { }
LL |     match v { }
   |           - this expression has type `Void`, which is uninhabited
LL |     let x = 2; //~ ERROR unreachable
   |     ^^^^^^^^^^ unreachable statement
note: the lint level is defined here
  --> /checkout/src/test/ui/match/match-no-arms-unreachable-after.rs:2:9
   |
LL | #![deny(unreachable_code)]
---

---- [ui] src/test/ui/repr/repr-transparent.rs stdout ----
diff of stderr:

42 LL | enum Void {}
43    | --------- zero-variant enum
44 
+ error[E0731]: transparent enum needs exactly one variant, but has 0
+    |
+    |
+ LL | enum Void {}
+    | ^^^^^^^^^ needs exactly one variant, but has 0
+ 
45 error[E0690]: the variant of a transparent enum needs at most one non-zero-sized field, but has 2
47    |

52    |         |
53    |         this field is non-zero-sized
53    |         this field is non-zero-sized
54 
+ error[E0690]: the variant of a transparent enum needs at most one non-zero-sized field, but has 2
+    |
+    |
+ LL | enum TooManyFieldsEnum {
+    | ^^^^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
+ LL |     Foo(u32, String),
+    |         |
+    |         this field is non-zero-sized
+ 
+ 
55 error[E0731]: transparent enum needs exactly one variant, but has 2
57    |

62 LL |     Bar,
62 LL |     Bar,
63    |     --- too many variants in `MultipleVariants`
64 
+ error[E0731]: transparent enum needs exactly one variant, but has 2
+    |
+    |
+ LL | enum MultipleVariants {
+    | ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
+ LL |     Foo(String),
+ LL |     Bar,
+ LL |     Bar,
+    |     --- too many variants in `MultipleVariants`
+ 
65 error[E0691]: zero-sized field in transparent enum has alignment larger than 1
67    |

69    |              ^^^^^^^^ has alignment larger than 1
70 
70 
71 error[E0691]: zero-sized field in transparent enum has alignment larger than 1
+    |
+    |
+ LL |     Foo(u32, [u16; 0]),
+    |              ^^^^^^^^ has alignment larger than 1
+ 
+ error[E0691]: zero-sized field in transparent enum has alignment larger than 1
73    |
73    |
74 LL |     Foo { bar: ZstAlign32<T>, baz: u32 }
75    |           ^^^^^^^^^^^^^^^^^^ has alignment larger than 1
76 
76 
+ error[E0691]: zero-sized field in transparent enum has alignment larger than 1
+    |
+    |
+ LL |     Foo { bar: ZstAlign32<T>, baz: u32 }
+    |           ^^^^^^^^^^^^^^^^^^ has alignment larger than 1
77 error[E0690]: transparent union needs at most one non-zero-sized field, but has 2
78   --> $DIR/repr-transparent.rs:85:1
79    |

---
To only update this specific test, also pass `--test-args repr/repr-transparent.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/repr/repr-transparent.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/repr/repr-transparent" "-A" "unused" "-Crpath" "-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/repr/repr-transparent/auxiliary"
stdout: none
--- stderr -------------------------------
error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2
   |
   |
LL | struct MultipleNonZst(u8, u8); //~ ERROR needs at most one non-zero-sized field
   | |                     |
   | |                     this field is non-zero-sized
   | |                     this field is non-zero-sized
   | needs at most one non-zero-sized field, but has 2
error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2
  --> /checkout/src/test/ui/repr/repr-transparent.rs:32:1
   |
   |
LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
   | |                               |
   | |                               this field is non-zero-sized
   | |                               this field is non-zero-sized
   | needs at most one non-zero-sized field, but has 2

error[E0691]: zero-sized field in transparent struct has alignment larger than 1
   |
   |
LL | struct NontrivialAlignZst(u32, [u16; 0]); //~ ERROR alignment larger than 1
   |                                ^^^^^^^^ has alignment larger than 1

error[E0691]: zero-sized field in transparent struct has alignment larger than 1
   |
   |
LL | struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1
   |                        ^^^^^^^^^^^^^ has alignment larger than 1

error[E0731]: transparent enum needs exactly one variant, but has 0
   |
   |
LL | enum Void {} //~ ERROR transparent enum needs exactly one variant, but has 0
   | ^^^^^^^^^ needs exactly one variant, but has 0
error[E0084]: unsupported representation for zero-variant enum
  --> /checkout/src/test/ui/repr/repr-transparent.rs:44:1
   |
   |
LL | #[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum
   | ^^^^^^^^^^^^^^^^^^^^
LL | enum Void {} //~ ERROR transparent enum needs exactly one variant, but has 0
   | --------- zero-variant enum

error[E0731]: transparent enum needs exactly one variant, but has 0
   |
   |
LL | enum Void {} //~ ERROR transparent enum needs exactly one variant, but has 0
   | ^^^^^^^^^ needs exactly one variant, but has 0

error[E0690]: the variant of a transparent enum needs at most one non-zero-sized field, but has 2
   |
   |
LL | enum TooManyFieldsEnum {
   | ^^^^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
LL |     Foo(u32, String),
   |         |
   |         this field is non-zero-sized


error[E0690]: the variant of a transparent enum needs at most one non-zero-sized field, but has 2
   |
   |
LL | enum TooManyFieldsEnum {
   | ^^^^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
LL |     Foo(u32, String),
   |         |
   |         this field is non-zero-sized


error[E0731]: transparent enum needs exactly one variant, but has 2
   |
   |
LL | enum MultipleVariants { //~ ERROR transparent enum needs exactly one variant, but has 2
   | ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
LL |     Foo(String),
LL |     Bar,
LL |     Bar,
   |     --- too many variants in `MultipleVariants`

error[E0731]: transparent enum needs exactly one variant, but has 2
   |
   |
LL | enum MultipleVariants { //~ ERROR transparent enum needs exactly one variant, but has 2
   | ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
LL |     Foo(String),
LL |     Bar,
LL |     Bar,
   |     --- too many variants in `MultipleVariants`

error[E0691]: zero-sized field in transparent enum has alignment larger than 1
   |
   |
LL |     Foo(u32, [u16; 0]), //~ ERROR alignment larger than 1
   |              ^^^^^^^^ has alignment larger than 1

error[E0691]: zero-sized field in transparent enum has alignment larger than 1
   |
   |
LL |     Foo(u32, [u16; 0]), //~ ERROR alignment larger than 1
   |              ^^^^^^^^ has alignment larger than 1

error[E0691]: zero-sized field in transparent enum has alignment larger than 1
   |
   |
LL |     Foo { bar: ZstAlign32<T>, baz: u32 } //~ ERROR alignment larger than 1
   |           ^^^^^^^^^^^^^^^^^^ has alignment larger than 1

error[E0691]: zero-sized field in transparent enum has alignment larger than 1
   |
   |
LL |     Foo { bar: ZstAlign32<T>, baz: u32 } //~ ERROR alignment larger than 1
   |           ^^^^^^^^^^^^^^^^^^ has alignment larger than 1
error[E0690]: transparent union needs at most one non-zero-sized field, but has 2
  --> /checkout/src/test/ui/repr/repr-transparent.rs:85:1
   |
   |
LL | union TooManyFields { //~ ERROR transparent union needs at most one non-zero-sized field, but has 2
   | ^^^^^^^^^^^^^^^^^^^ needs at most one non-zero-sized field, but has 2
LL |     u: u32,
LL |     s: i32
   |     ------ this field is non-zero-sized

error: aborting due to 16 previous errors

rust-log-analyzer avatar Aug 09 '22 18:08 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)
    |
281 |         match self._unimplemented {}
    |               ----^^^^^^^^^^^^^^^
    |               |
    |               unreachable expression
    |               this expression has type `deconstruct_pat::Slice`, which is uninhabited
    |
    = note: `-D unreachable-code` implied by `-D warnings`
error: unreachable expression
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:286:15
    |
286 |         match self._unimplemented {}
286 |         match self._unimplemented {}
    |               ----^^^^^^^^^^^^^^^
    |               |
    |               unreachable expression
    |               this expression has type `deconstruct_pat::Slice`, which is uninhabited
error: unreachable call
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:348:29
    |
    |
348 |             Slice(slice) => Some(*slice),
    |                             ^^^^ ------ this expression has type `deconstruct_pat::Slice`, which is uninhabited
    |                             unreachable call

error: unreachable call
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:470:67
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:470:67
    |
470 |             (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice),
    |                                                                   ^^^^^^^^^^^^^ ------------ this expression has type `deconstruct_pat::Slice`, which is uninhabited
    |                                                                   unreachable call

error: unreachable call
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:505:36
   --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:505:36
    |
505 |                 .any(|other| slice.is_covered_by(other)),
    |                                    ^^^^^^^^^^^^^ ----- this expression has type `deconstruct_pat::Slice`, which is uninhabited
    |                                    unreachable call

error: unreachable expression
    --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:1020:36
    --> crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs:1020:36
     |
1020 |             &Slice(slice) => match slice._unimplemented {},
     |                                    |
     |                                    unreachable expression
     |                                    unreachable expression
     |                                    this expression has type `deconstruct_pat::Slice`, which is uninhabited

error: could not compile `hir-ty` due to 6 previous errors
Build completed unsuccessfully in 0:28:03

rust-log-analyzer avatar Aug 09 '22 19:08 rust-log-analyzer

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)
    Checking rustc_plugin_impl v0.0.0 (/checkout/compiler/rustc_plugin_impl)
    Checking rustc_codegen_ssa v0.0.0 (/checkout/compiler/rustc_codegen_ssa)
    Checking rustc_borrowck v0.0.0 (/checkout/compiler/rustc_borrowck)
    Checking rustc_mir_transform v0.0.0 (/checkout/compiler/rustc_mir_transform)
error[E0069]: `return;` in a function whose return type is not `()`
    |
779 |                         return;
    |                         ^^^^^^ return type is not `()`

rust-log-analyzer avatar Aug 09 '22 23:08 rust-log-analyzer

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

bors avatar Aug 18 '22 13:08 bors

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

Click to see the possible cause of the failure (guessed by this bot)
....iii................................................................................. 13376/13399
.......................
failures:

---- [ui] src/test/ui/deriving/deriving-all-codegen.rs#unpretty stdout ----


1146     fn eq(&self, other: &WithUninhabited) -> bool {
1147         self.x == other.x && self.v == other.v && self.y == other.y
-     #[inline]
-     #[inline]
-     fn ne(&self, other: &WithUninhabited) -> bool {
-         self.x != other.x || self.v != other.v || self.y != other.y
1153 }
1153 }
1154 impl ::core::marker::StructuralEq for WithUninhabited {}
1155 #[automatically_derived]

1254                     EnumWithUninhabited::B(__arg1_0)) => *__self_0 == *__arg1_0,
1255                 (EnumWithUninhabited::C(__self_0),
1256                     EnumWithUninhabited::C(__arg1_0)) => *__self_0 == *__arg1_0,
-                 _ => unsafe { ::core::intrinsics::unreachable() }
-     }
-     #[inline]
-     #[inline]
-     fn ne(&self, other: &EnumWithUninhabited) -> bool {
-         let __self_tag = ::core::intrinsics::discriminant_value(self);
-         let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-         __self_tag != __arg1_tag ||
-             match (self, other) {
-                 (EnumWithUninhabited::A(__self_0),
-                     EnumWithUninhabited::A(__arg1_0)) => *__self_0 != *__arg1_0,
-                 (EnumWithUninhabited::B(__self_0),
-                     EnumWithUninhabited::B(__arg1_0)) => *__self_0 != *__arg1_0,
-                 (EnumWithUninhabited::C(__self_0),
-                     EnumWithUninhabited::C(__arg1_0)) => *__self_0 != *__arg1_0,
1272                 _ => unsafe { ::core::intrinsics::unreachable() }
1274     }


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
The actual stdout differed from the expected stdout.
Actual stdout saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/deriving/deriving-all-codegen.unpretty/deriving-all-codegen.unpretty.stdout
To only update this specific test, also pass `--test-args deriving/deriving-all-codegen.rs`


error in revision `unpretty`: 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/deriving/deriving-all-codegen.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--cfg" "unpretty" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/deriving/deriving-all-codegen.unpretty" "-A" "unused" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2021" "-Zunpretty=expanded" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/deriving/deriving-all-codegen.unpretty/auxiliary"
#![feature(prelude_import)]
// check-pass
// edition:2021
// revisions: check unpretty
// revisions: check unpretty
// [unpretty] compile-flags: -Zunpretty=expanded
//
// This test checks the code generated for all[*] the builtin derivable traits
// on a variety of structs and enums. It protects against accidental changes to
// the generated code, and makes deliberate changes to the generated code
// easier to review.
//
// [*] It excludes `Copy` in some cases, because that changes the code
// generated for `Clone`.
//
// [*] It excludes `RustcEncodable` and `RustDecodable`, which are obsolete and
// also require the `rustc_serialize` crate.
#![crate_type = "lib"]
#![warn(unused)]
#[prelude_import]
use std::prelude::rust_2021::*;
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
// test that lints are not triggerred in derived code
// Empty struct.
pub struct Empty;
#[automatically_derived]
impl ::core::clone::Clone for Empty {
impl ::core::clone::Clone for Empty {
    #[inline]
    fn clone(&self) -> Empty { *self }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for Empty { }
#[automatically_derived]
impl ::core::fmt::Debug for Empty {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Empty")
}
#[automatically_derived]
impl ::core::default::Default for Empty {
    #[inline]
    #[inline]
    fn default() -> Empty { Empty {} }
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Empty {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
}
impl ::core::marker::StructuralPartialEq for Empty {}
#[automatically_derived]
impl ::core::cmp::PartialEq for Empty {
    #[inline]
    fn eq(&self, other: &Empty) -> bool { true }
}
impl ::core::marker::StructuralEq for Empty {}
#[automatically_derived]
impl ::core::cmp::Eq for Empty {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Empty {
    #[inline]
    fn partial_cmp(&self, other: &Empty)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ordering::Equal)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for Empty {
    #[inline]
    fn cmp(&self, other: &Empty) -> ::core::cmp::Ordering {
        ::core::cmp::Ordering::Equal
}

// A basic struct.
pub struct Point {
pub struct Point {
    x: u32,
    y: u32,
}
#[automatically_derived]
impl ::core::clone::Clone for Point {
    #[inline]
    fn clone(&self) -> Point {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
}
#[automatically_derived]
impl ::core::marker::Copy for Point { }
#[automatically_derived]
#[automatically_derived]
impl ::core::fmt::Debug for Point {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "Point", "x",
            &&self.x, "y", &&self.y)
}
#[automatically_derived]
impl ::core::default::Default for Point {
    #[inline]
    #[inline]
    fn default() -> Point {
        Point {
            x: ::core::default::Default::default(),
            y: ::core::default::Default::default(),
    }
}
#[automatically_derived]
impl ::core::hash::Hash for Point {
impl ::core::hash::Hash for Point {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.x, state);
        ::core::hash::Hash::hash(&self.y, state)
}
}
impl ::core::marker::StructuralPartialEq for Point {}
#[automatically_derived]
impl ::core::cmp::PartialEq for Point {
    #[inline]
    fn eq(&self, other: &Point) -> bool {
        self.x == other.x && self.y == other.y
}
}
impl ::core::marker::StructuralEq for Point {}
#[automatically_derived]
impl ::core::cmp::Eq for Point {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Point {
    #[inline]
    #[inline]
    fn partial_cmp(&self, other: &Point)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                ::core::cmp::PartialOrd::partial_cmp(&self.y, &other.y),
            cmp => cmp,
    }
}
#[automatically_derived]
impl ::core::cmp::Ord for Point {
impl ::core::cmp::Ord for Point {
    #[inline]
    fn cmp(&self, other: &Point) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.x, &other.x) {
            ::core::cmp::Ordering::Equal =>
                ::core::cmp::Ord::cmp(&self.y, &other.y),
            cmp => cmp,
    }
}

// A large struct.
---
    b6: u32,
    b7: u32,
    b8: u32,
}
#[automatically_derived]
impl ::core::clone::Clone for Big {
    fn clone(&self) -> Big {
        Big {
        Big {
            b1: ::core::clone::Clone::clone(&self.b1),
            b2: ::core::clone::Clone::clone(&self.b2),
            b3: ::core::clone::Clone::clone(&self.b3),
            b4: ::core::clone::Clone::clone(&self.b4),
            b5: ::core::clone::Clone::clone(&self.b5),
            b6: ::core::clone::Clone::clone(&self.b6),
            b7: ::core::clone::Clone::clone(&self.b7),
            b8: ::core::clone::Clone::clone(&self.b8),
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::fmt::Debug for Big {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let names: &'static _ =
            &["b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8"];
        let values: &[&dyn ::core::fmt::Debug] =
            &[&&self.b1, &&self.b2, &&self.b3, &&self.b4, &&self.b5,
                        &&self.b6, &&self.b7, &&self.b8];
        ::core::fmt::Formatter::debug_struct_fields_finish(f, "Big", names,
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::default::Default for Big {
    #[inline]
    fn default() -> Big {
        Big {
            b1: ::core::default::Default::default(),
            b2: ::core::default::Default::default(),
            b3: ::core::default::Default::default(),
            b4: ::core::default::Default::default(),
            b5: ::core::default::Default::default(),
            b6: ::core::default::Default::default(),
            b7: ::core::default::Default::default(),
            b8: ::core::default::Default::default(),
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Big {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.b1, state);
        ::core::hash::Hash::hash(&self.b2, state);
        ::core::hash::Hash::hash(&self.b3, state);
        ::core::hash::Hash::hash(&self.b4, state);
        ::core::hash::Hash::hash(&self.b5, state);
        ::core::hash::Hash::hash(&self.b6, state);
        ::core::hash::Hash::hash(&self.b7, state);
        ::core::hash::Hash::hash(&self.b8, state)
}
}
impl ::core::marker::StructuralPartialEq for Big {}
#[automatically_derived]
impl ::core::cmp::PartialEq for Big {
    #[inline]
    fn eq(&self, other: &Big) -> bool {
        self.b1 == other.b1 && self.b2 == other.b2 && self.b3 == other.b3 &&
                            self.b4 == other.b4 && self.b5 == other.b5 &&
                    self.b6 == other.b6 && self.b7 == other.b7 &&
            self.b8 == other.b8
}
}
impl ::core::marker::StructuralEq for Big {}
#[automatically_derived]
impl ::core::cmp::Eq for Big {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Big {
    #[inline]
    fn partial_cmp(&self, other: &Big)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.b1, &other.b1) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                match ::core::cmp::PartialOrd::partial_cmp(&self.b2,
                        &other.b2) {
                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                        =>
                        match ::core::cmp::PartialOrd::partial_cmp(&self.b3,
                                &other.b3) {
                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                =>
                                match ::core::cmp::PartialOrd::partial_cmp(&self.b4,
                                        &other.b4) {
                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                        =>
                                        match ::core::cmp::PartialOrd::partial_cmp(&self.b5,
                                                &other.b5) {
                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                =>
                                                match ::core::cmp::PartialOrd::partial_cmp(&self.b6,
                                                        &other.b6) {
                                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                        =>
                                                        match ::core::cmp::PartialOrd::partial_cmp(&self.b7,
                                                                &other.b7) {
                                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                                =>
                                                                ::core::cmp::PartialOrd::partial_cmp(&self.b8, &other.b8),
                                                            cmp => cmp,
                                                    cmp => cmp,
                                                },
                                            cmp => cmp,
                                        },
---
            cmp => cmp,
        }
    }
}
#[automatically_derived]
impl ::core::cmp::Ord for Big {
    #[inline]
    fn cmp(&self, other: &Big) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.b1, &other.b1) {
            ::core::cmp::Ordering::Equal =>
                match ::core::cmp::Ord::cmp(&self.b2, &other.b2) {
                    ::core::cmp::Ordering::Equal =>
                        match ::core::cmp::Ord::cmp(&self.b3, &other.b3) {
                            ::core::cmp::Ordering::Equal =>
                                match ::core::cmp::Ord::cmp(&self.b4, &other.b4) {
                                    ::core::cmp::Ordering::Equal =>
                                        match ::core::cmp::Ord::cmp(&self.b5, &other.b5) {
                                            ::core::cmp::Ordering::Equal =>
                                                match ::core::cmp::Ord::cmp(&self.b6, &other.b6) {
                                                    ::core::cmp::Ordering::Equal =>
                                                        match ::core::cmp::Ord::cmp(&self.b7, &other.b7) {
                                                            ::core::cmp::Ordering::Equal =>
                                                                ::core::cmp::Ord::cmp(&self.b8, &other.b8),
                                                            cmp => cmp,
                                                    cmp => cmp,
                                                },
                                            cmp => cmp,
                                        },
---
        }
    }
}

// A struct with an unsized field. Some derives are not usable in this case.
pub struct Unsized([u32]);
#[automatically_derived]
impl ::core::fmt::Debug for Unsized {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Unsized",
            &&self.0)
}
#[automatically_derived]
impl ::core::hash::Hash for Unsized {
impl ::core::hash::Hash for Unsized {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.0, state)
}
}
impl ::core::marker::StructuralPartialEq for Unsized {}
#[automatically_derived]
impl ::core::cmp::PartialEq for Unsized {
    #[inline]
    fn eq(&self, other: &Unsized) -> bool { self.0 == other.0 }
}
impl ::core::marker::StructuralEq for Unsized {}
#[automatically_derived]
impl ::core::cmp::Eq for Unsized {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<[u32]>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Unsized {
    #[inline]
    fn partial_cmp(&self, other: &Unsized)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for Unsized {
    #[inline]
    fn cmp(&self, other: &Unsized) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
}

// A packed tuple struct that impls `Copy`.
// A packed tuple struct that impls `Copy`.
#[repr(packed)]
pub struct PackedCopy(u32);
#[automatically_derived]
impl ::core::clone::Clone for PackedCopy {
    fn clone(&self) -> PackedCopy {
    fn clone(&self) -> PackedCopy {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for PackedCopy { }
#[automatically_derived]
impl ::core::fmt::Debug for PackedCopy {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy",
            &&{ self.0 })
}
#[automatically_derived]
#[automatically_derived]
impl ::core::default::Default for PackedCopy {
    #[inline]
    fn default() -> PackedCopy {
        PackedCopy(::core::default::Default::default())
}
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for PackedCopy {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&{ self.0 }, state)
}
}
impl ::core::marker::StructuralPartialEq for PackedCopy {}
#[automatically_derived]
impl ::core::cmp::PartialEq for PackedCopy {
    #[inline]
    fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } }
}
impl ::core::marker::StructuralEq for PackedCopy {}
#[automatically_derived]
impl ::core::cmp::Eq for PackedCopy {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for PackedCopy {
    #[inline]
    fn partial_cmp(&self, other: &PackedCopy)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for PackedCopy {
    #[inline]
    fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 })
}


// A packed tuple struct that does not impl `Copy`. Note that the alignment of
// the field must be 1 for this code to be valid. Otherwise it triggers an
// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not
// derive Copy (error E0133)" at MIR building time. This is a weird case and
// it's possible that this struct is not supposed to work, but for now it does.
#[repr(packed)]
pub struct PackedNonCopy(u8);
#[automatically_derived]
impl ::core::clone::Clone for PackedNonCopy {
    #[inline]
    fn clone(&self) -> PackedNonCopy {
        let Self(ref __self_0_0) = *self;
        PackedNonCopy(::core::clone::Clone::clone(__self_0_0))
}
#[automatically_derived]
#[automatically_derived]
impl ::core::fmt::Debug for PackedNonCopy {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let Self(ref __self_0_0) = *self;
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedNonCopy",
            &__self_0_0)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::default::Default for PackedNonCopy {
    #[inline]
    fn default() -> PackedNonCopy {
        PackedNonCopy(::core::default::Default::default())
}
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for PackedNonCopy {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        let Self(ref __self_0_0) = *self;
        ::core::hash::Hash::hash(__self_0_0, state)
}
}
impl ::core::marker::StructuralPartialEq for PackedNonCopy {}
#[automatically_derived]
impl ::core::cmp::PartialEq for PackedNonCopy {
    #[inline]
    fn eq(&self, other: &PackedNonCopy) -> bool {
        let Self(ref __self_0_0) = *self;
        let Self(ref __self_1_0) = *other;
        *__self_0_0 == *__self_1_0
}
}
impl ::core::marker::StructuralEq for PackedNonCopy {}
#[automatically_derived]
impl ::core::cmp::Eq for PackedNonCopy {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u8>;
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for PackedNonCopy {
    #[inline]
    fn partial_cmp(&self, other: &PackedNonCopy)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let Self(ref __self_0_0) = *self;
        let Self(ref __self_1_0) = *other;
        ::core::cmp::PartialOrd::partial_cmp(__self_0_0, __self_1_0)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for PackedNonCopy {
    #[inline]
    fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering {
        let Self(ref __self_0_0) = *self;
        let Self(ref __self_1_0) = *other;
        ::core::cmp::Ord::cmp(__self_0_0, __self_1_0)
}

// An empty enum.
pub enum Enum0 {}
pub enum Enum0 {}
#[automatically_derived]
impl ::core::clone::Clone for Enum0 {
    #[inline]
    fn clone(&self) -> Enum0 { *self }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for Enum0 { }
#[automatically_derived]
impl ::core::fmt::Debug for Enum0 {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        unsafe { ::core::intrinsics::unreachable() }
}
#[automatically_derived]
impl ::core::hash::Hash for Enum0 {
impl ::core::hash::Hash for Enum0 {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        unsafe { ::core::intrinsics::unreachable() }
}
}
impl ::core::marker::StructuralPartialEq for Enum0 {}
#[automatically_derived]
impl ::core::cmp::PartialEq for Enum0 {
    #[inline]
    fn eq(&self, other: &Enum0) -> bool {
        unsafe { ::core::intrinsics::unreachable() }
}
}
impl ::core::marker::StructuralEq for Enum0 {}
#[automatically_derived]
impl ::core::cmp::Eq for Enum0 {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Enum0 {
    #[inline]
    #[inline]
    fn partial_cmp(&self, other: &Enum0)
        -> ::core::option::Option<::core::cmp::Ordering> {
        unsafe { ::core::intrinsics::unreachable() }
}
#[automatically_derived]
impl ::core::cmp::Ord for Enum0 {
    #[inline]
    #[inline]
    fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering {
        unsafe { ::core::intrinsics::unreachable() }
}

// A single-variant enum.
pub enum Enum1 {
pub enum Enum1 {
    Single {
        x: u32,
    },
}
#[automatically_derived]
impl ::core::clone::Clone for Enum1 {
    #[inline]
    fn clone(&self) -> Enum1 {
        match self {
            Enum1::Single { x: __self_0 } =>
                Enum1::Single { x: ::core::clone::Clone::clone(__self_0) },
    }
}
#[automatically_derived]
impl ::core::fmt::Debug for Enum1 {
impl ::core::fmt::Debug for Enum1 {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Enum1::Single { x: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "Single", "x", &__self_0),
    }
}
#[automatically_derived]
impl ::core::hash::Hash for Enum1 {
impl ::core::hash::Hash for Enum1 {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        match self {
            Enum1::Single { x: __self_0 } =>
                ::core::hash::Hash::hash(__self_0, state),
    }
}
}
impl ::core::marker::StructuralPartialEq for Enum1 {}
#[automatically_derived]
impl ::core::cmp::PartialEq for Enum1 {
    #[inline]
    fn eq(&self, other: &Enum1) -> bool {
        match (self, other) {
            (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
                *__self_0 == *__arg1_0,
    }
}
}
impl ::core::marker::StructuralEq for Enum1 {}
#[automatically_derived]
impl ::core::cmp::Eq for Enum1 {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Enum1 {
    #[inline]
    #[inline]
    fn partial_cmp(&self, other: &Enum1)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match (self, other) {
            (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
    }
}
#[automatically_derived]
impl ::core::cmp::Ord for Enum1 {
impl ::core::cmp::Ord for Enum1 {
    #[inline]
    fn cmp(&self, other: &Enum1) -> ::core::cmp::Ordering {
        match (self, other) {
            (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
                ::core::cmp::Ord::cmp(__self_0, __arg1_0),
    }
}


// A C-like, fieldless enum with a single variant.
pub enum Fieldless1 {
    #[default]
    A,
}
#[automatically_derived]
#[automatically_derived]
impl ::core::clone::Clone for Fieldless1 {
    #[inline]
    fn clone(&self) -> Fieldless1 { Fieldless1::A }
#[automatically_derived]
#[automatically_derived]
impl ::core::fmt::Debug for Fieldless1 {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "A")
}
#[automatically_derived]
impl ::core::default::Default for Fieldless1 {
    #[inline]
    #[inline]
    fn default() -> Fieldless1 { Self::A }
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Fieldless1 {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
}
impl ::core::marker::StructuralPartialEq for Fieldless1 {}
#[automatically_derived]
impl ::core::cmp::PartialEq for Fieldless1 {
    #[inline]
    fn eq(&self, other: &Fieldless1) -> bool { true }
}
impl ::core::marker::StructuralEq for Fieldless1 {}
#[automatically_derived]
impl ::core::cmp::Eq for Fieldless1 {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Fieldless1 {
    #[inline]
    fn partial_cmp(&self, other: &Fieldless1)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ordering::Equal)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for Fieldless1 {
    #[inline]
    fn cmp(&self, other: &Fieldless1) -> ::core::cmp::Ordering {
        ::core::cmp::Ordering::Equal
}


// A C-like, fieldless enum.
pub enum Fieldless {
    #[default]
    A,
    B,
    C,
    C,
}
#[automatically_derived]
impl ::core::clone::Clone for Fieldless {
    #[inline]
    fn clone(&self) -> Fieldless { *self }
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for Fieldless { }
#[automatically_derived]
impl ::core::fmt::Debug for Fieldless {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Fieldless::A => ::core::fmt::Formatter::write_str(f, "A"),
            Fieldless::B => ::core::fmt::Formatter::write_str(f, "B"),
            Fieldless::C => ::core::fmt::Formatter::write_str(f, "C"),
    }
}
#[automatically_derived]
impl ::core::default::Default for Fieldless {
impl ::core::default::Default for Fieldless {
    #[inline]
    fn default() -> Fieldless { Self::A }
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Fieldless {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_tag, state)
}
}
impl ::core::marker::StructuralPartialEq for Fieldless {}
#[automatically_derived]
impl ::core::cmp::PartialEq for Fieldless {
    #[inline]
    fn eq(&self, other: &Fieldless) -> bool {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        __self_tag == __arg1_tag
}
}
impl ::core::marker::StructuralEq for Fieldless {}
#[automatically_derived]
impl ::core::cmp::Eq for Fieldless {
    #[doc(hidden)]
    #[doc(hidden)]
    #[no_coverage]
    fn assert_receiver_is_total_eq(&self) -> () {}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::PartialOrd for Fieldless {
    #[inline]
    fn partial_cmp(&self, other: &Fieldless)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::PartialOrd::partial_cmp(&__self_tag, &__arg1_tag)
}
#[automatically_derived]
#[automatically_derived]
impl ::core::cmp::Ord for Fieldless {
    #[inline]
    fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering {
        let __self_tag = ::core::intrinsics::discriminant_value(self);
        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag)
}


// An enum with multiple fieldless and fielded variants.
pub enum Mixed {
    #[default]
    P,
    Q,
    R(u32),
    R(u32),
    S {
        d1: u32,
        d2: u32,
    },
}
#[automatically_derived]
impl ::core::clone::Clone for Mixed {
    #[inline]
    fn clone(&self) -> Mixed {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
}
#[automatically_derived]
#[automatically_derived]
impl ::core::marker::Copy for Mixed { }
#[automatically_derived]
impl ::core::fmt::Debug for Mixed {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Mixed::P => ::core::fmt::Formatter::write_str(f, "P"),
            Mixed::Q => ::core::fmt::Formatter::write_str(f, "Q"),
            Mixed::R(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "R",
                    &__self_0),
            Mixed::S { d1: __self_0, d2: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f, "S",
                    "d1", &__self_0, "d2", &__self_1),
    }
}
#[automatically_derived]
#[automatically_derived]
impl ::core::default::Default for Mixed {
    #[inline]
    fn default() -> Mixed { Self::P }
#[automatically_derived]
#[automatically_derived]
impl ::core::hash::Hash for Mixed {
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {

rust-log-analyzer avatar Aug 18 '22 19:08 rust-log-analyzer

How does this PR articulate with https://github.com/rust-lang/rust/pull/100720?

cjgillot avatar Aug 20 '22 10:08 cjgillot

There are a number of queries that are susceptible to cycle errors if they run on an infinitely recursive (unrepresentable) ADT. adt_sized_constraint and type_uninhabited_from are a couple such queries. There are multiple ways to solve the cycle error problem for a given query:

  1. Ensure the query never runs on unrepresentable types. (this PR stops rustc before bodies are type-checked, so that type_implemented_from remains guarded from unrepresentable types)
  2. Implement Value::from_cycle_error to have a fallback (adt_sized_constraint currently does this)
  3. Add if !is_representable(field_id) { return <fallback> }. (this is an idea I had that prompted me to do #100720)

So we can either be conservative and try to guard queries from unrepresentable types as much as possible (halt rustc early), or go the other direction and try to recover-and-continue as much as possible for unrepresentable types. Or maybe the right balance is somewhere in the middle. I'm not quite sure.

In any case, it might make sense to try and merge #100720 first on its own, and then we can think about how other parts of the compiler may or may not use the new is_representable query. Though I think it might also be fine to merge this PR first. They are only tangentially related.

camsteffen avatar Aug 20 '22 15:08 camsteffen

Removed the early exit and instead added from_cycle_error for type_uninhabited_from. This feels much less invasive and also makes this PR pretty much completely orthoganal to https://github.com/rust-lang/rust/pull/100720.

camsteffen avatar Aug 20 '22 17:08 camsteffen

@bors try

let's do a crater run

oli-obk avatar Aug 22 '22 11:08 oli-obk

:hourglass: Trying commit ad74cc0599fa589ab7eae29d62f3735f8d8b6d95 with merge a7c82ab039ba430bf2de64b244f5f41eee8351b6...

bors avatar Aug 22 '22 11:08 bors

:sunny: Try build successful - checks-actions Build commit: a7c82ab039ba430bf2de64b244f5f41eee8351b6 (a7c82ab039ba430bf2de64b244f5f41eee8351b6)

bors avatar Aug 22 '22 13:08 bors

@craterbot check

oli-obk avatar Aug 22 '22 14:08 oli-obk

:ok_hand: Experiment pr-100288 created and queued. :robot: Automatically detected try build a7c82ab039ba430bf2de64b244f5f41eee8351b6 :mag: You can check out the queue and this experiment's details.

:information_source: Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

craterbot avatar Aug 22 '22 14:08 craterbot

:construction: Experiment pr-100288 is now running

:information_source: Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

craterbot avatar Aug 22 '22 14:08 craterbot

:tada: Experiment pr-100288 is completed! :bar_chart: 71 regressed and 6 fixed (241753 total) :newspaper: Open the full report.

:warning: If you notice any spurious failure please add them to the blacklist! :information_source: Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

craterbot avatar Aug 23 '22 16:08 craterbot

10 regressions where the unreachable expression lint now triggers more aggressively (we can ignore those)

48 regressions with "Failed to get rustc version" in a libc build script. No clue how that happened.

Some syn failures:

[INFO] [stdout] error[E0277]: the trait bound `proc_macro2::TokenStream: From<proc_macro::TokenStream>` is not satisfied
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/github.com-1ecc6299db9ec823/syn-1.0.92/src/buffer.rs:122:20
[INFO] [stdout]     |
[INFO] [stdout] 122 |         Self::new2(stream.into())
[INFO] [stdout]     |                    ^^^^^^ ---- required by a bound introduced by this call
[INFO] [stdout]     |                    |
[INFO] [stdout]     |                    the trait `From<proc_macro::TokenStream>` is not implemented for `proc_macro2::TokenStream`
[INFO] [stdout]     |
[INFO] [stdout]     = help: the trait `From<proc_macro2::TokenTree>` is implemented for `proc_macro2::TokenStream`
[INFO] [stdout]     = note: required for `proc_macro::TokenStream` to implement `Into<proc_macro2::TokenStream>`
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error[E0277]: the trait bound `proc_macro2::TokenStream: From<proc_macro::TokenStream>` is not satisfied
[INFO] [stdout]     --> /opt/rustwide/cargo-home/registry/src/github.com-1ecc6299db9ec823/syn-1.0.92/src/parse.rs:1163:52
[INFO] [stdout]      |
[INFO] [stdout] 1163 |         self.parse2(proc_macro2::TokenStream::from(tokens))
[INFO] [stdout]      |                     ------------------------------ ^^^^^^ the trait `From<proc_macro::TokenStream>` is not implemented for `proc_macro2::TokenStream`
[INFO] [stdout]      |                     |
[INFO] [stdout]      |                     required by a bound introduced by this call
[INFO] [stdout]      |
[INFO] [stdout]      = help: the trait `From<proc_macro2::TokenTree>` is implemented for `proc_macro2::TokenStream`
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: aborting due to 2 previous errors

oli-obk avatar Aug 24 '22 12:08 oli-obk

48 regressions with "Failed to get rustc version" in a libc build script. No clue how that happened.

That's https://github.com/rust-lang/crater/issues/663

RalfJung avatar Aug 24 '22 12:08 RalfJung

Addressed comments in fixup commits. Is the crater run good enough? I looked through the new unreachable_code warnings and they look correct.

camsteffen avatar Aug 25 '22 02:08 camsteffen

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

Click to see the possible cause of the failure (guessed by this bot)

---- [mir-opt] src/test/mir-opt/const_prop/invalid_constant.rs stdout ----
33       }
34   
35       bb0: {
-           StorageLive(_2);                 // scope 0 at $DIR/invalid_constant.rs:+6:9: +6:22
-           StorageLive(_3);                 // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
-           Deinit(_3);                      // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
-           (_3.0: u32) = const 1114113_u32; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:63
- -         _2 = (_3.1: char);               // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:67
- +         _2 = const {transmute(0x00110001): char}; // scope 2 at $DIR/invalid_constant.rs:+6:34: +6:67
-           StorageDead(_3);                 // scope 0 at $DIR/invalid_constant.rs:+6:69: +6:70
-           StorageLive(_4);                 // scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
-           StorageLive(_5);                 // scope 1 at $DIR/invalid_constant.rs:+13:25: +13:59
-           StorageLive(_6);                 // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
-           Deinit(_6);                      // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
-           (_6.0: u32) = const 4_u32;       // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
- -         _5 = (_6.1: E);                  // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
- -         _4 = [move _5];                  // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
- +         _5 = const Scalar(0x00000004): E; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
- +                                          // mir::Constant
- +                                          // + span: $DIR/invalid_constant.rs:28:34: 28:57
- +                                          // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
- +         _4 = [const Scalar(0x00000004): E]; // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
- +                                          // mir::Constant
- +                                          // + span: $DIR/invalid_constant.rs:28:24: 28:60
- +                                          // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
-           StorageDead(_5);                 // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
-           StorageDead(_6);                 // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
-           StorageLive(_7);                 // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
-           StorageLive(_8);                 // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
-           StorageLive(_9);                 // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
-           Deinit(_9);                      // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
-           (_9.0: u32) = const 0_u32;       // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
-           nop;                             // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
-           nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
-           StorageDead(_8);                 // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
-           StorageDead(_9);                 // scope 3 at $DIR/invalid_constant.rs:+20:74: +20:75
-           StorageLive(_10);                // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
-           StorageDead(_10);                // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
-           StorageDead(_7);                 // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
-           StorageDead(_4);                 // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
-           StorageDead(_2);                 // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
74           unreachable;                     // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
76   }


thread '[mir-opt] src/test/mir-opt/const_prop/invalid_constant.rs' panicked at 'Actual MIR output differs from expected MIR output /checkout/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff', src/tools/compiletest/src/runtest.rs:3512:25

---- [mir-opt] src/test/mir-opt/uninhabited-enum.rs stdout ----
11     }
12 
12 
13     bb0: {
-         StorageLive(_2);                 // scope 0 at $DIR/uninhabited-enum.rs:+1:8: +1:14
-         StorageDead(_2);                 // scope 0 at $DIR/uninhabited-enum.rs:+4:1: +4:2
16         unreachable;                     // scope 0 at $DIR/uninhabited-enum.rs:+0:41: +4:2
18 }


thread '[mir-opt] src/test/mir-opt/uninhabited-enum.rs' panicked at 'Actual MIR output differs from expected MIR output /checkout/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir', src/tools/compiletest/src/runtest.rs:3512:25

failures:
    [mir-opt] src/test/mir-opt/const_prop/invalid_constant.rs
    [mir-opt] src/test/mir-opt/uninhabited-enum.rs

rust-log-analyzer avatar Aug 25 '22 02:08 rust-log-analyzer

This PR adds new UB detection to const eval, though it seems to be nothing anyone relied on (crater did not show any new const eval failures).

#[derive(Copy, Clone)]
pub struct ChildStdin {
    inner: AnonPipe,
}
#[derive(Copy, Clone)]
enum AnonPipe {}

const FOO: () = {
const FOO: () = {
    union Foo {
        a: ChildStdin,
        b: (),
    }
    let x = unsafe { Foo { b: () }.a };
    let x = &x.inner;
};

FOO now fails to be evaluated, because the first let x must be unreachable as ChildStdin cannot possibly be constructed.

There's also some code that will now pass typeck when it didn't before:

fn loop_break_void() -> i32 {
    let loop_value = loop { break get_void() };
    // used to error because typeck thought the function
    // could return and thus need to coerce `()` into `i32`
    // right here.
}

I propose to merge this change as the changes are what would be expected from the language side, so this is just a bugfix.

@rfcbot merge

oli-obk avatar Aug 25 '22 07:08 oli-obk

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

  • [x] @compiler-errors
  • [x] @jackh726
  • [x] @lcnr
  • [ ] @nikomatsakis
  • [x] @oli-obk
  • [x] @spastorino

No concerns currently listed.

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 Aug 25 '22 07:08 rfcbot

There's also some code that will now pass typeck when it didn't before:

Oh, this can be done without lang team involvement?

RalfJung avatar Aug 25 '22 12:08 RalfJung

Rebase needed to address the mir-opt failures. Some new changes in those tests.

camsteffen avatar Aug 25 '22 18:08 camsteffen

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

bors avatar Sep 08 '22 05:09 bors

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

rfcbot avatar Sep 08 '22 12:09 rfcbot

@bors try @rust-timer queue

camsteffen avatar Sep 09 '22 23:09 camsteffen