From 687b4d9bb2d1427d2ca9bb6225a706117e379350 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 14 Dec 2022 18:52:14 +0900 Subject: [PATCH 01/12] Add regression test for #104678 Signed-off-by: Yuki Okushi --- .../ui/async-await/in-trait/issue-104678.rs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/test/ui/async-await/in-trait/issue-104678.rs diff --git a/src/test/ui/async-await/in-trait/issue-104678.rs b/src/test/ui/async-await/in-trait/issue-104678.rs new file mode 100644 index 0000000000000..e396df4e5d119 --- /dev/null +++ b/src/test/ui/async-await/in-trait/issue-104678.rs @@ -0,0 +1,31 @@ +// edition:2021 +// check-pass + +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + +use std::future::Future; +pub trait Pool { + type Conn; + + async fn async_callback<'a, F: FnOnce(&'a Self::Conn) -> Fut, Fut: Future>( + &'a self, + callback: F, + ) -> (); +} + +pub struct PoolImpl; +pub struct ConnImpl; + +impl Pool for PoolImpl { + type Conn = ConnImpl; + + async fn async_callback<'a, F: FnOnce(&'a Self::Conn) -> Fut, Fut: Future>( + &'a self, + _callback: F, + ) -> () { + todo!() + } +} + +fn main() {} From 5f5ae17f4efbd54c0d53451101044422e9b728ad Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 12 Dec 2022 18:21:10 +0000 Subject: [PATCH 02/12] Consider discriminant fields that are ordered before variant fields --- compiler/rustc_ty_utils/src/layout.rs | 30 ++++++++++++++----- .../generator_discr_placement.rs | 25 ++++++++++++++++ .../generator_discr_placement.stdout | 11 +++++++ 3 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/print_type_sizes/generator_discr_placement.rs create mode 100644 src/test/ui/print_type_sizes/generator_discr_placement.stdout diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index f4672a70072b2..c15aba681da05 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -919,7 +919,7 @@ fn variant_info_for_generator<'tcx>( def_id: DefId, substs: ty::SubstsRef<'tcx>, ) -> (Vec, Option) { - let Variants::Multiple { tag, ref tag_encoding, .. } = layout.variants else { + let Variants::Multiple { tag, ref tag_encoding, tag_field, .. } = layout.variants else { return (vec![], None); }; @@ -975,12 +975,28 @@ fn variant_info_for_generator<'tcx>( if variant_size == Size::ZERO { variant_size = upvars_size; } - // We need to add the discriminant size back into min_size, since it is subtracted - // later during printing. - variant_size += match tag_encoding { - TagEncoding::Direct => tag.size(cx), - _ => Size::ZERO, - }; + + // This `if` deserves some explanation. + // + // The layout code has a choice of where to place the discriminant of this generator. + // If the discriminant of the generator is placed early in the layout (before the + // variant's own fields), then it'll implicitly be counted towards the size of the + // variant, since we use the maximum offset to calculate size. + // (side-note: I know this is a bit problematic given upvars placement, etc). + // + // This is important, since the layout printing code always subtracts this discriminant + // size from the variant size if the struct is "enum"-like, so failing to account for it + // will either lead to numerical underflow, or an underreported variant size... + // + // However, if the discriminant is placed past the end of the variant, then we need + // to factor in the size of the discriminant manually. This really should be refactored + // better, but this "works" for now. + if layout.fields.offset(tag_field) >= variant_size { + variant_size += match tag_encoding { + TagEncoding::Direct => tag.size(cx), + _ => Size::ZERO, + }; + } VariantInfo { name: Some(Symbol::intern(&ty::GeneratorSubsts::variant_name(variant_idx))), diff --git a/src/test/ui/print_type_sizes/generator_discr_placement.rs b/src/test/ui/print_type_sizes/generator_discr_placement.rs new file mode 100644 index 0000000000000..ddb5db56f9cb9 --- /dev/null +++ b/src/test/ui/print_type_sizes/generator_discr_placement.rs @@ -0,0 +1,25 @@ +// compile-flags: -Z print-type-sizes +// build-pass +// ignore-pass + +// Tests a generator that has its discriminant as the *final* field. + +// Avoid emitting panic handlers, like the rest of these tests... +#![feature(start, generators)] + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + let a = || { + { + let w: i32 = 4; + yield; + drop(w); + } + { + let z: i32 = 7; + yield; + drop(z); + } + }; + 0 +} diff --git a/src/test/ui/print_type_sizes/generator_discr_placement.stdout b/src/test/ui/print_type_sizes/generator_discr_placement.stdout new file mode 100644 index 0000000000000..7dfc8f0bd44f2 --- /dev/null +++ b/src/test/ui/print_type_sizes/generator_discr_placement.stdout @@ -0,0 +1,11 @@ +print-type-size type: `[generator@$DIR/generator_discr_placement.rs:12:13: 12:15]`: 8 bytes, alignment: 4 bytes +print-type-size discriminant: 1 bytes +print-type-size variant `Suspend0`: 7 bytes +print-type-size padding: 3 bytes +print-type-size field `.w`: 4 bytes, alignment: 4 bytes +print-type-size variant `Suspend1`: 7 bytes +print-type-size padding: 3 bytes +print-type-size field `.z`: 4 bytes, alignment: 4 bytes +print-type-size variant `Unresumed`: 0 bytes +print-type-size variant `Returned`: 0 bytes +print-type-size variant `Panicked`: 0 bytes From bdc3c4bf553ca10a1cbaeee8af061eef79417379 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 12 Dec 2022 20:09:34 +0000 Subject: [PATCH 03/12] Make print_type_sizes test not use feature(start) --- src/test/ui/print_type_sizes/async.rs | 12 ++-------- src/test/ui/print_type_sizes/async.stdout | 8 +++---- src/test/ui/print_type_sizes/generator.rs | 8 +++---- .../generator_discr_placement.rs | 8 +++---- .../generator_discr_placement.stdout | 2 +- src/test/ui/print_type_sizes/generics.rs | 24 ++----------------- .../ui/print_type_sizes/multiple_types.rs | 12 +--------- src/test/ui/print_type_sizes/niche-filling.rs | 10 +++----- src/test/ui/print_type_sizes/no_duplicates.rs | 8 ++----- src/test/ui/print_type_sizes/packed.rs | 20 ++++------------ src/test/ui/print_type_sizes/padding.rs | 8 +------ src/test/ui/print_type_sizes/repr-align.rs | 12 +++------- src/test/ui/print_type_sizes/repr_int_c.rs | 8 +------ src/test/ui/print_type_sizes/uninhabited.rs | 6 ++--- src/test/ui/print_type_sizes/variants.rs | 10 +------- .../ui/print_type_sizes/zero-sized-fields.rs | 8 ++----- 16 files changed, 36 insertions(+), 128 deletions(-) diff --git a/src/test/ui/print_type_sizes/async.rs b/src/test/ui/print_type_sizes/async.rs index 3491ad5afbc15..1598b0696913b 100644 --- a/src/test/ui/print_type_sizes/async.rs +++ b/src/test/ui/print_type_sizes/async.rs @@ -1,19 +1,11 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type lib // edition:2021 // build-pass // ignore-pass -#![feature(start)] - async fn wait() {} -async fn test(arg: [u8; 8192]) { +pub async fn test(arg: [u8; 8192]) { wait().await; drop(arg); } - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - let _ = test([0; 8192]); - 0 -} diff --git a/src/test/ui/print_type_sizes/async.stdout b/src/test/ui/print_type_sizes/async.stdout index 94ad09ef296d3..6e47bb4930dc5 100644 --- a/src/test/ui/print_type_sizes/async.stdout +++ b/src/test/ui/print_type_sizes/async.stdout @@ -1,4 +1,4 @@ -print-type-size type: `[async fn body@$DIR/async.rs:10:32: 13:2]`: 16386 bytes, alignment: 1 bytes +print-type-size type: `[async fn body@$DIR/async.rs:8:36: 11:2]`: 16386 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Suspend0`: 16385 bytes print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes @@ -16,14 +16,14 @@ print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment print-type-size variant `MaybeUninit`: 8192 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 8192 bytes -print-type-size type: `[async fn body@$DIR/async.rs:8:17: 8:19]`: 1 bytes, alignment: 1 bytes +print-type-size type: `[async fn body@$DIR/async.rs:6:17: 6:19]`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes -print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1 bytes diff --git a/src/test/ui/print_type_sizes/generator.rs b/src/test/ui/print_type_sizes/generator.rs index a46db6121046b..d1cd36274ef3e 100644 --- a/src/test/ui/print_type_sizes/generator.rs +++ b/src/test/ui/print_type_sizes/generator.rs @@ -1,8 +1,8 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // ignore-pass -#![feature(start, generators, generator_trait)] +#![feature(generators, generator_trait)] use std::ops::Generator; @@ -13,8 +13,6 @@ fn generator(array: [u8; C]) -> impl Generator isize { +pub fn foo() { let _ = generator([0; 8192]); - 0 } diff --git a/src/test/ui/print_type_sizes/generator_discr_placement.rs b/src/test/ui/print_type_sizes/generator_discr_placement.rs index ddb5db56f9cb9..1a85fe95bb6f7 100644 --- a/src/test/ui/print_type_sizes/generator_discr_placement.rs +++ b/src/test/ui/print_type_sizes/generator_discr_placement.rs @@ -1,14 +1,13 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type lib // build-pass // ignore-pass // Tests a generator that has its discriminant as the *final* field. // Avoid emitting panic handlers, like the rest of these tests... -#![feature(start, generators)] +#![feature(generators)] -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +pub fn foo() { let a = || { { let w: i32 = 4; @@ -21,5 +20,4 @@ fn start(_: isize, _: *const *const u8) -> isize { drop(z); } }; - 0 } diff --git a/src/test/ui/print_type_sizes/generator_discr_placement.stdout b/src/test/ui/print_type_sizes/generator_discr_placement.stdout index 7dfc8f0bd44f2..7f8f4ccae7c14 100644 --- a/src/test/ui/print_type_sizes/generator_discr_placement.stdout +++ b/src/test/ui/print_type_sizes/generator_discr_placement.stdout @@ -1,4 +1,4 @@ -print-type-size type: `[generator@$DIR/generator_discr_placement.rs:12:13: 12:15]`: 8 bytes, alignment: 4 bytes +print-type-size type: `[generator@$DIR/generator_discr_placement.rs:11:13: 11:15]`: 8 bytes, alignment: 4 bytes print-type-size discriminant: 1 bytes print-type-size variant `Suspend0`: 7 bytes print-type-size padding: 3 bytes diff --git a/src/test/ui/print_type_sizes/generics.rs b/src/test/ui/print_type_sizes/generics.rs index 3ef7b60db2cae..05097087d5a81 100644 --- a/src/test/ui/print_type_sizes/generics.rs +++ b/src/test/ui/print_type_sizes/generics.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // ignore-pass // ^-- needed because `--pass check` does not emit the output needed. @@ -8,24 +8,6 @@ // monomorphized, in the MIR of the original function in which they // occur, to have their size reported. -#![feature(start)] - -// In an ad-hoc attempt to avoid the injection of unwinding code -// (which clutters the output of `-Z print-type-sizes` with types from -// `unwind::libunwind`): -// -// * I am not using Default to build values because that seems to -// cause the injection of unwinding code. (Instead I just make `fn new` -// methods.) -// -// * Pair derive Copy to ensure that we don't inject -// unwinding code into generic uses of Pair when T itself is also -// Copy. -// -// (I suspect this reflect some naivety within the rust compiler -// itself; it should be checking for drop glue, i.e., a destructor -// somewhere in the monomorphized types. It should not matter whether -// the type is Copy.) #[derive(Copy, Clone)] pub struct Pair { _car: T, @@ -61,11 +43,9 @@ pub fn f1(x: T) { Pair::new(FiftyBytes::new(), FiftyBytes::new()); } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +pub fn start() { let _b: Pair = Pair::new(0, 0); let _s: Pair = Pair::new(SevenBytes::new(), SevenBytes::new()); let ref _z: ZeroSized = ZeroSized; f1::(SevenBytes::new()); - 0 } diff --git a/src/test/ui/print_type_sizes/multiple_types.rs b/src/test/ui/print_type_sizes/multiple_types.rs index f1ad27ec13137..9159038924719 100644 --- a/src/test/ui/print_type_sizes/multiple_types.rs +++ b/src/test/ui/print_type_sizes/multiple_types.rs @@ -1,11 +1,9 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // This file illustrates that when multiple structural types occur in // a function, every one of them is included in the output. -#![feature(start)] - pub struct SevenBytes([u8; 7]); pub struct FiftyBytes([u8; 50]); @@ -13,11 +11,3 @@ pub enum Enum { Small(SevenBytes), Large(FiftyBytes), } - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - let _e: Enum; - let _f: FiftyBytes; - let _s: SevenBytes; - 0 -} diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs index 0716cee21c662..5e620f248b65d 100644 --- a/src/test/ui/print_type_sizes/niche-filling.rs +++ b/src/test/ui/print_type_sizes/niche-filling.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // ignore-pass // ^-- needed because `--pass check` does not emit the output needed. @@ -14,7 +14,6 @@ // aligned (while on most it is 8-byte aligned) and so the resulting // padding and overall computed sizes can be quite different. -#![feature(start)] #![feature(rustc_attrs)] #![allow(dead_code)] @@ -56,7 +55,7 @@ pub struct NestedNonZero { impl Default for NestedNonZero { fn default() -> Self { - NestedNonZero { pre: 0, val: NonZeroU32::new(1).unwrap(), post: 0 } + NestedNonZero { pre: 0, val: unsafe { NonZeroU32::new_unchecked(1) }, post: 0 } } } @@ -76,8 +75,7 @@ pub union Union2 { b: B, } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +pub fn test() { let _x: MyOption = Default::default(); let _y: EmbeddedDiscr = Default::default(); let _z: MyOption = Default::default(); @@ -96,6 +94,4 @@ fn start(_: isize, _: *const *const u8) -> isize { // ...even when theoretically possible. let _j: MyOption> = Default::default(); let _k: MyOption> = Default::default(); - - 0 } diff --git a/src/test/ui/print_type_sizes/no_duplicates.rs b/src/test/ui/print_type_sizes/no_duplicates.rs index e45e4794a3526..2ec5d9e64bfbf 100644 --- a/src/test/ui/print_type_sizes/no_duplicates.rs +++ b/src/test/ui/print_type_sizes/no_duplicates.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // ignore-pass // ^-- needed because `--pass check` does not emit the output needed. @@ -8,16 +8,12 @@ // (even if multiple functions), it is only printed once in the // print-type-sizes output. -#![feature(start)] - pub struct SevenBytes([u8; 7]); pub fn f1() { let _s: SevenBytes = SevenBytes([0; 7]); } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +pub fn test() { let _s: SevenBytes = SevenBytes([0; 7]); - 0 } diff --git a/src/test/ui/print_type_sizes/packed.rs b/src/test/ui/print_type_sizes/packed.rs index 269cc3cc2825f..5ddfe4bf4dbb0 100644 --- a/src/test/ui/print_type_sizes/packed.rs +++ b/src/test/ui/print_type_sizes/packed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // ignore-pass // ^-- needed because `--pass check` does not emit the output needed. @@ -13,11 +13,10 @@ // padding and overall computed sizes can be quite different. #![allow(dead_code)] -#![feature(start)] #[derive(Default)] #[repr(packed)] -struct Packed1 { +pub struct Packed1 { a: u8, b: u8, g: i32, @@ -28,7 +27,7 @@ struct Packed1 { #[derive(Default)] #[repr(packed(2))] -struct Packed2 { +pub struct Packed2 { a: u8, b: u8, g: i32, @@ -40,7 +39,7 @@ struct Packed2 { #[derive(Default)] #[repr(packed(2))] #[repr(C)] -struct Packed2C { +pub struct Packed2C { a: u8, b: u8, g: i32, @@ -50,7 +49,7 @@ struct Packed2C { } #[derive(Default)] -struct Padded { +pub struct Padded { a: u8, b: u8, g: i32, @@ -58,12 +57,3 @@ struct Padded { h: i16, d: u8, } - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - let _c: Packed1 = Default::default(); - let _d: Packed2 = Default::default(); - let _e: Packed2C = Default::default(); - let _f: Padded = Default::default(); - 0 -} diff --git a/src/test/ui/print_type_sizes/padding.rs b/src/test/ui/print_type_sizes/padding.rs index d1acad16d7e1d..f41c677dc6c08 100644 --- a/src/test/ui/print_type_sizes/padding.rs +++ b/src/test/ui/print_type_sizes/padding.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // This file illustrates how padding is handled: alignment @@ -9,7 +9,6 @@ // aligned (while on most it is 8-byte aligned) and so the resulting // padding and overall computed sizes can be quite different. -#![feature(start)] #![allow(dead_code)] struct S { @@ -27,8 +26,3 @@ enum E2 { A(i8, i32), B(S), } - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - 0 -} diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs index 07544935b2f82..0bd11ebc95843 100644 --- a/src/test/ui/print_type_sizes/repr-align.rs +++ b/src/test/ui/print_type_sizes/repr-align.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // ignore-pass // ^-- needed because `--pass check` does not emit the output needed. @@ -11,7 +11,7 @@ // It avoids using u64/i64 because on some targets that is only 4-byte // aligned (while on most it is 8-byte aligned) and so the resulting // padding and overall computed sizes can be quite different. -#![feature(start)] + #![allow(dead_code)] #[repr(align(16))] @@ -24,15 +24,9 @@ enum E { } #[derive(Default)] -struct S { +pub struct S { a: i32, b: i32, c: A, d: i8, } - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - let _s: S = Default::default(); - 0 -} diff --git a/src/test/ui/print_type_sizes/repr_int_c.rs b/src/test/ui/print_type_sizes/repr_int_c.rs index b8067c112eef1..6b103776a30d3 100644 --- a/src/test/ui/print_type_sizes/repr_int_c.rs +++ b/src/test/ui/print_type_sizes/repr_int_c.rs @@ -1,10 +1,9 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // This test makes sure that the tag is not grown for `repr(C)` or `repr(u8)` // variants (see https://github.com/rust-lang/rust/issues/50098 for the original bug). -#![feature(start)] #![allow(dead_code)] #[repr(C, u8)] @@ -18,8 +17,3 @@ enum Repru8 { A(u16), B, } - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - 0 -} diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index 06a62db4ebb0f..86fab7b500af0 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -1,14 +1,12 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // ignore-pass // ^-- needed because `--pass check` does not emit the output needed. // FIXME: consider using an attribute instead of side-effects. #![feature(never_type)] -#![feature(start)] -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +pub fn test() { let _x: Option = None; let _y: Result = Ok(42); let _z: Result = loop {}; diff --git a/src/test/ui/print_type_sizes/variants.rs b/src/test/ui/print_type_sizes/variants.rs index 6c8553cc23ded..5a3020520265d 100644 --- a/src/test/ui/print_type_sizes/variants.rs +++ b/src/test/ui/print_type_sizes/variants.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // This file illustrates two things: @@ -9,8 +9,6 @@ // 2. For an enum, the print-type-sizes output will also include the // size of each variant. -#![feature(start)] - pub struct SevenBytes([u8; 7]); pub struct FiftyBytes([u8; 50]); @@ -18,9 +16,3 @@ pub enum Enum { Small(SevenBytes), Large(FiftyBytes), } - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - let _e: Enum; - 0 -} diff --git a/src/test/ui/print_type_sizes/zero-sized-fields.rs b/src/test/ui/print_type_sizes/zero-sized-fields.rs index e02a33109e56a..09415824d5df0 100644 --- a/src/test/ui/print_type_sizes/zero-sized-fields.rs +++ b/src/test/ui/print_type_sizes/zero-sized-fields.rs @@ -1,12 +1,10 @@ -// compile-flags: -Z print-type-sizes +// compile-flags: -Z print-type-sizes --crate-type=lib // build-pass // ignore-pass // At one point, zero-sized fields such as those in this file were causing // incorrect output from `-Z print-type-sizes`. -#![feature(start)] - struct S1 { x: u32, y: u32, @@ -28,8 +26,7 @@ struct S5 { tagz: TagZ, } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +pub fn test() { let _s1: S1 = S1 { x: 0, y: 0, tag: () }; let _s5: S5<(), Empty> = S5 { @@ -43,5 +40,4 @@ fn start(_: isize, _: *const *const u8) -> isize { z: 4, tagz: Empty {}, }; - 0 } From 9e3d847d7b17b5917f45a6243cf17c2fb484df8c Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 14 Dec 2022 10:26:39 -0700 Subject: [PATCH 04/12] rustdoc: remove unnecessary CSS `kbd { cursor: default }` Added along with theme picker changes in e78f1392b79779fa184f9a63e7be04ac7074a1c2, but no reason seems to have been given at the time for why this particular rule was added. Removing this rule results in `` elements getting an I-bar, while the rule causes them to use the "default" arrow, but since selecting the text in these elements works fine, the I-bar is not misleading. --- src/librustdoc/html/static/css/rustdoc.css | 1 - src/test/rustdoc-gui/help-page.goml | 1 - 2 files changed, 2 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index c485ac9ddb8c1..5b5d4eafa5a5b 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1396,7 +1396,6 @@ kbd { vertical-align: middle; border: solid 1px var(--border-color); border-radius: 3px; - cursor: default; color: var(--kbd--color); background-color: var(--kbd-background); box-shadow: inset 0 -1px 0 var(--kbd-box-shadow-color); diff --git a/src/test/rustdoc-gui/help-page.goml b/src/test/rustdoc-gui/help-page.goml index 799ba851c92f9..80203901ed3c4 100644 --- a/src/test/rustdoc-gui/help-page.goml +++ b/src/test/rustdoc-gui/help-page.goml @@ -27,7 +27,6 @@ define-function: ( "color": |color|, "background-color": |background|, "box-shadow": |box_shadow| + " 0px -1px 0px 0px inset", - "cursor": "default", }, ALL)), ], ) From 7bf36de6abeba487dbe0328685f45b8034513927 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 12 Dec 2022 21:03:00 +0000 Subject: [PATCH 05/12] Make report_projection_error more term agnostic --- .../src/traits/error_reporting/mod.rs | 44 +++++++++++-------- .../const-projection-err.gce.stderr | 24 ++++++++++ .../const-projection-err.rs | 18 ++++++++ .../const-projection-err.stock.stderr | 17 +++++++ src/test/ui/issues/issue-105330.stderr | 8 +++- 5 files changed, 91 insertions(+), 20 deletions(-) create mode 100644 src/test/ui/associated-type-bounds/const-projection-err.gce.stderr create mode 100644 src/test/ui/associated-type-bounds/const-projection-err.rs create mode 100644 src/test/ui/associated-type-bounds/const-projection-err.stock.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index c68da3e24a190..fa94f16dc299a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1636,17 +1636,30 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { infer::LateBoundRegionConversionTime::HigherRankedType, bound_predicate.rebind(data), ); - let normalized_ty = ocx.normalize( - &obligation.cause, - obligation.param_env, - self.tcx.mk_projection(data.projection_ty.def_id, data.projection_ty.substs), - ); + let unnormalized_term = match data.term.unpack() { + ty::TermKind::Ty(_) => self + .tcx + .mk_projection(data.projection_ty.def_id, data.projection_ty.substs) + .into(), + ty::TermKind::Const(ct) => self + .tcx + .mk_const( + ty::UnevaluatedConst { + def: ty::WithOptConstParam::unknown(data.projection_ty.def_id), + substs: data.projection_ty.substs, + }, + ct.ty(), + ) + .into(), + }; + let normalized_term = + ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term); debug!(?obligation.cause, ?obligation.param_env); - debug!(?normalized_ty, data.ty = ?data.term); + debug!(?normalized_term, data.ty = ?data.term); - let is_normalized_ty_expected = !matches!( + let is_normalized_term_expected = !matches!( obligation.cause.code().peel_derives(), ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(_, _) @@ -1655,7 +1668,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ObjectCastObligation(..) | ObligationCauseCode::OpaqueType ); - let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error()); // constrain inference variables a bit more to nested obligations from normalize so // we can have more helpful errors. @@ -1664,11 +1676,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Err(new_err) = ocx.eq_exp( &obligation.cause, obligation.param_env, - is_normalized_ty_expected, - normalized_ty, - expected_ty, + is_normalized_term_expected, + normalized_term, + data.term, ) { - (Some((data, is_normalized_ty_expected, normalized_ty, expected_ty)), new_err) + (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err) } else { (None, error.err) } @@ -1677,12 +1689,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }; let msg = values - .and_then(|(predicate, _, normalized_ty, expected_ty)| { - self.maybe_detailed_projection_msg( - predicate, - normalized_ty.into(), - expected_ty.into(), - ) + .and_then(|(predicate, _, normalized_term, expected_term)| { + self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term) }) .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate)); let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}"); diff --git a/src/test/ui/associated-type-bounds/const-projection-err.gce.stderr b/src/test/ui/associated-type-bounds/const-projection-err.gce.stderr new file mode 100644 index 0000000000000..0f1ec9ad0522f --- /dev/null +++ b/src/test/ui/associated-type-bounds/const-projection-err.gce.stderr @@ -0,0 +1,24 @@ +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-projection-err.rs:4:26 + | +LL | #![cfg_attr(gce, feature(generic_const_exprs))] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0271]: type mismatch resolving `::A == 1` + --> $DIR/const-projection-err.rs:14:11 + | +LL | foo::(); + | ^ expected `0`, found `1` + | +note: required by a bound in `foo` + --> $DIR/const-projection-err.rs:11:28 + | +LL | fn foo>() {} + | ^^^^^ required by this bound in `foo` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/associated-type-bounds/const-projection-err.rs b/src/test/ui/associated-type-bounds/const-projection-err.rs new file mode 100644 index 0000000000000..bead85630016b --- /dev/null +++ b/src/test/ui/associated-type-bounds/const-projection-err.rs @@ -0,0 +1,18 @@ +// revisions: stock gce + +#![feature(associated_const_equality)] +#![cfg_attr(gce, feature(generic_const_exprs))] +//[gce]~^ WARN the feature `generic_const_exprs` is incomplete + +trait TraitWAssocConst { + const A: usize; +} + +fn foo>() {} + +fn bar>() { + foo::(); + //~^ ERROR type mismatch resolving `::A == 1` +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/const-projection-err.stock.stderr b/src/test/ui/associated-type-bounds/const-projection-err.stock.stderr new file mode 100644 index 0000000000000..bf0824259a5a7 --- /dev/null +++ b/src/test/ui/associated-type-bounds/const-projection-err.stock.stderr @@ -0,0 +1,17 @@ +error[E0271]: type mismatch resolving `::A == 1` + --> $DIR/const-projection-err.rs:14:11 + | +LL | foo::(); + | ^ expected `1`, found `::A` + | + = note: expected constant `1` + found constant `::A` +note: required by a bound in `foo` + --> $DIR/const-projection-err.rs:11:28 + | +LL | fn foo>() {} + | ^^^^^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-105330.stderr b/src/test/ui/issues/issue-105330.stderr index 92f2ccb6544b1..30c380152a5e6 100644 --- a/src/test/ui/issues/issue-105330.stderr +++ b/src/test/ui/issues/issue-105330.stderr @@ -55,8 +55,10 @@ error[E0271]: type mismatch resolving `::A == 32` --> $DIR/issue-105330.rs:12:11 | LL | foo::()(); - | ^^^^ types differ + | ^^^^ expected `32`, found `::A` | + = note: expected constant `32` + found constant `::A` note: required by a bound in `foo` --> $DIR/issue-105330.rs:11:28 | @@ -89,8 +91,10 @@ error[E0271]: type mismatch resolving `::A == 32` --> $DIR/issue-105330.rs:19:11 | LL | foo::(); - | ^^^^ types differ + | ^^^^ expected `32`, found `::A` | + = note: expected constant `32` + found constant `::A` note: required by a bound in `foo` --> $DIR/issue-105330.rs:11:28 | From cfa6a93a36d3cbb8e392f5d820e9e139f66c8a5a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 12 Dec 2022 19:23:20 +0000 Subject: [PATCH 06/12] Auto traits in dyn are suggestable --- compiler/rustc_middle/src/ty/diagnostics.rs | 15 ++------------- .../display-is-suggestable.rs | 8 ++++++++ .../display-is-suggestable.stderr | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/argument-suggestions/display-is-suggestable.rs create mode 100644 src/test/ui/argument-suggestions/display-is-suggestable.stderr diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index d7880a32ea9cd..ceb17a59a63d1 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,8 +3,8 @@ use std::ops::ControlFlow; use crate::ty::{ - visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, - InferTy, Opaque, PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, + visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque, + PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; use rustc_data_structures::fx::FxHashMap; @@ -469,17 +469,6 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } } - Dynamic(dty, _, _) => { - for pred in *dty { - match pred.skip_binder() { - ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => { - // Okay - } - _ => return ControlFlow::Break(()), - } - } - } - Param(param) => { // FIXME: It would be nice to make this not use string manipulation, // but it's pretty hard to do this, since `ty::ParamTy` is missing diff --git a/src/test/ui/argument-suggestions/display-is-suggestable.rs b/src/test/ui/argument-suggestions/display-is-suggestable.rs new file mode 100644 index 0000000000000..d765bc4f74d33 --- /dev/null +++ b/src/test/ui/argument-suggestions/display-is-suggestable.rs @@ -0,0 +1,8 @@ +use std::fmt::Display; + +fn foo(x: &(dyn Display + Send)) {} + +fn main() { + foo(); + //~^ ERROR this function takes 1 argument but 0 arguments were supplied +} diff --git a/src/test/ui/argument-suggestions/display-is-suggestable.stderr b/src/test/ui/argument-suggestions/display-is-suggestable.stderr new file mode 100644 index 0000000000000..edd72b53eb3b6 --- /dev/null +++ b/src/test/ui/argument-suggestions/display-is-suggestable.stderr @@ -0,0 +1,19 @@ +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/display-is-suggestable.rs:6:5 + | +LL | foo(); + | ^^^-- an argument of type `&dyn std::fmt::Display + Send` is missing + | +note: function defined here + --> $DIR/display-is-suggestable.rs:3:4 + | +LL | fn foo(x: &(dyn Display + Send)) {} + | ^^^ ------------------------ +help: provide the argument + | +LL | foo(/* &dyn std::fmt::Display + Send */); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0061`. From 2a0d7126e74b4f3de93c88a2b13c6b04372b89c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 14 Dec 2022 11:26:32 -0800 Subject: [PATCH 07/12] Do not mention long types in E0599 label The type is already mentioned in the main message and the list of unmet bounds. --- compiler/rustc_hir_typeck/src/method/suggest.rs | 9 ++++++++- src/test/ui/higher-rank-trait-bounds/issue-30786.stderr | 4 ++-- src/test/ui/issues/issue-31173.stderr | 2 +- src/test/ui/mismatched_types/issue-36053-2.stderr | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 41cd6bf314ebf..b61f35bd45862 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -895,7 +895,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } else { - err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds")); + let ty_str = if ty_str.len() > 50 { + String::new() + } else { + format!("on `{ty_str}` ") + }; + err.span_label(span, format!( + "{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds" + )); } }; diff --git a/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr b/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr index c1e235441d65d..d1d76916b2639 100644 --- a/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr +++ b/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr @@ -8,7 +8,7 @@ LL | pub struct Map { | doesn't satisfy `_: StreamExt` ... LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds + | ^^^^^^^ method cannot be called due to unsatisfied trait bounds | note: the following trait bounds were not satisfied: `&'a mut &Map: Stream` @@ -29,7 +29,7 @@ LL | pub struct Filter { | doesn't satisfy `_: StreamExt` ... LL | let count = filter.countx(); - | ^^^^^^ method cannot be called on `Filter fn(&'a u64) -> &'a u64 {identity::}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>` due to unsatisfied trait bounds + | ^^^^^^ method cannot be called due to unsatisfied trait bounds | note: the following trait bounds were not satisfied: `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream` diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index b667ae0a78937..a32359c2b9f79 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -13,7 +13,7 @@ error[E0599]: the method `collect` exists for struct `Cloned $DIR/issue-31173.rs:12:10 | LL | .collect(); - | ^^^^^^^ method cannot be called on `Cloned, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>` due to unsatisfied trait bounds + | ^^^^^^^ method cannot be called due to unsatisfied trait bounds --> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL | = note: doesn't satisfy `<_ as Iterator>::Item = &_` diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index b91f75b97f84a..3151bc76891e4 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -17,7 +17,7 @@ error[E0599]: the method `count` exists for struct `Filter $DIR/issue-36053-2.rs:7:55 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | --------- ^^^^^ method cannot be called on `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>` due to unsatisfied trait bounds + | --------- ^^^^^ method cannot be called due to unsatisfied trait bounds | | | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` | doesn't satisfy `_: FnMut<(&&str,)>` From de59844c98f7925242a798a72c59dc3610dd0e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 15 Dec 2022 00:06:34 +0100 Subject: [PATCH 08/12] more clippy::complexity fixes --- compiler/rustc_ast/src/ast.rs | 8 +------- compiler/rustc_data_structures/src/sorted_map.rs | 8 ++++---- compiler/rustc_errors/src/emitter.rs | 2 +- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 1 - compiler/rustc_macros/src/diagnostics/diagnostic.rs | 2 +- compiler/rustc_session/src/config.rs | 12 +++--------- compiler/rustc_span/src/analyze_source_file.rs | 4 ++-- compiler/rustc_span/src/lib.rs | 2 +- compiler/rustc_span/src/source_map.rs | 2 +- compiler/rustc_target/src/spec/apple_base.rs | 2 +- compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs | 7 +------ compiler/rustc_type_ir/src/sty.rs | 12 ++++++------ 13 files changed, 23 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 2e86970bcfdc7..f933b9b161ca9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2466,7 +2466,7 @@ pub enum ModKind { Unloaded, } -#[derive(Copy, Clone, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)] pub struct ModSpans { /// `inner_span` covers the body of the module; for a file module, its the whole file. /// For an inline module, its the span inside the `{ ... }`, not including the curly braces. @@ -2474,12 +2474,6 @@ pub struct ModSpans { pub inject_use_span: Span, } -impl Default for ModSpans { - fn default() -> ModSpans { - ModSpans { inner_span: Default::default(), inject_use_span: Default::default() } - } -} - /// Foreign module declaration. /// /// E.g., `extern { .. }` or `extern "C" { .. }`. diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 03ff5e5b3751f..05f059c89d5cd 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -126,13 +126,13 @@ impl SortedMap { /// Iterate over the keys, sorted #[inline] pub fn keys(&self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { - self.data.iter().map(|&(ref k, _)| k) + self.data.iter().map(|(k, _)| k) } /// Iterate over values, sorted by key #[inline] pub fn values(&self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { - self.data.iter().map(|&(_, ref v)| v) + self.data.iter().map(|(_, v)| v) } #[inline] @@ -222,7 +222,7 @@ impl SortedMap { K: Borrow, Q: Ord + ?Sized, { - self.data.binary_search_by(|&(ref x, _)| x.borrow().cmp(key)) + self.data.binary_search_by(|(x, _)| x.borrow().cmp(key)) } #[inline] @@ -300,7 +300,7 @@ impl FromIterator<(K, V)> for SortedMap { fn from_iter>(iter: T) -> Self { let mut data: Vec<(K, V)> = iter.into_iter().collect(); - data.sort_unstable_by(|&(ref k1, _), &(ref k2, _)| k1.cmp(k2)); + data.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2)); data.dedup_by(|&mut (ref k1, _), &mut (ref k2, _)| k1.cmp(k2) == Ordering::Equal); SortedMap { data } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index c62e358e804ca..e2a0e436fd5e2 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2313,7 +2313,7 @@ impl FileWithAnnotatedLines { } // Find overlapping multiline annotations, put them at different depths - multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, usize::MAX - ml.line_end)); + multiline_annotations.sort_by_key(|(_, ml)| (ml.line_start, usize::MAX - ml.line_end)); for (_, ann) in multiline_annotations.clone() { for (_, a) in multiline_annotations.iter_mut() { // Move all other multiline annotations overlapping with this one diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index eb0506c459afa..518b5ec10f890 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -324,7 +324,7 @@ impl CodeSuggestion { // Account for the difference between the width of the current code and the // snippet being suggested, so that the *later* suggestions are correctly // aligned on the screen. - acc += len as isize - (cur_hi.col.0 - cur_lo.col.0) as isize; + acc += len - (cur_hi.col.0 - cur_lo.col.0) as isize; } prev_hi = cur_hi; prev_line = sf.get_line(prev_hi.line - 1); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index ef98c4ba54cbd..29a6902ccb077 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1757,7 +1757,6 @@ impl<'a> State<'a> { self.print_qpath(qpath, true); self.popen(); if let Some(ddpos) = ddpos.as_opt_usize() { - let ddpos = ddpos as usize; self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p)); if ddpos != 0 { self.word_space(","); diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 684835d8c5c86..13f06fe747349 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -192,7 +192,7 @@ impl Mismatch { let crate_name = std::env::var("CARGO_CRATE_NAME").ok()?; // If we're not in a "rustc_" crate, bail. - let Some(("rustc", slug_prefix)) = crate_name.split_once("_") else { return None }; + let Some(("rustc", slug_prefix)) = crate_name.split_once('_') else { return None }; let slug_name = slug.segments.first()?.ident.to_string(); if !slug_name.starts_with(slug_prefix) { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 6de564a3a0692..3bafd3730bd79 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -875,18 +875,12 @@ pub struct PacRet { pub key: PAuthKey, } -#[derive(Clone, Copy, Hash, Debug, PartialEq)] +#[derive(Clone, Copy, Hash, Debug, PartialEq, Default)] pub struct BranchProtection { pub bti: bool, pub pac_ret: Option, } -impl Default for BranchProtection { - fn default() -> Self { - BranchProtection { bti: false, pac_ret: None } - } -} - pub const fn default_lib_output() -> CrateType { CrateType::Rlib } @@ -1875,7 +1869,7 @@ fn parse_opt_level( .into_iter() .flat_map(|(i, s)| { // NB: This can match a string without `=`. - if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None } + if let Some("opt-level") = s.split('=').next() { Some(i) } else { None } }) .max(); if max_o > max_c { @@ -1912,7 +1906,7 @@ fn select_debuginfo( .into_iter() .flat_map(|(i, s)| { // NB: This can match a string without `=`. - if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None } + if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None } }) .max(); if max_g > max_c { diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index d3c2c5113bcde..26cd54210d0bb 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -175,7 +175,7 @@ cfg_if::cfg_if! { // There might still be a tail left to analyze let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset; if tail_start < src.len() { - analyze_source_file_generic(&src[tail_start as usize ..], + analyze_source_file_generic(&src[tail_start ..], src.len() - tail_start, output_offset + BytePos::from_usize(tail_start), lines, @@ -219,7 +219,7 @@ fn analyze_source_file_generic( while i < scan_len { let byte = unsafe { // We verified that i < scan_len <= src.len() - *src_bytes.get_unchecked(i as usize) + *src_bytes.get_unchecked(i) }; // How much to advance in order to get to the next UTF-8 char in the diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 335bfc3302f27..5525eb5331c27 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1381,7 +1381,7 @@ impl Encodable for SourceFile { 4 => { raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs); for diff in diff_iter { - raw_diffs.extend_from_slice(&(diff.0 as u32).to_le_bytes()); + raw_diffs.extend_from_slice(&(diff.0).to_le_bytes()); } } _ => unreachable!(), diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index a4e0f54d27670..fb3e4a6c083f8 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -941,7 +941,7 @@ impl SourceMap { /// Otherwise, the span reached to limit is returned. pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option) -> Span { let mut sp = span; - for _ in 0..limit.unwrap_or(100 as usize) { + for _ in 0..limit.unwrap_or(100_usize) { sp = self.next_point(sp); if let Ok(ref snippet) = self.span_to_snippet(sp) { if expect.map_or(false, |es| snippet == es) { diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index fc6a2edabb763..44644c4733e87 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -81,7 +81,7 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { _ => os.into(), }; - let platform_version: StaticCow = match os.as_ref() { + let platform_version: StaticCow = match os { "ios" => ios_lld_platform_version(), "tvos" => tvos_lld_platform_version(), "watchos" => watchos_lld_platform_version(), diff --git a/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs index e3eb9bccd5ed7..34934379c7e84 100644 --- a/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs +++ b/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs @@ -5,12 +5,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.add_pre_link_args( LinkerFlavor::Unix(Cc::No), - &[ - "-b64".into(), - "-bpT:0x100000000".into(), - "-bpD:0x110000000".into(), - "-bcdtors:all:0:s".into(), - ], + &["-b64", "-bpT:0x100000000", "-bpD:0x110000000", "-bcdtors:all:0:s"], ); Target { diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index e9ffbca96280d..f30ae82d7cdd2 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -250,9 +250,9 @@ impl Clone for TyKind { match self { Bool => Bool, Char => Char, - Int(i) => Int(i.clone()), - Uint(u) => Uint(u.clone()), - Float(f) => Float(f.clone()), + Int(i) => Int(*i), + Uint(u) => Uint(*u), + Float(f) => Float(*f), Adt(d, s) => Adt(d.clone(), s.clone()), Foreign(d) => Foreign(d.clone()), Str => Str, @@ -262,7 +262,7 @@ impl Clone for TyKind { Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()), FnDef(d, s) => FnDef(d.clone(), s.clone()), FnPtr(s) => FnPtr(s.clone()), - Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), repr.clone()), + Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), *repr), Closure(d, s) => Closure(d.clone(), s.clone()), Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()), GeneratorWitness(g) => GeneratorWitness(g.clone()), @@ -270,7 +270,7 @@ impl Clone for TyKind { Tuple(t) => Tuple(t.clone()), Alias(k, p) => Alias(*k, p.clone()), Param(p) => Param(p.clone()), - Bound(d, b) => Bound(d.clone(), b.clone()), + Bound(d, b) => Bound(*d, b.clone()), Placeholder(p) => Placeholder(p.clone()), Infer(t) => Infer(t.clone()), Error(e) => Error(e.clone()), @@ -936,7 +936,7 @@ impl Clone for RegionKind { fn clone(&self) -> Self { match self { ReEarlyBound(r) => ReEarlyBound(r.clone()), - ReLateBound(d, r) => ReLateBound(d.clone(), r.clone()), + ReLateBound(d, r) => ReLateBound(*d, r.clone()), ReFree(r) => ReFree(r.clone()), ReStatic => ReStatic, ReVar(r) => ReVar(r.clone()), From afcc354bc447f0a72a88ac63647a00f673567583 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 14 Dec 2022 16:25:26 -0700 Subject: [PATCH 09/12] rustdoc: remove no-op CSS `.scrape-example .src-line-numbers { margin: 0 }` This is the default CSS for `
` tags in `.code-wrapper` anyway, so this
line does nothing.
---
 src/librustdoc/html/static/css/rustdoc.css | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index c485ac9ddb8c1..e7614789ed925 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1970,7 +1970,6 @@ in storage.js
 }
 
 .scraped-example .code-wrapper .src-line-numbers {
-	margin: 0;
 	padding: 14px 0;
 }
 

From da98ef9a5d0b8a4fb90e1d845506880fae9e7352 Mon Sep 17 00:00:00 2001
From: Dan Johnson 
Date: Wed, 2 Nov 2022 17:45:08 -0700
Subject: [PATCH 10/12] Ensure async trait impls are async (or otherwise return
 an opaque type)

As a workaround for the full `#[refine]` semantics not being implemented
yet, forbit returning a concrete future type like `Box` or a
manually implemented Future.

`-> impl Future` is still permitted; while that can also cause
accidental refinement, that's behind a different feature gate
(`return_position_impl_trait_in_trait`) and that problem exists
regardless of whether the trait method is async, so will have to be
solved more generally.

Fixes #102745
---
 .../locales/en-US/hir_analysis.ftl            |  4 ++
 .../src/check/compare_method.rs               | 32 ++++++++++++++++
 compiler/rustc_hir_analysis/src/errors.rs     | 11 ++++++
 .../in-trait/async-example-desugared-boxed.rs |  7 +---
 .../async-example-desugared-boxed.stderr      | 11 ++++++
 .../in-trait/async-example-desugared-extra.rs | 37 +++++++++++++++++++
 .../async-example-desugared-manual.rs         | 29 +++++++++++++++
 .../async-example-desugared-manual.stderr     | 11 ++++++
 .../in-trait/async-example-desugared.rs       |  5 +--
 .../async-await/in-trait/fn-not-async-err.rs  |  2 +-
 .../in-trait/fn-not-async-err.stderr          | 18 +++------
 .../async-await/in-trait/fn-not-async-err2.rs |  4 +-
 12 files changed, 146 insertions(+), 25 deletions(-)
 create mode 100644 src/test/ui/async-await/in-trait/async-example-desugared-boxed.stderr
 create mode 100644 src/test/ui/async-await/in-trait/async-example-desugared-extra.rs
 create mode 100644 src/test/ui/async-await/in-trait/async-example-desugared-manual.rs
 create mode 100644 src/test/ui/async-await/in-trait/async-example-desugared-manual.stderr

diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
index e33323a779536..26cdf8a58f3fb 100644
--- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
@@ -20,6 +20,10 @@ hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
     .where_label = this `where` clause might not match the one in the trait
     .bounds_label = this bound might be missing in the impl
 
+hir_analysis_async_trait_impl_should_be_async =
+    method `{$method_name}` should be async because the method from the trait is async
+    .trait_item_label = required because the trait method is async
+
 hir_analysis_drop_impl_on_wrong_item =
     the `Drop` trait may only be implemented for local structs, enums, and unions
     .label = must be a struct, enum, or union in the current crate
diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs
index ba7d31cea2e2f..bfa37c05a194f 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_method.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs
@@ -67,6 +67,10 @@ pub(crate) fn compare_impl_method<'tcx>(
         return;
     }
 
+    if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
+        return;
+    }
+
     if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
     {
         return;
@@ -323,6 +327,34 @@ fn compare_predicate_entailment<'tcx>(
     Ok(())
 }
 
+fn compare_asyncness<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: &ty::AssocItem,
+    impl_m_span: Span,
+    trait_m: &ty::AssocItem,
+    trait_item_span: Option,
+) -> Result<(), ErrorGuaranteed> {
+    if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
+        match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
+            ty::Alias(ty::Opaque, ..) => {
+                // allow both `async fn foo()` and `fn foo() -> impl Future`
+            }
+            ty::Error(rustc_errors::ErrorGuaranteed { .. }) => {
+                // We don't know if it's ok, but at least it's already an error.
+            }
+            _ => {
+                return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
+                    span: impl_m_span,
+                    method_name: trait_m.name,
+                    trait_item_span,
+                }));
+            }
+        };
+    }
+
+    Ok(())
+}
+
 #[instrument(skip(tcx), level = "debug", ret)]
 pub fn collect_trait_impl_trait_tys<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index d9697c63c56e1..d383fcacb3a9c 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -51,6 +51,17 @@ pub struct LifetimesOrBoundsMismatchOnTrait {
     pub ident: Ident,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_analysis_async_trait_impl_should_be_async)]
+pub struct AsyncTraitImplShouldBeAsync {
+    #[primary_span]
+    // #[label]
+    pub span: Span,
+    #[label(trait_item_label)]
+    pub trait_item_span: Option,
+    pub method_name: Symbol,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")]
 pub struct DropImplOnWrongItem {
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-boxed.rs b/src/test/ui/async-await/in-trait/async-example-desugared-boxed.rs
index 61d7e2520eab7..1b1b3cffd58f3 100644
--- a/src/test/ui/async-await/in-trait/async-example-desugared-boxed.rs
+++ b/src/test/ui/async-await/in-trait/async-example-desugared-boxed.rs
@@ -1,4 +1,3 @@
-// check-pass
 // edition: 2021
 
 #![feature(async_fn_in_trait)]
@@ -13,11 +12,9 @@ trait MyTrait {
 }
 
 impl MyTrait for i32 {
-    // This will break once a PR that implements #102745 is merged
     fn foo(&self) -> Pin + '_>> {
-        Box::pin(async {
-            *self
-        })
+        //~^ ERROR method `foo` should be async
+        Box::pin(async { *self })
     }
 }
 
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-boxed.stderr b/src/test/ui/async-await/in-trait/async-example-desugared-boxed.stderr
new file mode 100644
index 0000000000000..60fa534a64f02
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-example-desugared-boxed.stderr
@@ -0,0 +1,11 @@
+error: method `foo` should be async because the method from the trait is async
+  --> $DIR/async-example-desugared-boxed.rs:15:5
+   |
+LL |     async fn foo(&self) -> i32;
+   |     --------------------------- required because the trait method is async
+...
+LL |     fn foo(&self) -> Pin + '_>> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-extra.rs b/src/test/ui/async-await/in-trait/async-example-desugared-extra.rs
new file mode 100644
index 0000000000000..81e1e59a36249
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-example-desugared-extra.rs
@@ -0,0 +1,37 @@
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::Poll;
+
+trait MyTrait {
+    async fn foo(&self) -> i32;
+}
+
+#[derive(Clone)]
+struct MyFuture(i32);
+
+impl Future for MyFuture {
+    type Output = i32;
+    fn poll(
+        self: Pin<&mut Self>,
+        _: &mut std::task::Context<'_>,
+    ) -> Poll<::Output> {
+        Poll::Ready(self.0)
+    }
+}
+
+impl MyTrait for i32 {
+    // FIXME: this should eventually require `#[refine]` to compile, because it also provides
+    // `Clone`.
+    fn foo(&self) -> impl Future + Clone {
+        MyFuture(*self)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-manual.rs b/src/test/ui/async-await/in-trait/async-example-desugared-manual.rs
new file mode 100644
index 0000000000000..71473e7455fd6
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-example-desugared-manual.rs
@@ -0,0 +1,29 @@
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::task::Poll;
+
+trait MyTrait {
+    async fn foo(&self) -> i32;
+}
+
+struct MyFuture;
+impl Future for MyFuture {
+    type Output = i32;
+    fn poll(self: std::pin::Pin<&mut Self>, _: &mut std::task::Context<'_>) -> Poll {
+        Poll::Ready(0)
+    }
+}
+
+impl MyTrait for u32 {
+    fn foo(&self) -> MyFuture {
+        //~^ ERROR method `foo` should be async
+        MyFuture
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared-manual.stderr b/src/test/ui/async-await/in-trait/async-example-desugared-manual.stderr
new file mode 100644
index 0000000000000..567a36a86d191
--- /dev/null
+++ b/src/test/ui/async-await/in-trait/async-example-desugared-manual.stderr
@@ -0,0 +1,11 @@
+error: method `foo` should be async because the method from the trait is async
+  --> $DIR/async-example-desugared-manual.rs:23:5
+   |
+LL |     async fn foo(&self) -> i32;
+   |     --------------------------- required because the trait method is async
+...
+LL |     fn foo(&self) -> MyFuture {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/in-trait/async-example-desugared.rs b/src/test/ui/async-await/in-trait/async-example-desugared.rs
index 1313c9edd861c..fb92ec786746f 100644
--- a/src/test/ui/async-await/in-trait/async-example-desugared.rs
+++ b/src/test/ui/async-await/in-trait/async-example-desugared.rs
@@ -12,11 +12,8 @@ trait MyTrait {
 }
 
 impl MyTrait for i32 {
-    // This will break once a PR that implements #102745 is merged
     fn foo(&self) -> impl Future + '_ {
-        async {
-            *self
-        }
+        async { *self }
     }
 }
 
diff --git a/src/test/ui/async-await/in-trait/fn-not-async-err.rs b/src/test/ui/async-await/in-trait/fn-not-async-err.rs
index f94d32145a290..9598d53bce8b2 100644
--- a/src/test/ui/async-await/in-trait/fn-not-async-err.rs
+++ b/src/test/ui/async-await/in-trait/fn-not-async-err.rs
@@ -9,7 +9,7 @@ trait MyTrait {
 
 impl MyTrait for i32 {
     fn foo(&self) -> i32 {
-        //~^ ERROR: `i32` is not a future [E0277]
+        //~^ ERROR: method `foo` should be async
         *self
     }
 }
diff --git a/src/test/ui/async-await/in-trait/fn-not-async-err.stderr b/src/test/ui/async-await/in-trait/fn-not-async-err.stderr
index 03321dc5b5af1..579801d0f3975 100644
--- a/src/test/ui/async-await/in-trait/fn-not-async-err.stderr
+++ b/src/test/ui/async-await/in-trait/fn-not-async-err.stderr
@@ -1,17 +1,11 @@
-error[E0277]: `i32` is not a future
-  --> $DIR/fn-not-async-err.rs:11:22
-   |
-LL |     fn foo(&self) -> i32 {
-   |                      ^^^ `i32` is not a future
-   |
-   = help: the trait `Future` is not implemented for `i32`
-   = note: i32 must be a future or must implement `IntoFuture` to be awaited
-note: required by a bound in `MyTrait::foo::{opaque#0}`
-  --> $DIR/fn-not-async-err.rs:7:28
+error: method `foo` should be async because the method from the trait is async
+  --> $DIR/fn-not-async-err.rs:11:5
    |
 LL |     async fn foo(&self) -> i32;
-   |                            ^^^ required by this bound in `MyTrait::foo::{opaque#0}`
+   |     --------------------------- required because the trait method is async
+...
+LL |     fn foo(&self) -> i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/in-trait/fn-not-async-err2.rs b/src/test/ui/async-await/in-trait/fn-not-async-err2.rs
index 594baa91ad8ba..2c4ed5535801e 100644
--- a/src/test/ui/async-await/in-trait/fn-not-async-err2.rs
+++ b/src/test/ui/async-await/in-trait/fn-not-async-err2.rs
@@ -12,9 +12,7 @@ trait MyTrait {
 impl MyTrait for i32 {
     fn foo(&self) -> impl Future {
         //~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `impl` method return [E0562]
-        async {
-            *self
-        }
+        async { *self }
     }
 }
 

From 6ac0b94f4405f2ca36107f31cd8bcbcb682cc923 Mon Sep 17 00:00:00 2001
From: Michael Howell 
Date: Wed, 14 Dec 2022 22:11:59 -0700
Subject: [PATCH 11/12] rustdoc: remove no-op CSS `.item-info:before { color }`

No content is set, so this pseudo-element does not exist. The CSS was
obsoleted by 73d0f7c7b68784f1db0a1f53855c20d118a7e8b0.
---
 src/librustdoc/html/static/css/themes/ayu.css   | 2 --
 src/librustdoc/html/static/css/themes/dark.css  | 2 --
 src/librustdoc/html/static/css/themes/light.css | 2 --
 3 files changed, 6 deletions(-)

diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index eba845bf5a915..a4097c456135d 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -150,8 +150,6 @@ pre, .rustdoc.source .example-wrap {
 	color: #c5c5c5;
 }
 
-.content .item-info::before { color: #ccc; }
-
 .sidebar h2 a,
 .sidebar h3 a {
 	color: white;
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index d945e956c533e..a11aba12e0ac7 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -85,8 +85,6 @@
 	--table-alt-row-background-color: #2A2A2A;
 }
 
-.content .item-info::before { color: #ccc; }
-
 body.source .example-wrap pre.rust a {
 	background: #333;
 }
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 58955a79316af..f697724468fb3 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -82,8 +82,6 @@
 	--table-alt-row-background-color: #F5F5F5;
 }
 
-.content .item-info::before { color: #ccc; }
-
 body.source .example-wrap pre.rust a {
 	background: #eee;
 }

From a5beb7abb9da221f73e839f555835c36716e3015 Mon Sep 17 00:00:00 2001
From: Jakob Degen 
Date: Tue, 13 Dec 2022 21:30:42 -0800
Subject: [PATCH 12/12] Various cleanups to dest prop

---
 compiler/rustc_mir_transform/src/dest_prop.rs | 171 +++++++++---------
 1 file changed, 88 insertions(+), 83 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 97485c4f57b12..3e45319431cec 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -132,15 +132,12 @@ use std::collections::hash_map::{Entry, OccupiedEntry};
 use crate::MirPass;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::{dump_mir, PassWhere};
 use rustc_middle::mir::{
     traversal, BasicBlock, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place,
     Rvalue, Statement, StatementKind, TerminatorKind,
 };
-use rustc_middle::mir::{
-    visit::{MutVisitor, PlaceContext, Visitor},
-    ProjectionElem,
-};
 use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::MaybeLiveLocals;
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -359,40 +356,45 @@ struct FilterInformation<'a, 'body, 'alloc, 'tcx> {
 // through these methods, and not directly.
 impl<'alloc> Candidates<'alloc> {
     /// Just `Vec::retain`, but the condition is inverted and we add debugging output
-    fn vec_remove_debug(
+    fn vec_filter_candidates(
         src: Local,
         v: &mut Vec,
-        mut f: impl FnMut(Local) -> bool,
+        mut f: impl FnMut(Local) -> CandidateFilter,
         at: Location,
     ) {
         v.retain(|dest| {
             let remove = f(*dest);
-            if remove {
+            if remove == CandidateFilter::Remove {
                 trace!("eliminating {:?} => {:?} due to conflict at {:?}", src, dest, at);
             }
-            !remove
+            remove == CandidateFilter::Keep
         });
     }
 
-    /// `vec_remove_debug` but for an `Entry`
-    fn entry_remove(
+    /// `vec_filter_candidates` but for an `Entry`
+    fn entry_filter_candidates(
         mut entry: OccupiedEntry<'_, Local, Vec>,
         p: Local,
-        f: impl FnMut(Local) -> bool,
+        f: impl FnMut(Local) -> CandidateFilter,
         at: Location,
     ) {
         let candidates = entry.get_mut();
-        Self::vec_remove_debug(p, candidates, f, at);
+        Self::vec_filter_candidates(p, candidates, f, at);
         if candidates.len() == 0 {
             entry.remove();
         }
     }
 
-    /// Removes all candidates `(p, q)` or `(q, p)` where `p` is the indicated local and `f(q)` is true.
-    fn remove_candidates_if(&mut self, p: Local, mut f: impl FnMut(Local) -> bool, at: Location) {
+    /// For all candidates `(p, q)` or `(q, p)` removes the candidate if `f(q)` says to do so
+    fn filter_candidates_by(
+        &mut self,
+        p: Local,
+        mut f: impl FnMut(Local) -> CandidateFilter,
+        at: Location,
+    ) {
         // Cover the cases where `p` appears as a `src`
         if let Entry::Occupied(entry) = self.c.entry(p) {
-            Self::entry_remove(entry, p, &mut f, at);
+            Self::entry_filter_candidates(entry, p, &mut f, at);
         }
         // And the cases where `p` appears as a `dest`
         let Some(srcs) = self.reverse.get_mut(&p) else {
@@ -401,18 +403,31 @@ impl<'alloc> Candidates<'alloc> {
         // We use `retain` here to remove the elements from the reverse set if we've removed the
         // matching candidate in the forward set.
         srcs.retain(|src| {
-            if !f(*src) {
+            if f(*src) == CandidateFilter::Keep {
                 return true;
             }
             let Entry::Occupied(entry) = self.c.entry(*src) else {
                 return false;
             };
-            Self::entry_remove(entry, *src, |dest| dest == p, at);
+            Self::entry_filter_candidates(
+                entry,
+                *src,
+                |dest| {
+                    if dest == p { CandidateFilter::Remove } else { CandidateFilter::Keep }
+                },
+                at,
+            );
             false
         });
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum CandidateFilter {
+    Keep,
+    Remove,
+}
+
 impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
     /// Filters the set of candidates to remove those that conflict.
     ///
@@ -460,7 +475,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
             for (i, statement) in data.statements.iter().enumerate().rev() {
                 self.at = Location { block, statement_index: i };
                 self.live.seek_after_primary_effect(self.at);
-                self.get_statement_write_info(&statement.kind);
+                self.write_info.for_statement(&statement.kind, self.body);
                 self.apply_conflicts();
             }
         }
@@ -469,80 +484,59 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
     fn apply_conflicts(&mut self) {
         let writes = &self.write_info.writes;
         for p in writes {
-            self.candidates.remove_candidates_if(
+            let other_skip = self.write_info.skip_pair.and_then(|(a, b)| {
+                if a == *p {
+                    Some(b)
+                } else if b == *p {
+                    Some(a)
+                } else {
+                    None
+                }
+            });
+            self.candidates.filter_candidates_by(
                 *p,
-                // It is possible that a local may be live for less than the
-                // duration of a statement This happens in the case of function
-                // calls or inline asm. Because of this, we also mark locals as
-                // conflicting when both of them are written to in the same
-                // statement.
-                |q| self.live.contains(q) || writes.contains(&q),
+                |q| {
+                    if Some(q) == other_skip {
+                        return CandidateFilter::Keep;
+                    }
+                    // It is possible that a local may be live for less than the
+                    // duration of a statement This happens in the case of function
+                    // calls or inline asm. Because of this, we also mark locals as
+                    // conflicting when both of them are written to in the same
+                    // statement.
+                    if self.live.contains(q) || writes.contains(&q) {
+                        CandidateFilter::Remove
+                    } else {
+                        CandidateFilter::Keep
+                    }
+                },
                 self.at,
             );
         }
     }
-
-    /// Gets the write info for the `statement`.
-    fn get_statement_write_info(&mut self, statement: &StatementKind<'tcx>) {
-        self.write_info.writes.clear();
-        match statement {
-            StatementKind::Assign(box (lhs, rhs)) => match rhs {
-                Rvalue::Use(op) => {
-                    if !lhs.is_indirect() {
-                        self.get_assign_use_write_info(*lhs, op);
-                        return;
-                    }
-                }
-                _ => (),
-            },
-            _ => (),
-        }
-
-        self.write_info.for_statement(statement);
-    }
-
-    fn get_assign_use_write_info(&mut self, lhs: Place<'tcx>, rhs: &Operand<'tcx>) {
-        // We register the writes for the operand unconditionally
-        self.write_info.add_operand(rhs);
-        // However, we cannot do the same thing for the `lhs` as that would always block the
-        // optimization. Instead, we consider removing candidates manually.
-        let Some(rhs) = rhs.place() else {
-            self.write_info.add_place(lhs);
-            return;
-        };
-        // Find out which candidate pair we should skip, if any
-        let Some((src, dest)) = places_to_candidate_pair(lhs, rhs, self.body) else {
-            self.write_info.add_place(lhs);
-            return;
-        };
-        self.candidates.remove_candidates_if(
-            lhs.local,
-            |other| {
-                // Check if this is the candidate pair that should not be removed
-                if (lhs.local == src && other == dest) || (lhs.local == dest && other == src) {
-                    return false;
-                }
-                // Otherwise, do the "standard" thing
-                self.live.contains(other)
-            },
-            self.at,
-        )
-    }
 }
 
 /// Describes where a statement/terminator writes to
 #[derive(Default, Debug)]
 struct WriteInfo {
     writes: Vec,
+    /// If this pair of locals is a candidate pair, completely skip processing it during this
+    /// statement. All other candidates are unaffected.
+    skip_pair: Option<(Local, Local)>,
 }
 
 impl WriteInfo {
-    fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>) {
+    fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>, body: &Body<'tcx>) {
+        self.reset();
         match statement {
             StatementKind::Assign(box (lhs, rhs)) => {
                 self.add_place(*lhs);
                 match rhs {
-                    Rvalue::Use(op) | Rvalue::Repeat(op, _) => {
+                    Rvalue::Use(op) => {
+                        self.add_operand(op);
+                        self.consider_skipping_for_assign_use(*lhs, op, body);
+                    }
+                    Rvalue::Repeat(op, _) => {
                         self.add_operand(op);
                     }
                     Rvalue::Cast(_, op, _)
@@ -586,8 +580,22 @@ impl WriteInfo {
         }
     }
 
+    fn consider_skipping_for_assign_use<'tcx>(
+        &mut self,
+        lhs: Place<'tcx>,
+        rhs: &Operand<'tcx>,
+        body: &Body<'tcx>,
+    ) {
+        let Some(rhs) = rhs.place() else {
+            return
+        };
+        if let Some(pair) = places_to_candidate_pair(lhs, rhs, body) {
+            self.skip_pair = Some(pair);
+        }
+    }
+
     fn for_terminator<'tcx>(&mut self, terminator: &TerminatorKind<'tcx>) {
-        self.writes.clear();
+        self.reset();
         match terminator {
             TerminatorKind::SwitchInt { discr: op, .. }
             | TerminatorKind::Assert { cond: op, .. } => {
@@ -657,15 +665,16 @@ impl WriteInfo {
             Operand::Copy(_) | Operand::Constant(_) => (),
         }
     }
+
+    fn reset(&mut self) {
+        self.writes.clear();
+        self.skip_pair = None;
+    }
 }
 
 /////////////////////////////////////////////////////
 // Candidate accumulation
 
-fn is_constant<'tcx>(place: Place<'tcx>) -> bool {
-    place.projection.iter().all(|p| !matches!(p, ProjectionElem::Deref | ProjectionElem::Index(_)))
-}
-
 /// If the pair of places is being considered for merging, returns the candidate which would be
 /// merged in order to accomplish this.
 ///
@@ -741,10 +750,6 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> {
             Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
         )) = &statement.kind
         {
-            if !is_constant(*lhs) || !is_constant(*rhs) {
-                return;
-            }
-
             let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
                 return;
             };