From 2a899dc1cfe37270cf976b54a2953133faafa0ae Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 10:46:22 +0000 Subject: [PATCH 01/31] `UnsafeCell` now has no niches, ever. --- compiler/rustc_attr/src/builtin.rs | 8 +- .../rustc_const_eval/src/interpret/intern.rs | 2 +- .../src/interpret/validity.rs | 2 +- .../src/transform/check_consts/qualifs.rs | 4 +- compiler/rustc_feature/src/active.rs | 3 - compiler/rustc_lint/src/types.rs | 2 +- compiler/rustc_middle/src/ty/adt.rs | 11 + compiler/rustc_middle/src/ty/layout.rs | 48 +-- compiler/rustc_middle/src/ty/mod.rs | 10 +- compiler/rustc_passes/src/check_attr.rs | 21 +- compiler/rustc_span/src/symbol.rs | 2 - library/core/src/cell.rs | 1 - library/core/src/lib.rs | 1 - src/test/ui/layout/unsafe-cell-hides-niche.rs | 5 +- src/test/ui/lint/clashing-extern-fn.rs | 4 +- src/test/ui/lint/clashing-extern-fn.stderr | 40 +-- src/test/ui/repr/feature-gate-no-niche.rs | 20 -- src/test/ui/repr/feature-gate-no-niche.stderr | 35 -- .../repr-no-niche-inapplicable-to-unions.rs | 14 - ...epr-no-niche-inapplicable-to-unions.stderr | 19 - src/test/ui/repr/repr-no-niche.rs | 327 ------------------ .../clippy/clippy_lints/src/non_copy_const.rs | 2 +- 22 files changed, 71 insertions(+), 510 deletions(-) delete mode 100644 src/test/ui/repr/feature-gate-no-niche.rs delete mode 100644 src/test/ui/repr/feature-gate-no-niche.stderr delete mode 100644 src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs delete mode 100644 src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr delete mode 100644 src/test/ui/repr/repr-no-niche.rs diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index ce7c0eb72cd24..6673d75d99df0 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -856,7 +856,6 @@ pub enum ReprAttr { ReprSimd, ReprTransparent, ReprAlign(u32), - ReprNoNiche, } #[derive(Eq, PartialEq, Debug, Copy, Clone)] @@ -904,7 +903,6 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { sym::packed => Some(ReprPacked(1)), sym::simd => Some(ReprSimd), sym::transparent => Some(ReprTransparent), - sym::no_niche => Some(ReprNoNiche), sym::align => { let mut err = struct_span_err!( diagnostic, @@ -943,7 +941,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { Ok(literal) => acc.push(ReprPacked(literal)), Err(message) => literal_error = Some(message), }; - } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche) + } else if matches!(name, sym::C | sym::simd | sym::transparent) || int_type_of_word(name).is_some() { recognised = true; @@ -1001,7 +999,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { } else { if matches!( meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent | sym::no_niche + sym::C | sym::simd | sym::transparent ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; @@ -1039,7 +1037,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { .emit(); } else if matches!( meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent | sym::no_niche + sym::C | sym::simd | sym::transparent ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 9dfdafcb38e0b..7616e7a63d107 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -217,7 +217,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory } if let Some(def) = mplace.layout.ty.ty_adt_def() { - if Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() { + if def.is_unsafe_cell() { // We are crossing over an `UnsafeCell`, we can mutate again. This means that // References we encounter inside here are interned as pointing to mutable // allocations. diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 0bf78446e37fa..48ca5913fabbd 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -821,7 +821,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // Special check preventing `UnsafeCell` in the inner part of constants if let Some(def) = op.layout.ty.ty_adt_def() { if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) - && Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() + && def.is_unsafe_cell() { throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 6e5a0c813ac20..770286599d25f 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -96,13 +96,13 @@ impl Qualif for HasMutInterior { } fn in_adt_inherently<'tcx>( - cx: &ConstCx<'_, 'tcx>, + _cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>, _: SubstsRef<'tcx>, ) -> bool { // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently. // It arises structurally for all other types. - Some(adt.did()) == cx.tcx.lang_items().unsafe_cell_type() + adt.is_unsafe_cell() } } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index b54f0ef361a8d..117bdad971a20 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -156,9 +156,6 @@ declare_features! ( (active, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (active, lang_items, "1.0.0", None, None), - /// Allows `#[repr(no_niche)]` (an implementation detail of `rustc`, - /// it is not on path for eventual stabilization). - (active, no_niche, "1.42.0", None, None), /// Allows using `#[omit_gdb_pretty_printer_section]`. (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), /// Allows using `#[prelude_import]` on glob `use` items. diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index be4843c7ff153..4ed9d9b27b297 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -705,7 +705,7 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi // Types with a `#[repr(no_niche)]` attribute have their niche hidden. // The attribute is used by the UnsafeCell for example (the only use so far). - if def.repr().hide_niche() { + if def.is_unsafe_cell() { return false; } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index bf7cb610a9097..9972199c62e04 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -52,6 +52,8 @@ bitflags! { /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`. /// (i.e., this flag is never set unless this ADT is an enum). const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; + /// Indicates whether the type is `UnsafeCell`. + const IS_UNSAFE_CELL = 1 << 9; } } @@ -242,6 +244,9 @@ impl AdtDefData { if Some(did) == tcx.lang_items().manually_drop() { flags |= AdtFlags::IS_MANUALLY_DROP; } + if Some(did) == tcx.lang_items().unsafe_cell_type() { + flags |= AdtFlags::IS_UNSAFE_CELL; + } AdtDefData { did, variants, flags, repr } } @@ -328,6 +333,12 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_BOX) } + /// Returns `true` if this is UnsafeCell. + #[inline] + pub fn is_unsafe_cell(self) -> bool { + self.flags().contains(AdtFlags::IS_UNSAFE_CELL) + } + /// Returns `true` if this is `ManuallyDrop`. #[inline] pub fn is_manually_drop(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index f87b6e4212d29..cef8a1dba7f8d 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -542,14 +542,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { debug!("univariant offset: {:?} field: {:#?}", offset, field); offsets[i as usize] = offset; - if !repr.hide_niche() { - if let Some(mut niche) = field.largest_niche { - let available = niche.available(dl); - if available > largest_niche_available { - largest_niche_available = available; - niche.offset += offset; - largest_niche = Some(niche); - } + if let Some(mut niche) = field.largest_niche { + let available = niche.available(dl); + if available > largest_niche_available { + largest_niche_available = available; + niche.offset += offset; + largest_niche = Some(niche); } } @@ -1104,23 +1102,29 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { assert!(valid_range.end >= end); valid_range.end = end; } - - // Update `largest_niche` if we have introduced a larger niche. - let niche = if def.repr().hide_niche() { - None + if def.is_unsafe_cell() { + match scalar { + Scalar::Initialized { value, valid_range } => { + *valid_range = WrappingRange::full(value.size(dl)) + } + // Already doesn't have any niches + Scalar::Union { .. } => {} + } + st.largest_niche = None; } else { - Niche::from_scalar(dl, Size::ZERO, *scalar) - }; - if let Some(niche) = niche { - match st.largest_niche { - Some(largest_niche) => { - // Replace the existing niche even if they're equal, - // because this one is at a lower offset. - if largest_niche.available(dl) <= niche.available(dl) { - st.largest_niche = Some(niche); + // Update `largest_niche` if we have introduced a larger niche. + let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); + if let Some(niche) = niche { + match st.largest_niche { + Some(largest_niche) => { + // Replace the existing niche even if they're equal, + // because this one is at a lower offset. + if largest_niche.available(dl) <= niche.available(dl) { + st.largest_niche = Some(niche); + } } + None => st.largest_niche = Some(niche), } - None => st.largest_niche = Some(niche), } } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 3a795af2121d0..058cf1a4183df 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1719,11 +1719,9 @@ bitflags! { const IS_TRANSPARENT = 1 << 2; // Internal only for now. If true, don't reorder fields. const IS_LINEAR = 1 << 3; - // If true, don't expose any niche to type's context. - const HIDE_NICHE = 1 << 4; // If true, the type's layout can be randomized using // the seed stored in `ReprOptions.layout_seed` - const RANDOMIZE_LAYOUT = 1 << 5; + const RANDOMIZE_LAYOUT = 1 << 4; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | ReprFlags::IS_SIMD.bits @@ -1780,7 +1778,6 @@ impl ReprOptions { ReprFlags::empty() } attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, - attr::ReprNoNiche => ReprFlags::HIDE_NICHE, attr::ReprSimd => ReprFlags::IS_SIMD, attr::ReprInt(i) => { size = Some(i); @@ -1833,11 +1830,6 @@ impl ReprOptions { self.flags.contains(ReprFlags::IS_LINEAR) } - #[inline] - pub fn hide_niche(&self) -> bool { - self.flags.contains(ReprFlags::HIDE_NICHE) - } - /// Returns the discriminant type, given these `repr` options. /// This must only be called on enums! pub fn discr_type(&self) -> attr::IntType { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8c123c052e5ac..cd5357d796d9a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1808,21 +1808,6 @@ impl CheckAttrVisitor<'_> { _ => ("a", "struct, enum, or union"), } } - sym::no_niche => { - if !self.tcx.features().enabled(sym::no_niche) { - feature_err( - &self.tcx.sess.parse_sess, - sym::no_niche, - hint.span(), - "the attribute `repr(no_niche)` is currently unstable", - ) - .emit(); - } - match target { - Target::Struct | Target::Enum => continue, - _ => ("a", "struct or enum"), - } - } sym::i8 | sym::u8 | sym::i16 @@ -1870,10 +1855,8 @@ impl CheckAttrVisitor<'_> { // This is not ideal, but tracking precisely which ones are at fault is a huge hassle. let hint_spans = hints.iter().map(|hint| hint.span()); - // Error on repr(transparent, ). - let non_no_niche = |hint: &&NestedMetaItem| hint.name_or_empty() != sym::no_niche; - let non_no_niche_count = hints.iter().filter(non_no_niche).count(); - if is_transparent && non_no_niche_count > 1 { + // Error on repr(transparent, ). + if is_transparent && hints.len() > 1 { let hint_spans: Vec<_> = hint_spans.clone().collect(); struct_span_err!( self.tcx.sess, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 65a2a18e02f8f..43312105fd6b0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -979,7 +979,6 @@ symbols! { no_link, no_main, no_mangle, - no_niche, no_sanitize, no_stack_check, no_start, @@ -1152,7 +1151,6 @@ symbols! { repr128, repr_align, repr_align_enum, - repr_no_niche, repr_packed, repr_simd, repr_transparent, diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 63c83ddb6f7cf..8a37fadc56f4c 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1856,7 +1856,6 @@ impl fmt::Display for RefMut<'_, T> { #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] -#[repr(no_niche)] // rust-lang/rust#68303. pub struct UnsafeCell { value: T, } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 093c7d298734a..19775e7acda2f 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -191,7 +191,6 @@ #![feature(never_type)] #![feature(no_core)] #![feature(no_coverage)] // rust-lang/rust#84605 -#![feature(no_niche)] // rust-lang/rust#68303 #![feature(platform_intrinsics)] #![feature(prelude_import)] #![feature(repr_simd)] diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 4ca3f7a1aad94..eb65756a5f643 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -5,8 +5,6 @@ // run-pass -#![feature(no_niche)] - use std::cell::UnsafeCell; use std::mem::size_of; use std::num::NonZeroU32 as N32; @@ -16,8 +14,7 @@ struct Wrapper(T); #[repr(transparent)] struct Transparent(T); -#[repr(no_niche)] -struct NoNiche(T); +struct NoNiche(UnsafeCell); fn main() { assert_eq!(size_of::>>(), 8); diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs index 2ce4dd56eab0d..809e0602671fe 100644 --- a/src/test/ui/lint/clashing-extern-fn.rs +++ b/src/test/ui/lint/clashing-extern-fn.rs @@ -1,7 +1,6 @@ // check-pass // aux-build:external_extern_fn.rs #![crate_type = "lib"] -#![feature(no_niche)] #![warn(clashing_extern_declarations)] mod redeclared_different_signature { @@ -400,9 +399,8 @@ mod hidden_niche { #[repr(transparent)] struct Transparent { x: NonZeroUsize } - #[repr(no_niche)] #[repr(transparent)] - struct TransparentNoNiche { y: NonZeroUsize } + struct TransparentNoNiche { y: UnsafeCell } extern "C" { fn hidden_niche_transparent() -> Option; diff --git a/src/test/ui/lint/clashing-extern-fn.stderr b/src/test/ui/lint/clashing-extern-fn.stderr index a856de322c8ca..4607f68499322 100644 --- a/src/test/ui/lint/clashing-extern-fn.stderr +++ b/src/test/ui/lint/clashing-extern-fn.stderr @@ -1,5 +1,5 @@ warning: `clash` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:15:13 + --> $DIR/clashing-extern-fn.rs:14:13 | LL | fn clash(x: u8); | ---------------- `clash` previously declared here @@ -8,7 +8,7 @@ LL | fn clash(x: u64); | ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | note: the lint level is defined here - --> $DIR/clashing-extern-fn.rs:5:9 + --> $DIR/clashing-extern-fn.rs:4:9 | LL | #![warn(clashing_extern_declarations)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | #![warn(clashing_extern_declarations)] found `unsafe extern "C" fn(u64)` warning: `extern_link_name` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:53:9 + --> $DIR/clashing-extern-fn.rs:52:9 | LL | / #[link_name = "extern_link_name"] LL | | fn some_new_name(x: i16); @@ -29,7 +29,7 @@ LL | fn extern_link_name(x: u32); found `unsafe extern "C" fn(u32)` warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature - --> $DIR/clashing-extern-fn.rs:56:9 + --> $DIR/clashing-extern-fn.rs:55:9 | LL | fn some_other_new_name(x: i16); | ------------------------------- `some_other_new_name` previously declared here @@ -43,7 +43,7 @@ LL | | fn some_other_extern_link_name(x: u32); found `unsafe extern "C" fn(u32)` warning: `other_both_names_different` redeclares `link_name_same` with a different signature - --> $DIR/clashing-extern-fn.rs:60:9 + --> $DIR/clashing-extern-fn.rs:59:9 | LL | / #[link_name = "link_name_same"] LL | | fn both_names_different(x: i16); @@ -58,7 +58,7 @@ LL | | fn other_both_names_different(x: u32); found `unsafe extern "C" fn(u32)` warning: `different_mod` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:73:9 + --> $DIR/clashing-extern-fn.rs:72:9 | LL | fn different_mod(x: u8); | ------------------------ `different_mod` previously declared here @@ -70,7 +70,7 @@ LL | fn different_mod(x: u64); found `unsafe extern "C" fn(u64)` warning: `variadic_decl` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:83:9 + --> $DIR/clashing-extern-fn.rs:82:9 | LL | fn variadic_decl(x: u8, ...); | ----------------------------- `variadic_decl` previously declared here @@ -82,7 +82,7 @@ LL | fn variadic_decl(x: u8); found `unsafe extern "C" fn(u8)` warning: `weigh_banana` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:143:13 + --> $DIR/clashing-extern-fn.rs:142:13 | LL | fn weigh_banana(count: *const Banana) -> u64; | --------------------------------------------- `weigh_banana` previously declared here @@ -94,7 +94,7 @@ LL | fn weigh_banana(count: *const Banana) -> u64; found `unsafe extern "C" fn(*const three::Banana) -> u64` warning: `draw_point` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:172:13 + --> $DIR/clashing-extern-fn.rs:171:13 | LL | fn draw_point(p: Point); | ------------------------ `draw_point` previously declared here @@ -106,7 +106,7 @@ LL | fn draw_point(p: Point); found `unsafe extern "C" fn(sameish_members::b::Point)` warning: `origin` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:198:13 + --> $DIR/clashing-extern-fn.rs:197:13 | LL | fn origin() -> Point3; | ---------------------- `origin` previously declared here @@ -118,7 +118,7 @@ LL | fn origin() -> Point3; found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` warning: `transparent_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:221:13 + --> $DIR/clashing-extern-fn.rs:220:13 | LL | fn transparent_incorrect() -> T; | -------------------------------- `transparent_incorrect` previously declared here @@ -130,7 +130,7 @@ LL | fn transparent_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `missing_return_type` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:239:13 + --> $DIR/clashing-extern-fn.rs:238:13 | LL | fn missing_return_type() -> usize; | ---------------------------------- `missing_return_type` previously declared here @@ -142,7 +142,7 @@ LL | fn missing_return_type(); found `unsafe extern "C" fn()` warning: `non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:257:13 + --> $DIR/clashing-extern-fn.rs:256:13 | LL | fn non_zero_usize() -> core::num::NonZeroUsize; | ----------------------------------------------- `non_zero_usize` previously declared here @@ -154,7 +154,7 @@ LL | fn non_zero_usize() -> usize; found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:259:13 + --> $DIR/clashing-extern-fn.rs:258:13 | LL | fn non_null_ptr() -> core::ptr::NonNull; | ----------------------------------------------- `non_null_ptr` previously declared here @@ -166,7 +166,7 @@ LL | fn non_null_ptr() -> *const usize; found `unsafe extern "C" fn() -> *const usize` warning: `option_non_zero_usize_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:357:13 + --> $DIR/clashing-extern-fn.rs:356:13 | LL | fn option_non_zero_usize_incorrect() -> usize; | ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here @@ -178,7 +178,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `option_non_null_ptr_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:359:13 + --> $DIR/clashing-extern-fn.rs:358:13 | LL | fn option_non_null_ptr_incorrect() -> *const usize; | --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here @@ -190,7 +190,7 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; found `unsafe extern "C" fn() -> *const isize` warning: `hidden_niche_transparent_no_niche` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:410:13 + --> $DIR/clashing-extern-fn.rs:408:13 | LL | fn hidden_niche_transparent_no_niche() -> usize; | ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here @@ -202,7 +202,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option Option` warning: `hidden_niche_unsafe_cell` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:414:13 + --> $DIR/clashing-extern-fn.rs:412:13 | LL | fn hidden_niche_unsafe_cell() -> usize; | --------------------------------------- `hidden_niche_unsafe_cell` previously declared here @@ -214,7 +214,7 @@ LL | fn hidden_niche_unsafe_cell() -> Option Option>` warning: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:410:55 + --> $DIR/clashing-extern-fn.rs:408:55 | LL | fn hidden_niche_transparent_no_niche() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -224,7 +224,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:414:46 + --> $DIR/clashing-extern-fn.rs:412:46 | LL | fn hidden_niche_unsafe_cell() -> Option>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe diff --git a/src/test/ui/repr/feature-gate-no-niche.rs b/src/test/ui/repr/feature-gate-no-niche.rs deleted file mode 100644 index 8872ee7119e4a..0000000000000 --- a/src/test/ui/repr/feature-gate-no-niche.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::num::NonZeroU8 as N8; -use std::num::NonZeroU16 as N16; - -#[repr(no_niche)] -pub struct Cloaked(N16); -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -#[repr(transparent, no_niche)] -pub struct Shadowy(N16); -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -#[repr(no_niche)] -pub enum Cloaked1 { _A(N16), } -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -#[repr(no_niche)] -pub enum Cloaked2 { _A(N16), _B(u8, N8) } -//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] - -fn main() { } diff --git a/src/test/ui/repr/feature-gate-no-niche.stderr b/src/test/ui/repr/feature-gate-no-niche.stderr deleted file mode 100644 index 34fd417cc99a2..0000000000000 --- a/src/test/ui/repr/feature-gate-no-niche.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:4:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:8:21 - | -LL | #[repr(transparent, no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:12:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error[E0658]: the attribute `repr(no_niche)` is currently unstable - --> $DIR/feature-gate-no-niche.rs:16:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ - | - = help: add `#![feature(no_niche)]` to the crate attributes to enable - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs deleted file mode 100644 index 870eda89c20d7..0000000000000 --- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(no_niche)] - -use std::num::NonZeroU8 as N8; -use std::num::NonZeroU16 as N16; - -#[repr(no_niche)] -pub union Cloaked1 { _A: N16 } -//~^^ ERROR attribute should be applied to a struct or enum [E0517] - -#[repr(no_niche)] -pub union Cloaked2 { _A: N16, _B: (u8, N8) } -//~^^ ERROR attribute should be applied to a struct or enum [E0517] - -fn main() { } diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr deleted file mode 100644 index 9af929d409473..0000000000000 --- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0517]: attribute should be applied to a struct or enum - --> $DIR/repr-no-niche-inapplicable-to-unions.rs:6:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ -LL | pub union Cloaked1 { _A: N16 } - | ------------------------------ not a struct or enum - -error[E0517]: attribute should be applied to a struct or enum - --> $DIR/repr-no-niche-inapplicable-to-unions.rs:10:8 - | -LL | #[repr(no_niche)] - | ^^^^^^^^ -LL | pub union Cloaked2 { _A: N16, _B: (u8, N8) } - | -------------------------------------------- not a struct or enum - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0517`. diff --git a/src/test/ui/repr/repr-no-niche.rs b/src/test/ui/repr/repr-no-niche.rs deleted file mode 100644 index 2e6064aeb0074..0000000000000 --- a/src/test/ui/repr/repr-no-niche.rs +++ /dev/null @@ -1,327 +0,0 @@ -// run-pass - -// This file tests repr(no_niche), which causes an struct/enum to hide -// any niche space that may exist in its internal state from the -// context it appears in. - -// Here are the axes this test is seeking to cover: -// -// repr annotation: -// visible: (); cloaked: (no_niche); transparent: (transparent); shadowy: (transparent, no_niche) -// -// enum vs struct -// -// niche-type via type-parameter vs inline declaration - -#![feature(decl_macro)] -#![feature(no_niche)] - -use std::mem::size_of; -use std::num::{NonZeroU8, NonZeroU16}; - -mod struct_inline { - use std::num::NonZeroU16 as N16; - - #[derive(Debug)] pub struct Visible(N16); - - #[repr(no_niche)] - #[derive(Debug)] pub struct Cloaked(N16); - - #[repr(transparent)] - #[derive(Debug)] pub struct Transparent(N16); - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub struct Shadowy(N16); -} - -mod struct_param { - #[derive(Debug)] pub struct Visible(T); - - #[repr(no_niche)] - #[derive(Debug)] pub struct Cloaked(T); - - #[repr(transparent)] - #[derive(Debug)] pub struct Transparent(T); - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub struct Shadowy(T); -} - -mod enum_inline { - use crate::two_fifty_six_variant_enum; - use std::num::{NonZeroU8 as N8, NonZeroU16 as N16}; - - #[derive(Debug)] pub enum Visible1 { _A(N16), } - - #[repr(no_niche)] - #[derive(Debug)] pub enum Cloaked1 { _A(N16), } - - // (N.B.: transparent enums must be univariant) - #[repr(transparent)] - #[derive(Debug)] pub enum Transparent { _A(N16), } - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub enum Shadowy { _A(N16), } - - // including multivariant enums for completeness. Payload and - // number of variants (i.e. discriminant size) have been chosen so - // that layout including discriminant is 4 bytes, with no space in - // padding to hide another discrimnant from the surrounding - // context. - // - // (Note that multivariant enums cannot usefully expose a niche in - // general; this test is relying on that.) - two_fifty_six_variant_enum!(Visible2, N8); - - two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2, N8); -} - -mod enum_param { - use super::two_fifty_six_variant_enum; - - #[derive(Debug)] pub enum Visible1 { _A(T), } - - #[repr(no_niche)] - #[derive(Debug)] pub enum Cloaked1 { _A(T), } - - // (N.B.: transparent enums must be univariant) - #[repr(transparent)] - #[derive(Debug)] pub enum Transparent { _A(T), } - - #[repr(transparent, no_niche)] - #[derive(Debug)] pub enum Shadowy { _A(T), } - - // including multivariant enums for completeness. Same notes apply - // here as above (assuming `T` is instantiated with `NonZeroU8`). - two_fifty_six_variant_enum!(Visible2); - - two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2); -} - -fn main() { - // sanity-checks - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 2); - - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 2); // transparent enums are univariant - assert_eq!(size_of::(), 2); - assert_eq!(size_of::(), 4); - assert_eq!(size_of::(), 4); - - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 4); - assert_eq!(size_of::>(), 4); - - // now the actual tests of no_niche: how do inputs above compose - // with `Option` type constructor. The cases with a `_+2` are the - // ones where no_niche fires. - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2+2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2+2); - - assert_eq!(size_of::>>(), 2); - assert_eq!(size_of::>>(), 2+2); - assert_eq!(size_of::>>(), 2); - assert_eq!(size_of::>>(), 2+2); - - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2+2); - assert_eq!(size_of::>(), 2); - assert_eq!(size_of::>(), 2+2); - // cannot use niche of multivariant payload - assert_eq!(size_of::>(), 4+2); - assert_eq!(size_of::>(), 4+2); - - assert_eq!(size_of::>>(), 2); - assert_eq!(size_of::>>(), 2+2); - assert_eq!(size_of::>>(), 2); - assert_eq!(size_of::>>(), 2+2); - // cannot use niche of multivariant payload - assert_eq!(size_of::>>(), 4+2); - assert_eq!(size_of::>>(), 4+2); -} - -macro two_fifty_six_variant_enum { - ($(#[$attr:meta])* $name:ident<$param:ident>) => { - #[derive(Debug)] $(#[$attr])* - pub enum $name<$param> { - _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param), - _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param), - _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param), - _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param), - - _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param), - _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param), - _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param), - _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param), - - _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param), - _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param), - _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param), - _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param), - - _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param), - _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param), - _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param), - _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param), - - _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param), - _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param), - _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param), - _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param), - - _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param), - _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param), - _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param), - _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param), - - _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param), - _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param), - _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param), - _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param), - - _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param), - _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param), - _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param), - _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param), - - _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param), - _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param), - _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param), - _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param), - - _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param), - _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param), - _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param), - _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param), - - _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param), - _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param), - _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param), - _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param), - - _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param), - _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param), - _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param), - _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param), - - _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param), - _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param), - _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param), - _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param), - - _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param), - _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param), - _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param), - _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param), - - _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param), - _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param), - _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param), - _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param), - - _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param), - _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param), - _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param), - _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param), - } - }, - - ($(#[$attr:meta])* $name:ident, $param:ty) => { - #[derive(Debug)] $(#[$attr])* - pub enum $name { - _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param), - _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param), - _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param), - _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param), - - _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param), - _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param), - _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param), - _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param), - - _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param), - _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param), - _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param), - _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param), - - _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param), - _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param), - _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param), - _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param), - - _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param), - _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param), - _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param), - _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param), - - _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param), - _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param), - _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param), - _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param), - - _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param), - _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param), - _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param), - _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param), - - _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param), - _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param), - _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param), - _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param), - - _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param), - _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param), - _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param), - _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param), - - _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param), - _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param), - _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param), - _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param), - - _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param), - _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param), - _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param), - _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param), - - _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param), - _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param), - _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param), - _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param), - - _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param), - _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param), - _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param), - _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param), - - _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param), - _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param), - _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param), - _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param), - - _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param), - _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param), - _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param), - _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param), - - _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param), - _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param), - _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param), - _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param), - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index a1ef32ae60805..6bce5fbd4c1fe 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -148,7 +148,7 @@ fn is_value_unfrozen_raw<'tcx>( match val.ty().kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. - ty::Adt(ty_def, ..) if Some(ty_def.did()) == cx.tcx.lang_items().unsafe_cell_type() => true, + ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true, ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { let val = cx.tcx.destructure_mir_constant(cx.param_env, val); val.fields.iter().any(|field| inner(cx, *field)) From 8d9f609d0d4465285ac9f0257c706c559644fef5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 11:19:57 +0000 Subject: [PATCH 02/31] Comment update --- compiler/rustc_lint/src/types.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 4ed9d9b27b297..aca481df2e113 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -703,8 +703,7 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi return true; } - // Types with a `#[repr(no_niche)]` attribute have their niche hidden. - // The attribute is used by the UnsafeCell for example (the only use so far). + // `UnsafeCell` has its niche hidden. if def.is_unsafe_cell() { return false; } From d496a4f8bb26709e58ce8821de07f7078d2f615d Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 7 Jul 2022 14:59:54 -0700 Subject: [PATCH 03/31] diagnostics: mention the `:` token when struct fields fail to parse --- compiler/rustc_parse/src/parser/expr.rs | 5 +++++ src/test/ui/parser/issues/issue-52496.stderr | 4 ++-- src/test/ui/parser/issues/issue-62973.stderr | 4 ++-- src/test/ui/parser/removed-syntax-with-2.rs | 2 +- src/test/ui/parser/removed-syntax-with-2.stderr | 4 ++-- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 2c43563b10474..36d633785507c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3012,6 +3012,11 @@ impl<'a> Parser<'a> { } }; + let is_shorthand = parsed_field.as_ref().map_or(false, |f| f.ident.span == f.expr.span); + // A shorthand field can be turned into a full field with `:`. + // We should point this out. + self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon)); + match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) { Ok(_) => { if let Some(f) = parsed_field.or(recovery_field) { diff --git a/src/test/ui/parser/issues/issue-52496.stderr b/src/test/ui/parser/issues/issue-52496.stderr index 9dbf26ef4b68c..cf5c621020fe8 100644 --- a/src/test/ui/parser/issues/issue-52496.stderr +++ b/src/test/ui/parser/issues/issue-52496.stderr @@ -4,11 +4,11 @@ error: float literals must have an integer part LL | let _ = Foo { bar: .5, baz: 42 }; | ^^ help: must have an integer part: `0.5` -error: expected one of `,` or `}`, found `.` +error: expected one of `,`, `:`, or `}`, found `.` --> $DIR/issue-52496.rs:8:22 | LL | let _ = Foo { bar.into(), bat: -1, . }; - | --- ^ expected one of `,` or `}` + | --- ^ expected one of `,`, `:`, or `}` | | | while parsing this struct diff --git a/src/test/ui/parser/issues/issue-62973.stderr b/src/test/ui/parser/issues/issue-62973.stderr index bc3358fc6baa6..d526c9d0bccca 100644 --- a/src/test/ui/parser/issues/issue-62973.stderr +++ b/src/test/ui/parser/issues/issue-62973.stderr @@ -20,11 +20,11 @@ LL | LL | | ^ -error: expected one of `,` or `}`, found `{` +error: expected one of `,`, `:`, or `}`, found `{` --> $DIR/issue-62973.rs:6:8 | LL | fn p() { match s { v, E { [) {) } - | ^ - -^ expected one of `,` or `}` + | ^ - -^ expected one of `,`, `:`, or `}` | | | | | | | help: `}` may belong here | | while parsing this struct diff --git a/src/test/ui/parser/removed-syntax-with-2.rs b/src/test/ui/parser/removed-syntax-with-2.rs index 8a489e71990fb..451057c66a127 100644 --- a/src/test/ui/parser/removed-syntax-with-2.rs +++ b/src/test/ui/parser/removed-syntax-with-2.rs @@ -6,6 +6,6 @@ fn main() { let a = S { foo: (), bar: () }; let b = S { foo: (), with a }; - //~^ ERROR expected one of `,` or `}`, found `a` + //~^ ERROR expected one of `,`, `:`, or `}`, found `a` //~| ERROR missing field `bar` in initializer of `S` } diff --git a/src/test/ui/parser/removed-syntax-with-2.stderr b/src/test/ui/parser/removed-syntax-with-2.stderr index 2c96dceb587ec..c6ae1ce674ff8 100644 --- a/src/test/ui/parser/removed-syntax-with-2.stderr +++ b/src/test/ui/parser/removed-syntax-with-2.stderr @@ -1,8 +1,8 @@ -error: expected one of `,` or `}`, found `a` +error: expected one of `,`, `:`, or `}`, found `a` --> $DIR/removed-syntax-with-2.rs:8:31 | LL | let b = S { foo: (), with a }; - | - ^ expected one of `,` or `}` + | - ^ expected one of `,`, `:`, or `}` | | | while parsing this struct From 6713dde898ef81042a51d940d36150c52cb697b6 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 7 Jul 2022 15:20:08 -0700 Subject: [PATCH 04/31] diagnostics: suggest naming a field after failing to parse --- compiler/rustc_parse/src/parser/expr.rs | 13 +++++++++++++ src/test/ui/parser/issues/issue-52496.stderr | 5 +++-- src/test/ui/parser/issues/issue-62973.stderr | 14 +++++++++++--- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 36d633785507c..f2765e4997ce4 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3037,6 +3037,19 @@ impl<'a> Parser<'a> { ",", Applicability::MachineApplicable, ); + } else if is_shorthand + && (AssocOp::from_token(&self.token).is_some() + || matches!(&self.token.kind, token::OpenDelim(_)) + || self.token.kind == token::Dot) + { + // Looks like they tried to write a shorthand, complex expression. + let ident = parsed_field.expect("is_shorthand implies Some").ident; + e.span_suggestion( + ident.span.shrink_to_lo(), + "try naming a field", + &format!("{ident}: "), + Applicability::HasPlaceholders, + ); } } if !recover { diff --git a/src/test/ui/parser/issues/issue-52496.stderr b/src/test/ui/parser/issues/issue-52496.stderr index cf5c621020fe8..77335c64c2120 100644 --- a/src/test/ui/parser/issues/issue-52496.stderr +++ b/src/test/ui/parser/issues/issue-52496.stderr @@ -8,8 +8,9 @@ error: expected one of `,`, `:`, or `}`, found `.` --> $DIR/issue-52496.rs:8:22 | LL | let _ = Foo { bar.into(), bat: -1, . }; - | --- ^ expected one of `,`, `:`, or `}` - | | + | --- - ^ expected one of `,`, `:`, or `}` + | | | + | | help: try naming a field: `bar:` | while parsing this struct error: expected identifier, found `.` diff --git a/src/test/ui/parser/issues/issue-62973.stderr b/src/test/ui/parser/issues/issue-62973.stderr index d526c9d0bccca..4737bc71860c2 100644 --- a/src/test/ui/parser/issues/issue-62973.stderr +++ b/src/test/ui/parser/issues/issue-62973.stderr @@ -24,11 +24,19 @@ error: expected one of `,`, `:`, or `}`, found `{` --> $DIR/issue-62973.rs:6:8 | LL | fn p() { match s { v, E { [) {) } - | ^ - -^ expected one of `,`, `:`, or `}` - | | | | - | | | help: `}` may belong here + | ^ - ^ expected one of `,`, `:`, or `}` + | | | | | while parsing this struct | unclosed delimiter + | +help: `}` may belong here + | +LL | fn p() { match s { v, E} { [) {) } + | + +help: try naming a field + | +LL | fn p() { match s { v, E: E { [) {) } + | ++ error: struct literals are not allowed here --> $DIR/issue-62973.rs:6:16 From 4bfba76a3da28d780be3cb31fd6269b8bc6183df Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 14:28:19 +0000 Subject: [PATCH 05/31] Add tests for libstd types --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index eb65756a5f643..f6a8e0de27ad0 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -5,9 +5,10 @@ // run-pass -use std::cell::UnsafeCell; +use std::cell::{UnsafeCell, RefCell, Cell}; use std::mem::size_of; use std::num::NonZeroU32 as N32; +use std::sync::{Mutex, RwLock}; struct Wrapper(T); @@ -18,12 +19,23 @@ struct NoNiche(UnsafeCell); fn main() { assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 4); + assert_eq!(size_of::>>(), 4); // (✓ niche opt) assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 4); + assert_eq!(size_of::>>(), 4); // (✓ niche opt) assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 8); + assert_eq!(size_of::>>(), 8); // (✗ niche opt) assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 8); + assert_eq!(size_of::>>(), 8); // (✗ niche opt) + + assert_eq!(size_of::< UnsafeCell<&()> >(), 8); + assert_eq!(size_of::>>(), 16); // (✗ niche opt) + assert_eq!(size_of::< Cell<&()> >(), 8); + assert_eq!(size_of::>>(), 16); // (✗ niche opt) + assert_eq!(size_of::< RefCell<&()> >(), 16); + assert_eq!(size_of::>>(), 24); // (✗ niche opt) + assert_eq!(size_of::< RwLock<&()> >(), 24); + assert_eq!(size_of::>>(), 32); // (✗ niche opt) + assert_eq!(size_of::< Mutex<&()> >(), 16); + assert_eq!(size_of::>>(), 24); // (✗ niche opt) } From 69b1b3c011143b573c904f0759d187588cc457c0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 14:47:25 +0000 Subject: [PATCH 06/31] Create a custom layout path for UnsafeCell instead of piggy backing on the layout_scalar_valid_range logic --- compiler/rustc_middle/src/ty/layout.rs | 60 ++++++++++++------- src/test/ui/layout/unsafe-cell-hides-niche.rs | 9 +++ 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index cef8a1dba7f8d..6d87328ef5daa 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1076,6 +1076,34 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr(), kind)?; st.variants = Variants::Single { index: v }; + + if def.is_unsafe_cell() { + let fill = |scalar: &mut _| match scalar { + Scalar::Initialized { value, valid_range } => { + *valid_range = WrappingRange::full(value.size(dl)) + } + // Already doesn't have any niches + Scalar::Union { .. } => {} + }; + match &mut st.abi { + Abi::Uninhabited => {} + Abi::Scalar(scalar) => fill(scalar), + Abi::ScalarPair(a, b) => { + fill(a); + fill(b); + } + Abi::Vector { element, count: _ } => { + // Until we support types other than floats and integers in SIMD, + // `element` must already be a full for its range, so there's nothing to + // do here. + assert!(element.is_always_valid(dl)); + } + Abi::Aggregate { sized: _ } => {} + } + st.largest_niche = None; + return Ok(tcx.intern_layout(st)); + } + let (start, end) = self.tcx.layout_scalar_valid_range(def.did()); match st.abi { Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { @@ -1102,29 +1130,19 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { assert!(valid_range.end >= end); valid_range.end = end; } - if def.is_unsafe_cell() { - match scalar { - Scalar::Initialized { value, valid_range } => { - *valid_range = WrappingRange::full(value.size(dl)) - } - // Already doesn't have any niches - Scalar::Union { .. } => {} - } - st.largest_niche = None; - } else { - // Update `largest_niche` if we have introduced a larger niche. - let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); - if let Some(niche) = niche { - match st.largest_niche { - Some(largest_niche) => { - // Replace the existing niche even if they're equal, - // because this one is at a lower offset. - if largest_niche.available(dl) <= niche.available(dl) { - st.largest_niche = Some(niche); - } + + // Update `largest_niche` if we have introduced a larger niche. + let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); + if let Some(niche) = niche { + match st.largest_niche { + Some(largest_niche) => { + // Replace the existing niche even if they're equal, + // because this one is at a lower offset. + if largest_niche.available(dl) <= niche.available(dl) { + st.largest_niche = Some(niche); } - None => st.largest_niche = Some(niche), } + None => st.largest_niche = Some(niche), } } } diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index f6a8e0de27ad0..2d3bb1d23c093 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -38,4 +38,13 @@ fn main() { assert_eq!(size_of::>>(), 32); // (✗ niche opt) assert_eq!(size_of::< Mutex<&()> >(), 16); assert_eq!(size_of::>>(), 24); // (✗ niche opt) + + assert_eq!(size_of::< UnsafeCell<&[i32]> >(), 16); + assert_eq!(size_of::>>(), 24); // (✗ niche opt) + assert_eq!(size_of::< UnsafeCell<(&(), &())> >(), 16); + assert_eq!(size_of::>>(), 24); // (✗ niche opt) + + trait Trait {} + assert_eq!(size_of::< UnsafeCell<&dyn Trait> >(), 16); + assert_eq!(size_of::>>(), 24); // (✗ niche opt) } From 423915590b08896ecc845b8b22910cb98c4c7e36 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:11:28 +0000 Subject: [PATCH 07/31] More obvious closure name --- compiler/rustc_middle/src/ty/layout.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6d87328ef5daa..8cbc0169bc7a4 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1078,7 +1078,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { st.variants = Variants::Single { index: v }; if def.is_unsafe_cell() { - let fill = |scalar: &mut _| match scalar { + let hide_niches = |scalar: &mut _| match scalar { Scalar::Initialized { value, valid_range } => { *valid_range = WrappingRange::full(value.size(dl)) } @@ -1087,10 +1087,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; match &mut st.abi { Abi::Uninhabited => {} - Abi::Scalar(scalar) => fill(scalar), + Abi::Scalar(scalar) => hide_niches(scalar), Abi::ScalarPair(a, b) => { - fill(a); - fill(b); + hide_niches(a); + hide_niches(b); } Abi::Vector { element, count: _ } => { // Until we support types other than floats and integers in SIMD, From 984db78d771ec67d781e954da759dbea8667197a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:25:41 +0000 Subject: [PATCH 08/31] Hide niches in SIMD types, too --- compiler/rustc_middle/src/ty/layout.rs | 7 +------ src/test/ui/layout/unsafe-cell-hides-niche.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 8cbc0169bc7a4..1ed41db099ca0 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1092,12 +1092,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { hide_niches(a); hide_niches(b); } - Abi::Vector { element, count: _ } => { - // Until we support types other than floats and integers in SIMD, - // `element` must already be a full for its range, so there's nothing to - // do here. - assert!(element.is_always_valid(dl)); - } + Abi::Vector { element, count: _ } => hide_niches(element), Abi::Aggregate { sized: _ } => {} } st.largest_niche = None; diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 2d3bb1d23c093..bb2156a5da727 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -5,6 +5,8 @@ // run-pass +#![feature(repr_simd)] + use std::cell::{UnsafeCell, RefCell, Cell}; use std::mem::size_of; use std::num::NonZeroU32 as N32; @@ -47,4 +49,10 @@ fn main() { trait Trait {} assert_eq!(size_of::< UnsafeCell<&dyn Trait> >(), 16); assert_eq!(size_of::>>(), 24); // (✗ niche opt) + + #[repr(simd)] + pub struct Vec4([T; 4]); + + assert_eq!(size_of::< UnsafeCell> >(), 16); + assert_eq!(size_of::>>>(), 32); // (✗ niche opt) } From 3f4cf59323304a2e785aba564a6eb3bd473d5499 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:29:02 +0000 Subject: [PATCH 09/31] Move checks to compile-time --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index bb2156a5da727..385472ac88a7d 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -3,7 +3,7 @@ // test checks that an `Option>` has the same // size in memory as an `Option>` (namely, 8 bytes). -// run-pass +// check-pass #![feature(repr_simd)] @@ -19,6 +19,13 @@ struct Transparent(T); struct NoNiche(UnsafeCell); +// Overwriting the runtime assertion and making it a compile-time assertion +macro_rules! assert_eq { + ($a:expr, $b:literal) => {{ + const _: () = assert!($a == $b); + }}; +} + fn main() { assert_eq!(size_of::>>(), 8); assert_eq!(size_of::>>(), 4); // (✓ niche opt) From af8536e32ff8840bb41c65a438ccf33568548e02 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:30:50 +0000 Subject: [PATCH 10/31] Simplify assertion macro --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 385472ac88a7d..f5c1fe1320c56 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -8,7 +8,6 @@ #![feature(repr_simd)] use std::cell::{UnsafeCell, RefCell, Cell}; -use std::mem::size_of; use std::num::NonZeroU32 as N32; use std::sync::{Mutex, RwLock}; @@ -21,45 +20,45 @@ struct NoNiche(UnsafeCell); // Overwriting the runtime assertion and making it a compile-time assertion macro_rules! assert_eq { - ($a:expr, $b:literal) => {{ - const _: () = assert!($a == $b); + ($a:ty, $b:literal) => {{ + const _: () = assert!(std::mem::size_of::<$a>() == $b); }}; } fn main() { - assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 4); // (✓ niche opt) - assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 4); // (✓ niche opt) - assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 8); // (✗ niche opt) + assert_eq!(Option>, 8); + assert_eq!(Option>, 4); // (✓ niche opt) + assert_eq!(Option>, 8); + assert_eq!(Option>, 4); // (✓ niche opt) + assert_eq!(Option>, 8); + assert_eq!(Option>, 8); // (✗ niche opt) - assert_eq!(size_of::>>(), 8); - assert_eq!(size_of::>>(), 8); // (✗ niche opt) + assert_eq!(Option>, 8); + assert_eq!(Option>, 8); // (✗ niche opt) - assert_eq!(size_of::< UnsafeCell<&()> >(), 8); - assert_eq!(size_of::>>(), 16); // (✗ niche opt) - assert_eq!(size_of::< Cell<&()> >(), 8); - assert_eq!(size_of::>>(), 16); // (✗ niche opt) - assert_eq!(size_of::< RefCell<&()> >(), 16); - assert_eq!(size_of::>>(), 24); // (✗ niche opt) - assert_eq!(size_of::< RwLock<&()> >(), 24); - assert_eq!(size_of::>>(), 32); // (✗ niche opt) - assert_eq!(size_of::< Mutex<&()> >(), 16); - assert_eq!(size_of::>>(), 24); // (✗ niche opt) + assert_eq!( UnsafeCell<&()> , 8); + assert_eq!(Option>, 16); // (✗ niche opt) + assert_eq!( Cell<&()> , 8); + assert_eq!(Option< Cell<&()>>, 16); // (✗ niche opt) + assert_eq!( RefCell<&()> , 16); + assert_eq!(Option< RefCell<&()>>, 24); // (✗ niche opt) + assert_eq!( RwLock<&()> , 24); + assert_eq!(Option< RwLock<&()>>, 32); // (✗ niche opt) + assert_eq!( Mutex<&()> , 16); + assert_eq!(Option< Mutex<&()>>, 24); // (✗ niche opt) - assert_eq!(size_of::< UnsafeCell<&[i32]> >(), 16); - assert_eq!(size_of::>>(), 24); // (✗ niche opt) - assert_eq!(size_of::< UnsafeCell<(&(), &())> >(), 16); - assert_eq!(size_of::>>(), 24); // (✗ niche opt) + assert_eq!( UnsafeCell<&[i32]> , 16); + assert_eq!(Option>, 24); // (✗ niche opt) + assert_eq!( UnsafeCell<(&(), &())> , 16); + assert_eq!(Option>, 24); // (✗ niche opt) trait Trait {} - assert_eq!(size_of::< UnsafeCell<&dyn Trait> >(), 16); - assert_eq!(size_of::>>(), 24); // (✗ niche opt) + assert_eq!( UnsafeCell<&dyn Trait> , 16); + assert_eq!(Option>, 24); // (✗ niche opt) #[repr(simd)] pub struct Vec4([T; 4]); - assert_eq!(size_of::< UnsafeCell> >(), 16); - assert_eq!(size_of::>>>(), 32); // (✗ niche opt) + assert_eq!( UnsafeCell> , 16); + assert_eq!(Option>>, 32); // (✗ niche opt) } From fef596f6a243d311dc50b50f83f8339e326f1f66 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:31:21 +0000 Subject: [PATCH 11/31] Rename assertion macro --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index f5c1fe1320c56..7fb55d8219ef8 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -19,46 +19,46 @@ struct Transparent(T); struct NoNiche(UnsafeCell); // Overwriting the runtime assertion and making it a compile-time assertion -macro_rules! assert_eq { +macro_rules! assert_size { ($a:ty, $b:literal) => {{ const _: () = assert!(std::mem::size_of::<$a>() == $b); }}; } fn main() { - assert_eq!(Option>, 8); - assert_eq!(Option>, 4); // (✓ niche opt) - assert_eq!(Option>, 8); - assert_eq!(Option>, 4); // (✓ niche opt) - assert_eq!(Option>, 8); - assert_eq!(Option>, 8); // (✗ niche opt) + assert_size!(Option>, 8); + assert_size!(Option>, 4); // (✓ niche opt) + assert_size!(Option>, 8); + assert_size!(Option>, 4); // (✓ niche opt) + assert_size!(Option>, 8); + assert_size!(Option>, 8); // (✗ niche opt) - assert_eq!(Option>, 8); - assert_eq!(Option>, 8); // (✗ niche opt) + assert_size!(Option>, 8); + assert_size!(Option>, 8); // (✗ niche opt) - assert_eq!( UnsafeCell<&()> , 8); - assert_eq!(Option>, 16); // (✗ niche opt) - assert_eq!( Cell<&()> , 8); - assert_eq!(Option< Cell<&()>>, 16); // (✗ niche opt) - assert_eq!( RefCell<&()> , 16); - assert_eq!(Option< RefCell<&()>>, 24); // (✗ niche opt) - assert_eq!( RwLock<&()> , 24); - assert_eq!(Option< RwLock<&()>>, 32); // (✗ niche opt) - assert_eq!( Mutex<&()> , 16); - assert_eq!(Option< Mutex<&()>>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<&()> , 8); + assert_size!(Option>, 16); // (✗ niche opt) + assert_size!( Cell<&()> , 8); + assert_size!(Option< Cell<&()>>, 16); // (✗ niche opt) + assert_size!( RefCell<&()> , 16); + assert_size!(Option< RefCell<&()>>, 24); // (✗ niche opt) + assert_size!( RwLock<&()> , 24); + assert_size!(Option< RwLock<&()>>, 32); // (✗ niche opt) + assert_size!( Mutex<&()> , 16); + assert_size!(Option< Mutex<&()>>, 24); // (✗ niche opt) - assert_eq!( UnsafeCell<&[i32]> , 16); - assert_eq!(Option>, 24); // (✗ niche opt) - assert_eq!( UnsafeCell<(&(), &())> , 16); - assert_eq!(Option>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<&[i32]> , 16); + assert_size!(Option>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<(&(), &())> , 16); + assert_size!(Option>, 24); // (✗ niche opt) trait Trait {} - assert_eq!( UnsafeCell<&dyn Trait> , 16); - assert_eq!(Option>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<&dyn Trait> , 16); + assert_size!(Option>, 24); // (✗ niche opt) #[repr(simd)] pub struct Vec4([T; 4]); - assert_eq!( UnsafeCell> , 16); - assert_eq!(Option>>, 32); // (✗ niche opt) + assert_size!( UnsafeCell> , 16); + assert_size!(Option>>, 32); // (✗ niche opt) } From 9a204509d2fe9d0ea72cb79ed6e341de7a3bcacb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:34:01 +0000 Subject: [PATCH 12/31] Show sizes in error output --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 7fb55d8219ef8..21ff0cb1e5527 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -18,10 +18,12 @@ struct Transparent(T); struct NoNiche(UnsafeCell); +struct Size; + // Overwriting the runtime assertion and making it a compile-time assertion macro_rules! assert_size { ($a:ty, $b:literal) => {{ - const _: () = assert!(std::mem::size_of::<$a>() == $b); + const _: Size::<$b> = Size::<{std::mem::size_of::<$a>()}>; }}; } From fcd7207d0e5ab4a9598e3b6caf6248134e5f95d6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 10:43:47 +0000 Subject: [PATCH 13/31] Make tests work on 32 bit and 64 bit --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 21ff0cb1e5527..2833f49a27bf6 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -8,6 +8,7 @@ #![feature(repr_simd)] use std::cell::{UnsafeCell, RefCell, Cell}; +use std::mem::size_of; use std::num::NonZeroU32 as N32; use std::sync::{Mutex, RwLock}; @@ -22,11 +23,13 @@ struct Size; // Overwriting the runtime assertion and making it a compile-time assertion macro_rules! assert_size { - ($a:ty, $b:literal) => {{ - const _: Size::<$b> = Size::<{std::mem::size_of::<$a>()}>; + ($a:ty, $b:expr) => {{ + const _: Size::<{$b}> = Size::<{size_of::<$a>()}>; }}; } +const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); + fn main() { assert_size!(Option>, 8); assert_size!(Option>, 4); // (✓ niche opt) @@ -38,25 +41,25 @@ fn main() { assert_size!(Option>, 8); assert_size!(Option>, 8); // (✗ niche opt) - assert_size!( UnsafeCell<&()> , 8); - assert_size!(Option>, 16); // (✗ niche opt) - assert_size!( Cell<&()> , 8); - assert_size!(Option< Cell<&()>>, 16); // (✗ niche opt) - assert_size!( RefCell<&()> , 16); - assert_size!(Option< RefCell<&()>>, 24); // (✗ niche opt) - assert_size!( RwLock<&()> , 24); - assert_size!(Option< RwLock<&()>>, 32); // (✗ niche opt) - assert_size!( Mutex<&()> , 16); - assert_size!(Option< Mutex<&()>>, 24); // (✗ niche opt) - - assert_size!( UnsafeCell<&[i32]> , 16); - assert_size!(Option>, 24); // (✗ niche opt) - assert_size!( UnsafeCell<(&(), &())> , 16); - assert_size!(Option>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<&()> , PTR_SIZE); + assert_size!(Option>, PTR_SIZE * 2); // (✗ niche opt) + assert_size!( Cell<&()> , PTR_SIZE); + assert_size!(Option< Cell<&()>>, PTR_SIZE * 2); // (✗ niche opt) + assert_size!( RefCell<&()> , PTR_SIZE * 2); + assert_size!(Option< RefCell<&()>>, PTR_SIZE * 3); // (✗ niche opt) + assert_size!( RwLock<&()> , if cfg!(target_pointer_width = "32") { 16 } else { 24 }); + assert_size!(Option< RwLock<&()>>, if cfg!(target_pointer_width = "32") { 20 } else { 32 }); // (✗ niche opt) + assert_size!( Mutex<&()> , if cfg!(target_pointer_width = "32") { 12 } else { 16 }); + assert_size!(Option< Mutex<&()>>, if cfg!(target_pointer_width = "32") { 16 } else { 24 }); // (✗ niche opt) + + assert_size!( UnsafeCell<&[i32]> , PTR_SIZE * 2); + assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) + assert_size!( UnsafeCell<(&(), &())> , PTR_SIZE * 2); + assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) trait Trait {} - assert_size!( UnsafeCell<&dyn Trait> , 16); - assert_size!(Option>, 24); // (✗ niche opt) + assert_size!( UnsafeCell<&dyn Trait> , PTR_SIZE * 2); + assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) #[repr(simd)] pub struct Vec4([T; 4]); From 8440208eb13ec1f680592b9a7793a67f2b1be15e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 11:07:03 +0000 Subject: [PATCH 14/31] tidy --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 2833f49a27bf6..1d0e1fce178d0 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -47,10 +47,22 @@ fn main() { assert_size!(Option< Cell<&()>>, PTR_SIZE * 2); // (✗ niche opt) assert_size!( RefCell<&()> , PTR_SIZE * 2); assert_size!(Option< RefCell<&()>>, PTR_SIZE * 3); // (✗ niche opt) - assert_size!( RwLock<&()> , if cfg!(target_pointer_width = "32") { 16 } else { 24 }); - assert_size!(Option< RwLock<&()>>, if cfg!(target_pointer_width = "32") { 20 } else { 32 }); // (✗ niche opt) - assert_size!( Mutex<&()> , if cfg!(target_pointer_width = "32") { 12 } else { 16 }); - assert_size!(Option< Mutex<&()>>, if cfg!(target_pointer_width = "32") { 16 } else { 24 }); // (✗ niche opt) + assert_size!( + RwLock<&()>, + if cfg!(target_pointer_width = "32") { 16 } else { 24 } + ); + assert_size!( + Option>, + if cfg!(target_pointer_width = "32") { 20 } else { 32 } + ); // (✗ niche opt) + assert_size!( + Mutex<&()> , + if cfg!(target_pointer_width = "32") { 12 } else { 16 } + ); + assert_size!( + Option>, + if cfg!(target_pointer_width = "32") { 16 } else { 24 } + ); // (✗ niche opt) assert_size!( UnsafeCell<&[i32]> , PTR_SIZE * 2); assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) From e51f1b7e275584872525bbfbd7c481595b99f237 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 11 Jul 2022 14:26:58 +0100 Subject: [PATCH 15/31] Keep unstable target features for asm feature checking Inline assembly uses the target features to determine which registers are available on the current target. However it needs to be able to access unstable target features for this. Fixes #99071 --- compiler/rustc_codegen_cranelift/src/lib.rs | 2 +- compiler/rustc_codegen_gcc/src/lib.rs | 8 ++-- compiler/rustc_codegen_llvm/src/lib.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 39 ++++++++++--------- .../rustc_codegen_ssa/src/traits/backend.rs | 2 +- compiler/rustc_interface/src/util.rs | 5 ++- compiler/rustc_session/src/session.rs | 4 ++ compiler/rustc_typeck/src/collect.rs | 2 +- 8 files changed, 38 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 9d2e12f98984a..da6e788700624 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -167,7 +167,7 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn target_features(&self, _sess: &Session) -> Vec { + fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { vec![] } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 58996a9db78ad..91c1fa6026c48 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -133,8 +133,8 @@ impl CodegenBackend for GccCodegenBackend { ) } - fn target_features(&self, sess: &Session) -> Vec { - target_features(sess) + fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec { + target_features(sess, allow_unstable) } } @@ -291,12 +291,12 @@ pub fn target_cpu(sess: &Session) -> &str { } } -pub fn target_features(sess: &Session) -> Vec { +pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { supported_target_features(sess) .iter() .filter_map( |&(feature, gate)| { - if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } + if sess.is_nightly_build() || allow_unstable || gate.is_none() { Some(feature) } else { None } }, ) .filter(|_feature| { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 913cf4eea13a3..c87d9a5406d3b 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -324,8 +324,8 @@ impl CodegenBackend for LlvmCodegenBackend { llvm_util::print_version(); } - fn target_features(&self, sess: &Session) -> Vec { - target_features(sess) + fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec { + target_features(sess, allow_unstable) } fn codegen_crate<'tcx>( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index ce6c6e3215c9b..5b3b7db12b7ce 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -233,26 +233,29 @@ pub fn check_tied_features( // Used to generate cfg variables and apply features // Must express features in the way Rust understands them -pub fn target_features(sess: &Session) -> Vec { +pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { let target_machine = create_informational_target_machine(sess); - let mut features: Vec = - supported_target_features(sess) - .iter() - .filter_map(|&(feature, gate)| { - if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } - }) - .filter(|feature| { - // check that all features in a given smallvec are enabled - for llvm_feature in to_llvm_features(sess, feature) { - let cstr = SmallCStr::new(llvm_feature); - if !unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } { - return false; - } + let mut features: Vec = supported_target_features(sess) + .iter() + .filter_map(|&(feature, gate)| { + if sess.is_nightly_build() || allow_unstable || gate.is_none() { + Some(feature) + } else { + None + } + }) + .filter(|feature| { + // check that all features in a given smallvec are enabled + for llvm_feature in to_llvm_features(sess, feature) { + let cstr = SmallCStr::new(llvm_feature); + if !unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } { + return false; } - true - }) - .map(|feature| Symbol::intern(feature)) - .collect(); + } + true + }) + .map(|feature| Symbol::intern(feature)) + .collect(); // LLVM 14 changed the ABI for i128 arguments to __float/__fix builtins on Win64 // (see https://reviews.llvm.org/D110413). This unstable target feature is intended for use diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 1e53c73d1bb4a..779bd3ea278ec 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -59,7 +59,7 @@ impl<'tcx, T> Backend<'tcx> for T where pub trait CodegenBackend { fn init(&self, _sess: &Session) {} fn print(&self, _req: PrintRequest, _sess: &Session) {} - fn target_features(&self, _sess: &Session) -> Vec { + fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { vec![] } fn print_passes(&self) {} diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 3fa8017dc93c3..a75383715a9ae 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -48,7 +48,10 @@ pub fn add_configuration( ) { let tf = sym::target_feature; - let target_features = codegen_backend.target_features(sess); + let unstable_target_features = codegen_backend.target_features(sess, true); + sess.unstable_target_features.extend(unstable_target_features.iter().cloned()); + + let target_features = codegen_backend.target_features(sess, false); sess.target_features.extend(target_features.iter().cloned()); cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat)))); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index b2c23cda6aae5..5a83a1f6caec4 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -194,6 +194,9 @@ pub struct Session { /// Set of enabled features for the current target. pub target_features: FxHashSet, + + /// Set of enabled features for the current target, including unstable ones. + pub unstable_target_features: FxHashSet, } pub struct PerfStats { @@ -1341,6 +1344,7 @@ pub fn build_session( miri_unleashed_features: Lock::new(Default::default()), asm_arch, target_features: FxHashSet::default(), + unstable_target_features: FxHashSet::default(), }; validate_commandline_args_with_session_available(&sess); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 838980e08aa04..016fafd3aec16 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -3198,7 +3198,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { /// Computes the set of target features used in a function for the purposes of /// inline assembly. fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet { - let mut target_features = tcx.sess.target_features.clone(); + let mut target_features = tcx.sess.unstable_target_features.clone(); if tcx.def_kind(did).has_codegen_attrs() { let attrs = tcx.codegen_fn_attrs(did); target_features.extend(&attrs.target_features); From dfe68eede3cef45c8a420aeb8ab4a57426662e04 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 11 Jul 2022 14:47:22 +0100 Subject: [PATCH 16/31] Add test for issue 99071 --- src/test/ui/asm/issue-99071.rs | 21 +++++++++++++++++++++ src/test/ui/asm/issue-99071.stderr | 8 ++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/test/ui/asm/issue-99071.rs create mode 100644 src/test/ui/asm/issue-99071.stderr diff --git a/src/test/ui/asm/issue-99071.rs b/src/test/ui/asm/issue-99071.rs new file mode 100644 index 0000000000000..bb6201861dff6 --- /dev/null +++ b/src/test/ui/asm/issue-99071.rs @@ -0,0 +1,21 @@ +// compile-flags: --target thumbv6m-none-eabi +// needs-llvm-components: arm +// needs-asm-support + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] +#![crate_type = "rlib"] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[lang = "sized"] +trait Sized {} + +pub fn foo() { + unsafe { + asm!("", in("r8") 0); + //~^ cannot use register `r8`: high registers (r8+) can only be used as clobbers in Thumb-1 code + } +} diff --git a/src/test/ui/asm/issue-99071.stderr b/src/test/ui/asm/issue-99071.stderr new file mode 100644 index 0000000000000..47386ffa4a8c9 --- /dev/null +++ b/src/test/ui/asm/issue-99071.stderr @@ -0,0 +1,8 @@ +error: cannot use register `r8`: high registers (r8+) can only be used as clobbers in Thumb-1 code + --> $DIR/issue-99071.rs:18:18 + | +LL | asm!("", in("r8") 0); + | ^^^^^^^^^^ + +error: aborting due to previous error + From d935c70afa464dcf16db532e39ae53621debd096 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 14:16:14 +0000 Subject: [PATCH 17/31] Don't allow accidental runtime-checks --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 101 +++++++++--------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 1d0e1fce178d0..865fc2ae29702 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -4,6 +4,7 @@ // size in memory as an `Option>` (namely, 8 bytes). // check-pass +// compile-flags: --crate-type=lib #![feature(repr_simd)] @@ -23,59 +24,57 @@ struct Size; // Overwriting the runtime assertion and making it a compile-time assertion macro_rules! assert_size { - ($a:ty, $b:expr) => {{ + ($a:ty, $b:expr) => { const _: Size::<{$b}> = Size::<{size_of::<$a>()}>; - }}; + }; } const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); -fn main() { - assert_size!(Option>, 8); - assert_size!(Option>, 4); // (✓ niche opt) - assert_size!(Option>, 8); - assert_size!(Option>, 4); // (✓ niche opt) - assert_size!(Option>, 8); - assert_size!(Option>, 8); // (✗ niche opt) - - assert_size!(Option>, 8); - assert_size!(Option>, 8); // (✗ niche opt) - - assert_size!( UnsafeCell<&()> , PTR_SIZE); - assert_size!(Option>, PTR_SIZE * 2); // (✗ niche opt) - assert_size!( Cell<&()> , PTR_SIZE); - assert_size!(Option< Cell<&()>>, PTR_SIZE * 2); // (✗ niche opt) - assert_size!( RefCell<&()> , PTR_SIZE * 2); - assert_size!(Option< RefCell<&()>>, PTR_SIZE * 3); // (✗ niche opt) - assert_size!( - RwLock<&()>, - if cfg!(target_pointer_width = "32") { 16 } else { 24 } - ); - assert_size!( - Option>, - if cfg!(target_pointer_width = "32") { 20 } else { 32 } - ); // (✗ niche opt) - assert_size!( - Mutex<&()> , - if cfg!(target_pointer_width = "32") { 12 } else { 16 } - ); - assert_size!( - Option>, - if cfg!(target_pointer_width = "32") { 16 } else { 24 } - ); // (✗ niche opt) - - assert_size!( UnsafeCell<&[i32]> , PTR_SIZE * 2); - assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) - assert_size!( UnsafeCell<(&(), &())> , PTR_SIZE * 2); - assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) - - trait Trait {} - assert_size!( UnsafeCell<&dyn Trait> , PTR_SIZE * 2); - assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) - - #[repr(simd)] - pub struct Vec4([T; 4]); - - assert_size!( UnsafeCell> , 16); - assert_size!(Option>>, 32); // (✗ niche opt) -} +assert_size!(Option>, 8); +assert_size!(Option>, 4); // (✓ niche opt) +assert_size!(Option>, 8); +assert_size!(Option>, 4); // (✓ niche opt) +assert_size!(Option>, 8); +assert_size!(Option>, 8); // (✗ niche opt) + +assert_size!(Option>, 8); +assert_size!(Option>, 8); // (✗ niche opt) + +assert_size!( UnsafeCell<&()> , PTR_SIZE); +assert_size!(Option>, PTR_SIZE * 2); // (✗ niche opt) +assert_size!( Cell<&()> , PTR_SIZE); +assert_size!(Option< Cell<&()>>, PTR_SIZE * 2); // (✗ niche opt) +assert_size!( RefCell<&()> , PTR_SIZE * 2); +assert_size!(Option< RefCell<&()>>, PTR_SIZE * 3); // (✗ niche opt) +assert_size!( + RwLock<&()>, + if cfg!(target_pointer_width = "32") { 16 } else { 24 } +); +assert_size!( + Option>, + if cfg!(target_pointer_width = "32") { 20 } else { 32 } +); // (✗ niche opt) +assert_size!( + Mutex<&()> , + if cfg!(target_pointer_width = "32") { 12 } else { 16 } +); +assert_size!( + Option>, + if cfg!(target_pointer_width = "32") { 16 } else { 24 } +); // (✗ niche opt) + +assert_size!( UnsafeCell<&[i32]> , PTR_SIZE * 2); +assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) +assert_size!( UnsafeCell<(&(), &())> , PTR_SIZE * 2); +assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) + +trait Trait {} +assert_size!( UnsafeCell<&dyn Trait> , PTR_SIZE * 2); +assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) + +#[repr(simd)] +pub struct Vec4([T; 4]); + +assert_size!( UnsafeCell> , 16); +assert_size!(Option>>, 32); // (✗ niche opt) From cdd6bba8f662b25d52a58d5ffebbe5c3eac60220 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 14:23:32 +0000 Subject: [PATCH 18/31] Simplify size checking --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 70 ++++++++----------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 865fc2ae29702..9e80a708f2fd7 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -23,58 +23,50 @@ struct NoNiche(UnsafeCell); struct Size; // Overwriting the runtime assertion and making it a compile-time assertion -macro_rules! assert_size { - ($a:ty, $b:expr) => { - const _: Size::<{$b}> = Size::<{size_of::<$a>()}>; +macro_rules! assert_size_eq { + ($ty:ty, $size:expr) => { + const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; + }; + ($ty:ty, $size:expr, $optioned_size:expr) => { + assert_size_eq!($ty, $size); + assert_size_eq!(Option<$ty>, $optioned_size); + const _: () = assert!($size == $optioned_size || size_of::<$ty>() < size_of::>()); }; } const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); -assert_size!(Option>, 8); -assert_size!(Option>, 4); // (✓ niche opt) -assert_size!(Option>, 8); -assert_size!(Option>, 4); // (✓ niche opt) -assert_size!(Option>, 8); -assert_size!(Option>, 8); // (✗ niche opt) - -assert_size!(Option>, 8); -assert_size!(Option>, 8); // (✗ niche opt) - -assert_size!( UnsafeCell<&()> , PTR_SIZE); -assert_size!(Option>, PTR_SIZE * 2); // (✗ niche opt) -assert_size!( Cell<&()> , PTR_SIZE); -assert_size!(Option< Cell<&()>>, PTR_SIZE * 2); // (✗ niche opt) -assert_size!( RefCell<&()> , PTR_SIZE * 2); -assert_size!(Option< RefCell<&()>>, PTR_SIZE * 3); // (✗ niche opt) -assert_size!( +assert_size_eq!(Wrapper, 4, 8); +assert_size_eq!(Wrapper, 4, 4); // (✓ niche opt) +assert_size_eq!(Transparent, 4, 8); +assert_size_eq!(Transparent, 4, 4); // (✓ niche opt) +assert_size_eq!(NoNiche, 4, 8); +assert_size_eq!(NoNiche, 4, 8); + +assert_size_eq!(UnsafeCell, 4, 8); +assert_size_eq!(UnsafeCell, 4, 8); + +assert_size_eq!(UnsafeCell<&()> , PTR_SIZE, PTR_SIZE * 2); +assert_size_eq!( Cell<&()> , PTR_SIZE, PTR_SIZE * 2); +assert_size_eq!( RefCell<&()> , PTR_SIZE * 2, PTR_SIZE * 3); +assert_size_eq!( RwLock<&()>, - if cfg!(target_pointer_width = "32") { 16 } else { 24 } -); -assert_size!( - Option>, + if cfg!(target_pointer_width = "32") { 16 } else { 24 }, if cfg!(target_pointer_width = "32") { 20 } else { 32 } -); // (✗ niche opt) -assert_size!( - Mutex<&()> , - if cfg!(target_pointer_width = "32") { 12 } else { 16 } ); -assert_size!( - Option>, +assert_size_eq!( + Mutex<&()> , + if cfg!(target_pointer_width = "32") { 12 } else { 16 }, if cfg!(target_pointer_width = "32") { 16 } else { 24 } -); // (✗ niche opt) +); -assert_size!( UnsafeCell<&[i32]> , PTR_SIZE * 2); -assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) -assert_size!( UnsafeCell<(&(), &())> , PTR_SIZE * 2); -assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) +assert_size_eq!(UnsafeCell<&[i32]> , PTR_SIZE * 2, PTR_SIZE * 3); +assert_size_eq!(UnsafeCell<(&(), &())> , PTR_SIZE * 2, PTR_SIZE * 3); trait Trait {} -assert_size!( UnsafeCell<&dyn Trait> , PTR_SIZE * 2); -assert_size!(Option>, PTR_SIZE * 3); // (✗ niche opt) +assert_size_eq!(UnsafeCell<&dyn Trait> , PTR_SIZE * 2, PTR_SIZE * 3); #[repr(simd)] pub struct Vec4([T; 4]); -assert_size!( UnsafeCell> , 16); -assert_size!(Option>>, 32); // (✗ niche opt) +assert_size_eq!(UnsafeCell> , 16, 32); From 0318b70514e13d09fd0e9043da4b7c49e0285f75 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 14:35:04 +0000 Subject: [PATCH 19/31] tidy --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 9e80a708f2fd7..7f159887ba1d4 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -30,7 +30,10 @@ macro_rules! assert_size_eq { ($ty:ty, $size:expr, $optioned_size:expr) => { assert_size_eq!($ty, $size); assert_size_eq!(Option<$ty>, $optioned_size); - const _: () = assert!($size == $optioned_size || size_of::<$ty>() < size_of::>()); + const _: () = assert!( + $size == $optioned_size || + size_of::<$ty>() < size_of::>() + ); }; } From 3338593afd6a010a2ce6799d3bf4bf4c2a252950 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 15:41:38 +0000 Subject: [PATCH 20/31] Only check relative sizes on platform specific types --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 69 +++++++++---------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 7f159887ba1d4..9eed2ad361ce3 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -22,54 +22,49 @@ struct NoNiche(UnsafeCell); struct Size; -// Overwriting the runtime assertion and making it a compile-time assertion -macro_rules! assert_size_eq { - ($ty:ty, $size:expr) => { +macro_rules! check_sizes { + (check_one_specific_size: $ty:ty, $size:expr) => { const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; }; ($ty:ty, $size:expr, $optioned_size:expr) => { - assert_size_eq!($ty, $size); - assert_size_eq!(Option<$ty>, $optioned_size); - const _: () = assert!( - $size == $optioned_size || - size_of::<$ty>() < size_of::>() - ); + check_sizes!(check_one_specific_size: $ty, $size); + check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size); + check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty); + }; + ($ty:ty) => { + check_sizes!(check_no_niche_opt: true, $ty); + }; + (check_no_niche_opt: $no_niche_opt:expr, $ty:ty) => { + const _: () = if $no_niche_opt { assert!(size_of::<$ty>() < size_of::>()); }; }; } const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); -assert_size_eq!(Wrapper, 4, 8); -assert_size_eq!(Wrapper, 4, 4); // (✓ niche opt) -assert_size_eq!(Transparent, 4, 8); -assert_size_eq!(Transparent, 4, 4); // (✓ niche opt) -assert_size_eq!(NoNiche, 4, 8); -assert_size_eq!(NoNiche, 4, 8); - -assert_size_eq!(UnsafeCell, 4, 8); -assert_size_eq!(UnsafeCell, 4, 8); - -assert_size_eq!(UnsafeCell<&()> , PTR_SIZE, PTR_SIZE * 2); -assert_size_eq!( Cell<&()> , PTR_SIZE, PTR_SIZE * 2); -assert_size_eq!( RefCell<&()> , PTR_SIZE * 2, PTR_SIZE * 3); -assert_size_eq!( - RwLock<&()>, - if cfg!(target_pointer_width = "32") { 16 } else { 24 }, - if cfg!(target_pointer_width = "32") { 20 } else { 32 } -); -assert_size_eq!( - Mutex<&()> , - if cfg!(target_pointer_width = "32") { 12 } else { 16 }, - if cfg!(target_pointer_width = "32") { 16 } else { 24 } -); - -assert_size_eq!(UnsafeCell<&[i32]> , PTR_SIZE * 2, PTR_SIZE * 3); -assert_size_eq!(UnsafeCell<(&(), &())> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(Wrapper, 4, 8); +check_sizes!(Wrapper, 4, 4); // (✓ niche opt) +check_sizes!(Transparent, 4, 8); +check_sizes!(Transparent, 4, 4); // (✓ niche opt) +check_sizes!(NoNiche, 4, 8); +check_sizes!(NoNiche, 4, 8); + +check_sizes!(UnsafeCell, 4, 8); +check_sizes!(UnsafeCell, 4, 8); + +check_sizes!(UnsafeCell<&()> , PTR_SIZE, PTR_SIZE * 2); +check_sizes!( Cell<&()> , PTR_SIZE, PTR_SIZE * 2); +check_sizes!( RefCell<&()> , PTR_SIZE * 2, PTR_SIZE * 3); + +check_sizes!(RwLock<&()>); +check_sizes!(Mutex<&()>); + +check_sizes!(UnsafeCell<&[i32]> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(UnsafeCell<(&(), &())> , PTR_SIZE * 2, PTR_SIZE * 3); trait Trait {} -assert_size_eq!(UnsafeCell<&dyn Trait> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(UnsafeCell<&dyn Trait> , PTR_SIZE * 2, PTR_SIZE * 3); #[repr(simd)] pub struct Vec4([T; 4]); -assert_size_eq!(UnsafeCell> , 16, 32); +check_sizes!(UnsafeCell> , 16, 32); From 6c529ded8674b89c46052da92399227c3b764c6a Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Thu, 2 Jun 2022 22:39:47 +0800 Subject: [PATCH 21/31] lower let-else in MIR instead --- compiler/rustc_ast_lowering/src/block.rs | 91 ++++--------------- compiler/rustc_ast_lowering/src/index.rs | 4 +- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_hir/src/hir.rs | 3 +- compiler/rustc_hir/src/intravisit.rs | 19 ++-- compiler/rustc_hir_pretty/src/lib.rs | 22 ++++- .../infer/error_reporting/need_type_info.rs | 7 +- compiler/rustc_lint/src/late.rs | 6 +- compiler/rustc_lint/src/levels.rs | 4 +- compiler/rustc_lint/src/passes.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 2 +- compiler/rustc_middle/src/thir.rs | 3 + compiler/rustc_middle/src/thir/visit.rs | 4 + compiler/rustc_mir_build/src/build/block.rs | 33 +++++-- .../rustc_mir_build/src/build/matches/mod.rs | 77 +++++++++++++++- compiler/rustc_mir_build/src/thir/cx/block.rs | 7 +- .../src/thir/pattern/check_match.rs | 24 +++-- .../src/remove_uninit_drops.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/hir_stats.rs | 4 +- compiler/rustc_passes/src/liveness.rs | 55 +++++++++-- compiler/rustc_privacy/src/lib.rs | 4 +- .../rustc_save_analysis/src/dump_visitor.rs | 14 +-- compiler/rustc_span/src/hygiene.rs | 2 - .../src/traits/error_reporting/suggestions.rs | 4 +- compiler/rustc_typeck/src/check/expr.rs | 21 +---- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 23 ++++- .../rustc_typeck/src/check/gather_locals.rs | 4 +- compiler/rustc_typeck/src/check/region.rs | 14 ++- compiler/rustc_typeck/src/check/writeback.rs | 4 +- compiler/rustc_typeck/src/expr_use_visitor.rs | 24 +++-- ...else-binding-explicit-mut-annotated.stderr | 8 +- src/test/ui/let-else/let-else-check.stderr | 12 +-- .../ui/let-else/let-else-non-diverging.stderr | 18 ++-- .../ui/let-else/let-else-ref-bindings.stderr | 16 +++- .../let-else/let-else-temporary-lifetime.rs | 25 +++++ src/tools/clippy/clippy_lints/src/attrs.rs | 2 +- src/tools/clippy/clippy_lints/src/copies.rs | 6 +- src/tools/clippy/clippy_lints/src/default.rs | 2 +- .../src/default_numeric_fallback.rs | 2 +- src/tools/clippy/clippy_lints/src/entry.rs | 2 +- .../clippy/clippy_lints/src/explicit_write.rs | 2 +- .../clippy/clippy_lints/src/let_if_seq.rs | 2 +- .../clippy/clippy_lints/src/let_underscore.rs | 4 +- .../src/loops/needless_collect.rs | 4 +- .../clippy_lints/src/loops/never_loop.rs | 2 +- .../clippy/clippy_lints/src/loops/utils.rs | 6 +- .../clippy_lints/src/loops/while_let_loop.rs | 2 +- .../src/loops/while_let_on_iterator.rs | 4 +- .../clippy/clippy_lints/src/map_unit_fn.rs | 2 +- .../clippy/clippy_lints/src/matches/mod.rs | 12 ++- .../clippy_lints/src/methods/str_splitn.rs | 2 +- src/tools/clippy/clippy_lints/src/misc.rs | 2 +- .../src/mixed_read_write_in_expression.rs | 4 +- src/tools/clippy/clippy_lints/src/mut_key.rs | 7 +- .../clippy_lints/src/needless_late_init.rs | 4 +- .../clippy/clippy_lints/src/no_effect.rs | 3 +- .../src/only_used_in_recursion.rs | 4 +- .../clippy_lints/src/pattern_type_mismatch.rs | 2 +- .../clippy_lints/src/read_zero_byte_vec.rs | 2 +- .../src/redundant_closure_call.rs | 2 +- src/tools/clippy/clippy_lints/src/returns.rs | 7 +- .../src/slow_vector_initialization.rs | 2 +- src/tools/clippy/clippy_lints/src/swap.rs | 2 +- .../clippy/clippy_lints/src/types/mod.rs | 4 +- .../clippy/clippy_lints/src/uninit_vec.rs | 2 +- .../src/unit_types/let_unit_value.rs | 2 +- .../clippy/clippy_lints/src/utils/author.rs | 2 +- .../clippy_lints/src/vec_init_then_push.rs | 2 +- .../clippy/clippy_utils/src/hir_utils.rs | 8 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- 71 files changed, 421 insertions(+), 264 deletions(-) create mode 100644 src/test/ui/let-else/let-else-temporary-lifetime.rs diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 9444fffc331c7..0ec596e705374 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -1,8 +1,8 @@ use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext}; -use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind}; +use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind}; use rustc_hir as hir; use rustc_session::parse::feature_err; -use rustc_span::{sym, DesugaringKind}; +use rustc_span::sym; use smallvec::SmallVec; @@ -36,21 +36,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match s.kind { StmtKind::Local(ref local) => { let hir_id = self.lower_node_id(s.id); - match &local.kind { - LocalKind::InitElse(init, els) => { - let e = self.lower_let_else(hir_id, local, init, els, tail); - expr = Some(e); - // remaining statements are in let-else expression - break; + let els = if let LocalKind::InitElse(_, els) = &local.kind { + if !self.tcx.features().let_else { + feature_err( + &self.tcx.sess.parse_sess, + sym::let_else, + s.span, + "`let...else` statements are unstable", + ) + .emit(); } - _ => { - let local = self.lower_local(local); - self.alias_attrs(hir_id, local.hir_id); - let kind = hir::StmtKind::Local(local); - let span = self.lower_span(s.span); - stmts.push(hir::Stmt { hir_id, kind, span }); - } - } + Some(self.lower_block(els, false)) + } else { + None + }; + let local = self.lower_local(local); + self.alias_attrs(hir_id, local.hir_id); + let kind = hir::StmtKind::Local(local, els); + let span = self.lower_span(s.span); + stmts.push(hir::Stmt { hir_id, kind, span }); } StmtKind::Item(ref it) => { stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map( @@ -115,59 +119,4 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } } - - fn lower_let_else( - &mut self, - stmt_hir_id: hir::HirId, - local: &Local, - init: &Expr, - els: &Block, - tail: &[Stmt], - ) -> &'hir hir::Expr<'hir> { - let ty = local - .ty - .as_ref() - .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable))); - let span = self.lower_span(local.span); - let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None); - let init = self.lower_expr(init); - let local_hir_id = self.lower_node_id(local.id); - self.lower_attrs(local_hir_id, &local.attrs); - let let_expr = { - let lex = self.arena.alloc(hir::Let { - hir_id: local_hir_id, - pat: self.lower_pat(&local.pat), - ty, - init, - span, - }); - self.arena.alloc(self.expr(span, hir::ExprKind::Let(lex), AttrVec::new())) - }; - let then_expr = { - let (stmts, expr) = self.lower_stmts(tail); - let block = self.block_all(span, stmts, expr); - self.arena.alloc(self.expr_block(block, AttrVec::new())) - }; - let else_expr = { - let block = self.lower_block(els, false); - self.arena.alloc(self.expr_block(block, AttrVec::new())) - }; - self.alias_attrs(let_expr.hir_id, local_hir_id); - self.alias_attrs(else_expr.hir_id, local_hir_id); - let if_expr = self.arena.alloc(hir::Expr { - hir_id: stmt_hir_id, - span, - kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)), - }); - if !self.tcx.features().let_else { - feature_err( - &self.tcx.sess.parse_sess, - sym::let_else, - local.span, - "`let...else` statements are unstable", - ) - .emit(); - } - if_expr - } } diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index ddd54f7c2089d..05210e9b89eac 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -284,10 +284,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_local(&mut self, l: &'hir Local<'hir>) { + fn visit_local(&mut self, l: &'hir Local<'hir>, e: Option<&'hir Block<'hir>>) { self.insert(l.span, l.hir_id, Node::Local(l)); self.with_parent(l.hir_id, |this| { - intravisit::walk_local(this, l); + intravisit::walk_local(this, l, e); }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index fdf60e60914a4..6b420c42d6152 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2147,7 +2147,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs.insert(hir_id.local_id, a); } let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None }; - self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local))) + self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local), None)) } fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 04f585df34cc2..65cb5f77e0629 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1296,7 +1296,8 @@ pub struct Stmt<'hir> { #[derive(Debug, HashStable_Generic)] pub enum StmtKind<'hir> { /// A local (`let`) binding. - Local(&'hir Local<'hir>), + /// FIXME: bundle the last two components into another `struct` + Local(&'hir Local<'hir>, Option<&'hir Block<'hir>>), /// An item binding. Item(ItemId), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 531d9f1404021..3585aba5f3db0 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -310,8 +310,8 @@ pub trait Visitor<'v>: Sized { fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) { walk_foreign_item(self, i) } - fn visit_local(&mut self, l: &'v Local<'v>) { - walk_local(self, l) + fn visit_local(&mut self, l: &'v Local<'v>, els: Option<&'v Block<'v>>) { + walk_local(self, l, els) } fn visit_block(&mut self, b: &'v Block<'v>) { walk_block(self, b) @@ -466,12 +466,19 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) { visitor.visit_expr(&body.value); } -pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) { +pub fn walk_local<'v, V: Visitor<'v>>( + visitor: &mut V, + local: &'v Local<'v>, + els: Option<&'v Block<'v>>, +) { // Intentionally visiting the expr first - the initialization expr // dominates the local's definition. walk_list!(visitor, visit_expr, &local.init); visitor.visit_id(local.hir_id); visitor.visit_pat(&local.pat); + if let Some(els) = els { + visitor.visit_block(els); + } walk_list!(visitor, visit_ty, &local.ty); } @@ -1055,9 +1062,9 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) { pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { visitor.visit_id(statement.hir_id); - match statement.kind { - StmtKind::Local(ref local) => visitor.visit_local(local), - StmtKind::Item(item) => visitor.visit_nested_item(item), + match &statement.kind { + StmtKind::Local(ref local, els) => visitor.visit_local(local, *els), + StmtKind::Item(item) => visitor.visit_nested_item(*item), StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { visitor.visit_expr(expression) } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 50acb0270b0be..7f8601308734f 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -883,7 +883,12 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::SubItem(ii.hir_id())) } - pub fn print_local(&mut self, init: Option<&hir::Expr<'_>>, decl: impl Fn(&mut Self)) { + pub fn print_local( + &mut self, + init: Option<&hir::Expr<'_>>, + els: Option<&hir::Block<'_>>, + decl: impl Fn(&mut Self), + ) { self.space_if_not_bol(); self.ibox(INDENT_UNIT); self.word_nbsp("let"); @@ -897,14 +902,21 @@ impl<'a> State<'a> { self.word_space("="); self.print_expr(init); } + + if let Some(els) = els { + self.nbsp(); + self.word_space("else"); + self.print_block(els); + } + self.end() } pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) { self.maybe_print_comment(st.span.lo()); match st.kind { - hir::StmtKind::Local(loc) => { - self.print_local(loc.init, |this| this.print_local_decl(loc)); + hir::StmtKind::Local(loc, els) => { + self.print_local(loc.init, els, |this| this.print_local_decl(loc)); } hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)), hir::StmtKind::Expr(expr) => { @@ -1404,7 +1416,7 @@ impl<'a> State<'a> { // Print `let _t = $init;`: let temp = Ident::from_str("_t"); - self.print_local(Some(init), |this| this.print_ident(temp)); + self.print_local(Some(init), None, |this| this.print_ident(temp)); self.word(";"); // Print `_t`: @@ -2293,7 +2305,7 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr<'_>) -> bool { /// seen the semicolon, and thus don't need another. fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool { match *stmt { - hir::StmtKind::Local(_) => true, + hir::StmtKind::Local(_, _) => true, hir::StmtKind::Item(_) => false, hir::StmtKind::Expr(e) => expr_requires_semi_to_be_stmt(e), hir::StmtKind::Semi(..) => false, diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 4d29fc469462c..ace30e61769f8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,12 +1,13 @@ use crate::infer::type_variable::TypeVariableOriginKind; use crate::infer::InferCtxt; +use hir::{Block, LocalSource}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; +use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local}; use rustc_middle::hir::nested_filter; use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -952,8 +953,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { self.infcx.tcx.hir() } - fn visit_local(&mut self, local: &'tcx Local<'tcx>) { - intravisit::walk_local(self, local); + fn visit_local(&mut self, local: &'tcx Local<'tcx>, els: Option<&'tcx Block<'tcx>>) { + intravisit::walk_local(self, local, els); if let Some(ty) = self.opt_node_type(local.hir_id) { if self.generic_arg_contains_target(ty.into()) { diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 27f67207209dd..695d89e791202 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -251,10 +251,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas } } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) { self.with_lint_attrs(l.hir_id, |cx| { - lint_callback!(cx, check_local, l); - hir_visit::walk_local(cx, l); + lint_callback!(cx, check_local, l, e); + hir_visit::walk_local(cx, l, e); }) } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 00e96f20d1aaa..43c7ff3c4bb20 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -783,9 +783,9 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { }) } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) { self.with_lint_attrs(l.hir_id, |builder| { - intravisit::walk_local(builder, l); + intravisit::walk_local(builder, l, e); }) } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index b1b4229b1f738..41d8e5cf859dd 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -24,7 +24,7 @@ macro_rules! late_lint_methods { fn check_foreign_item_post(a: &$hir hir::ForeignItem<$hir>); fn check_item(a: &$hir hir::Item<$hir>); fn check_item_post(a: &$hir hir::Item<$hir>); - fn check_local(a: &$hir hir::Local<$hir>); + fn check_local(a: &$hir hir::Local<$hir>, b: Option<&$hir hir::Block<$hir>>); fn check_block(a: &$hir hir::Block<$hir>); fn check_block_post(a: &$hir hir::Block<$hir>); fn check_stmt(a: &$hir hir::Stmt<$hir>); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 3e99ba5742a4b..85fc897c7ff03 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -789,7 +789,7 @@ impl<'hir> Map<'hir> { | Node::ForeignItem(_) | Node::TraitItem(_) | Node::ImplItem(_) - | Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break, + | Node::Stmt(Stmt { kind: StmtKind::Local(_, _), .. }) => break, Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => { return Some(expr); } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3fe6394ad7e9c..3e5f6bb8f0bcf 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -182,6 +182,9 @@ pub enum StmtKind<'tcx> { /// `let pat: ty = ` initializer: Option, + /// `let pat: ty = else { } + else_block: Option, + /// The lint level for this `let` statement. lint_level: LintLevel, }, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index c8d09875c2896..97249fdd17563 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -167,11 +167,15 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm init_scope: _, ref pattern, lint_level: _, + else_block, } => { if let Some(init) = initializer { visitor.visit_expr(&visitor.thir()[*init]); } visitor.visit_pat(pattern); + if let Some(block) = else_block { + visitor.visit_block(block) + } } } } diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index a83328c0cabc6..cb8be51a08562 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -99,6 +99,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref pattern, initializer, lint_level, + else_block, } => { let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild); this.block_context.push(BlockFrame::Statement { ignores_expr_result }); @@ -124,18 +125,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |this| { let scope = (*init_scope, source_info); this.in_scope(scope, *lint_level, |this| { - this.declare_bindings( - visibility_scope, - remainder_span, - pattern, - ArmHasGuard(false), - Some((None, initializer_span)), - ); - this.expr_into_pattern(block, pattern.clone(), init) + if let Some(else_block) = else_block { + this.ast_let_else( + block, + init, + initializer_span, + else_block, + visibility_scope, + remainder_span, + pattern, + ) + } else { + this.declare_bindings( + visibility_scope, + remainder_span, + pattern, + ArmHasGuard(false), + Some((None, initializer_span)), + ); + this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern + } }) - } + }, ) - ); + ) } else { let scope = (*init_scope, source_info); unpack!(this.in_scope(scope, *lint_level, |this| { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 1628f1a4b850b..7067a48b783ec 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1615,7 +1615,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // those N possible outcomes, create a (initially empty) // vector of candidates. Those are the candidates that still // apply if the test has that particular outcome. - debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair); + debug!("test_candidates: test={:?} match_pair={:?}", test, match_pair); let mut target_candidates: Vec>> = vec![]; target_candidates.resize_with(test.targets(), Default::default); @@ -1635,8 +1635,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } // at least the first candidate ought to be tested assert!(total_candidate_count > candidates.len()); - debug!("tested_candidates: {}", total_candidate_count - candidates.len()); - debug!("untested_candidates: {}", candidates.len()); + debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len()); + debug!("test_candidates: untested_candidates: {}", candidates.len()); // HACK(matthewjasper) This is a closure so that we can let the test // create its blocks before the rest of the match. This currently @@ -2274,4 +2274,75 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("declare_binding: vars={:?}", locals); self.var_indices.insert(var_id, locals); } + + pub(crate) fn ast_let_else( + &mut self, + mut block: BasicBlock, + init: &Expr<'tcx>, + initializer_span: Span, + else_block: &Block, + visibility_scope: Option, + remainder_span: Span, + pattern: &Pat<'tcx>, + ) -> BlockAnd<()> { + let scrutinee = unpack!(block = self.lower_scrutinee(block, init, initializer_span)); + let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) }; + let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false); + self.declare_bindings( + visibility_scope, + remainder_span, + pattern, + ArmHasGuard(false), + Some((None, initializer_span)), + ); + let mut candidate = Candidate::new(scrutinee.clone(), pattern, false); + let fake_borrow_temps = self.lower_match_tree( + block, + initializer_span, + pattern.span, + false, + &mut [&mut candidate, &mut wildcard], + ); + // This block is for the matching case + let matching = self.bind_pattern( + self.source_info(pattern.span), + candidate, + None, + &fake_borrow_temps, + initializer_span, + None, + None, + None, + ); + // This block is for the failure case + let failure = self.bind_pattern( + self.source_info(else_block.span), + wildcard, + None, + &fake_borrow_temps, + initializer_span, + None, + None, + None, + ); + // This place is not really used because this destination place + // should never be used to take values at the end of the failure + // block. + let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() }; + let failure_block; + unpack!( + failure_block = self.ast_block( + dummy_place, + failure, + else_block, + self.source_info(else_block.span), + ) + ); + self.cfg.terminate( + failure_block, + self.source_info(else_block.span), + TerminatorKind::Unreachable, + ); + matching.unit() + } } diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 59750d5d0b88e..d77d74e25f6e5 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -48,7 +48,7 @@ impl<'tcx> Cx<'tcx> { .filter_map(|(index, stmt)| { let hir_id = stmt.hir_id; let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id); - match stmt.kind { + match &stmt.kind { hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { let stmt = Stmt { kind: StmtKind::Expr { @@ -66,7 +66,7 @@ impl<'tcx> Cx<'tcx> { // ignore for purposes of the MIR None } - hir::StmtKind::Local(ref local) => { + hir::StmtKind::Local(local, els) => { let remainder_scope = region::Scope { id: block_id, data: region::ScopeData::Remainder(region::FirstStatementIndex::new( @@ -74,6 +74,8 @@ impl<'tcx> Cx<'tcx> { )), }; + let else_block = els.map(|els| self.mirror_block(els)); + let mut pattern = self.pattern_from_hir(local.pat); debug!(?pattern); @@ -110,6 +112,7 @@ impl<'tcx> Cx<'tcx> { }, pattern, initializer: local.init.map(|init| self.mirror_expr(init)), + else_block, lint_level: LintLevel::Explicit(local.hir_id), }, opt_destruction_scope: opt_dxn_ext, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 75fd156ebfdf3..daaabd855c87e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -21,7 +21,7 @@ use rustc_session::lint::builtin::{ }; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span}; +use rustc_span::{BytePos, Span}; pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { let body_id = match def_id.as_local() { @@ -75,8 +75,11 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { } } - fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) { - intravisit::walk_local(self, loc); + fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) { + intravisit::walk_local(self, loc, els); + if let Some(init) = &loc.init && els.is_some() { + self.check_let(&loc.pat, &init, loc.span); + } let (msg, sp) = match loc.source { hir::LocalSource::Normal => ("local binding", Some(loc.span)), @@ -84,7 +87,9 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { hir::LocalSource::AwaitDesugar => ("`await` future binding", None), hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None), }; - self.check_irrefutable(&loc.pat, msg, sp); + if els.is_none() { + self.check_irrefutable(&loc.pat, msg, sp); + } } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { @@ -1125,17 +1130,16 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option) -> L }) if Some(*hir_id) == pat_id => { return LetSource::IfLetGuard; } - hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => { - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(DesugaringKind::LetElse) = expn_data.kind { - return LetSource::LetElse(expn_data.call_site); - } - } _ => {} } let parent_parent = hir.get_parent_node(parent); let parent_parent_node = hir.get(parent_parent); + if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_, Some(_)), span, .. }) = + parent_parent_node + { + return LetSource::LetElse(*span); + } let parent_parent_parent = hir.get_parent_node(parent_parent); let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent); diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index efa45883eab4b..c48aa9a90efbe 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -102,7 +102,7 @@ fn is_needs_drop_and_init<'tcx>( let field_needs_drop_and_init = |(f, f_ty, mpi)| { let child = move_path_children_matching(move_data, mpi, |x| x.is_field_to(f)); let Some(mpi) = child else { - return f_ty.needs_drop(tcx, param_env); + return Ty::needs_drop(f_ty, tcx, param_env); }; is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d0723c68a77e8..f78c0f4f545ff 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2311,7 +2311,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { // When checking statements ignore expressions, they will be checked later. - if let hir::StmtKind::Local(ref l) = stmt.kind { + if let hir::StmtKind::Local(ref l, _) = stmt.kind { self.check_attributes(l.hir_id, stmt.span, Target::Statement, None); } intravisit::walk_stmt(self, stmt) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index a3be827a7ccec..d8e97e5adef2f 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -131,9 +131,9 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_foreign_item(self, i) } - fn visit_local(&mut self, l: &'v hir::Local<'v>) { + fn visit_local(&mut self, l: &'v hir::Local<'v>, e: Option<&'v hir::Block<'v>>) { self.record("Local", Id::Node(l.hir_id), l); - hir_visit::walk_local(self, l) + hir_visit::walk_local(self, l, e) } fn visit_block(&mut self, b: &'v hir::Block<'v>) { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 0070c0699a4aa..f125f107fe2a5 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -278,7 +278,7 @@ impl<'tcx> IrMaps<'tcx> { pats.extend(inner_pat.iter()); } Struct(_, fields, _) => { - let (short, not_short): (Vec<&_>, Vec<&_>) = + let (short, not_short): (Vec<_>, _) = fields.iter().partition(|f| f.is_shorthand); shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id)); pats.extend(not_short.iter().map(|f| f.pat)); @@ -298,7 +298,7 @@ impl<'tcx> IrMaps<'tcx> { } } - return shorthand_field_ids; + shorthand_field_ids } fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) { @@ -366,9 +366,12 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { lsets.warn_about_unused_args(body, entry_ln); } - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) { self.add_from_pat(&local.pat); - intravisit::walk_local(self, local); + if els.is_some() { + self.add_live_node_for_node(local.hir_id, ExprNode(local.span, local.hir_id)); + } + intravisit::walk_local(self, local, els); } fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { @@ -785,7 +788,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_stmt(&mut self, stmt: &hir::Stmt<'_>, succ: LiveNode) -> LiveNode { match stmt.kind { - hir::StmtKind::Local(ref local) => { + hir::StmtKind::Local(ref local, els) => { // Note: we mark the variable as defined regardless of whether // there is an initializer. Initially I had thought to only mark // the live variable as defined if it was initialized, and then we @@ -800,8 +803,40 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // initialization, which is mildly more complex than checking // once at the func header but otherwise equivalent. - let succ = self.propagate_through_opt_expr(local.init, succ); - self.define_bindings_in_pat(&local.pat, succ) + if let Some(els) = els { + // Eventually, `let pat: ty = init else { els };` is mostly equivalent to + // `let (bindings, ...) = match init { pat => (bindings, ...), _ => els };` + // except that extended lifetime applies at the `init` location. + // + // (e) + // | + // v + // (expr) + // / \ + // | | + // v v + // bindings els + // | + // v + // ( succ ) + // + if let Some(init) = local.init { + let else_ln = self.propagate_through_block(els, succ); + let ln = self.live_node(local.hir_id, local.span); + self.init_from_succ(ln, succ); + self.merge_from_succ(ln, else_ln); + let succ = self.propagate_through_expr(init, ln); + self.define_bindings_in_pat(&local.pat, succ) + } else { + span_bug!( + stmt.span, + "variable is uninitialized but an unexpected else branch is found" + ) + } + } else { + let succ = self.propagate_through_opt_expr(local.init, succ); + self.define_bindings_in_pat(&local.pat, succ) + } } hir::StmtKind::Item(..) => succ, hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { @@ -1121,7 +1156,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // (rvalue) || (rvalue) // | || | // v || v - // (write of place) || (place components) + // (write of place) || (place components) // | || | // v || v // (succ) || (succ) @@ -1306,14 +1341,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Checking for error conditions impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> { - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) { self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| { if local.init.is_some() { self.warn_about_dead_assign(spans, hir_id, ln, var); } }); - intravisit::walk_local(self, local); + intravisit::walk_local(self, local, els); } fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 5560d44aa0d52..05345f73ef65f 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1275,7 +1275,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { intravisit::walk_pat(self, pattern); } - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) { if let Some(init) = local.init { if self.check_expr_pat_type(init.hir_id, init.span) { // Do not report duplicate errors for `let x = y`. @@ -1283,7 +1283,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { } } - intravisit::walk_local(self, local); + intravisit::walk_local(self, local, els); } // Check types in item interfaces. diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 6eb2f2d929d57..2aaacad4ba4e2 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -82,14 +82,7 @@ impl<'tcx> DumpVisitor<'tcx> { pub fn new(save_ctxt: SaveContext<'tcx>) -> DumpVisitor<'tcx> { let span_utils = SpanUtils::new(&save_ctxt.tcx.sess); let dumper = Dumper::new(save_ctxt.config.clone()); - DumpVisitor { - tcx: save_ctxt.tcx, - save_ctxt, - dumper, - span: span_utils, - // mac_defs: FxHashSet::default(), - // macro_calls: FxHashSet::default(), - } + DumpVisitor { tcx: save_ctxt.tcx, save_ctxt, dumper, span: span_utils } } pub fn analysis(&self) -> &rls_data::Analysis { @@ -1421,13 +1414,14 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { intravisit::walk_stmt(self, s) } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) { self.process_macro_use(l.span); self.process_var_decl(&l.pat); - // Just walk the initializer and type (don't want to walk the pattern again). + // Just walk the initializer, the else branch and type (don't want to walk the pattern again). walk_list!(self, visit_ty, &l.ty); walk_list!(self, visit_expr, &l.init); + walk_list!(self, visit_block, e); } fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 3df4dfb74b319..29879c48b04ae 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1141,7 +1141,6 @@ pub enum DesugaringKind { Async, Await, ForLoop, - LetElse, WhileLoop, } @@ -1157,7 +1156,6 @@ impl DesugaringKind { DesugaringKind::YeetExpr => "`do yeet` expression", DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::ForLoop => "`for` loop", - DesugaringKind::LetElse => "`let...else`", DesugaringKind::WhileLoop => "`while` loop", } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 33585de600130..adbe71b83ed92 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -734,7 +734,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?); let parent_node = hir.get_parent_node(hir_id); match hir.find(parent_node) { - Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => { + Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local, _), .. })) => { get_name(err, &local.pat.kind) } // Different to previous arm because one is `&hir::Local` and the other @@ -1311,7 +1311,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { visitor.visit_body(&body); let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap(); - let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id) else { return false; }; + let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; }; let ret_types = visitor .returns diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 58c01a34cad51..5ae6ed4f72f3f 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -997,26 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce(self, &self.misc(sp), then_expr, then_ty); if let Some(else_expr) = opt_else_expr { - let else_ty = if sp.desugaring_kind() == Some(DesugaringKind::LetElse) { - // todo introduce `check_expr_with_expectation(.., Expectation::LetElse)` - // for errors that point to the offending expression rather than the entire block. - // We could use `check_expr_eq_type(.., tcx.types.never)`, but then there is no - // way to detect that the expected type originated from let-else and provide - // a customized error. - let else_ty = self.check_expr(else_expr); - let cause = self.cause(else_expr.span, ObligationCauseCode::LetElse); - - if let Some(mut err) = - self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) - { - err.emit(); - self.tcx.ty_error() - } else { - else_ty - } - } else { - self.check_expr_with_expectation(else_expr, expected) - }; + let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index a7c7089234aa9..fcd610e677a75 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1218,8 +1218,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Type check a `let` statement. - pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { + pub fn check_decl_local( + &self, + local: &'tcx hir::Local<'tcx>, + els: Option<&'tcx hir::Block<'tcx>>, + ) { self.check_decl(local.into()); + if let Some(blk) = els { + let previous_diverges = self.diverges.get(); + let else_ty = self.check_block_with_expected(blk, NoExpectation); + let cause = self.cause(blk.span, ObligationCauseCode::LetElse); + if let Some(mut err) = + self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) + { + err.emit(); + } + self.diverges.set(previous_diverges); + } } pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) { @@ -1236,8 +1251,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let old_has_errors = self.has_errors.replace(false); match stmt.kind { - hir::StmtKind::Local(ref l) => { - self.check_decl_local(&l); + hir::StmtKind::Local(l, e) => { + self.check_decl_local(l, e); } // Ignore for now. hir::StmtKind::Item(_) => {} @@ -1396,7 +1411,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: hir::LocalSource::AssignDesugar(_), .. - }), + }, _), .. }, hir::Stmt { diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index 576dc6f127cbd..956f315f68426 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -99,9 +99,9 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // Add explicitly-declared locals. - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) { self.declare(local.into()); - intravisit::walk_local(self, local); + intravisit::walk_local(self, local, els) } fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) { diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs index 9f1368a3e0777..54fb17734f4de 100644 --- a/compiler/rustc_typeck/src/check/region.rs +++ b/compiler/rustc_typeck/src/check/region.rs @@ -460,6 +460,7 @@ fn resolve_local<'tcx>( visitor: &mut RegionResolutionVisitor<'tcx>, pat: Option<&'tcx hir::Pat<'tcx>>, init: Option<&'tcx hir::Expr<'tcx>>, + els: Option<&'tcx hir::Block<'tcx>>, ) { debug!("resolve_local(pat={:?}, init={:?})", pat, init); @@ -537,13 +538,18 @@ fn resolve_local<'tcx>( } } - // Make sure we visit the initializer first, so expr_and_pat_count remains correct + // Make sure we visit the initializer first, so expr_and_pat_count remains correct. + // The correct order, as shared between generator_interior, drop_ranges and intravisitor, + // is to walk initializer, followed by pattern bindings, finally followed by the `else` block. if let Some(expr) = init { visitor.visit_expr(expr); } if let Some(pat) = pat { visitor.visit_pat(pat); } + if let Some(els) = els { + visitor.visit_block(els); + } /// Returns `true` if `pat` match the `P&` non-terminal. /// @@ -764,7 +770,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { // (i.e., `'static`), which means that after `g` returns, it drops, // and all the associated destruction scope rules apply. self.cx.var_parent = None; - resolve_local(self, None, Some(&body.value)); + resolve_local(self, None, Some(&body.value), None); } if body.generator_kind.is_some() { @@ -790,8 +796,8 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { resolve_expr(self, ex); } - fn visit_local(&mut self, l: &'tcx Local<'tcx>) { - resolve_local(self, Some(&l.pat), l.init); + fn visit_local(&mut self, l: &'tcx Local<'tcx>, e: Option<&'tcx Block<'tcx>>) { + resolve_local(self, Some(&l.pat), l.init, e) } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 41d241f84acea..b61ec13e388ac 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -321,8 +321,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { intravisit::walk_pat(self, p); } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { - intravisit::walk_local(self, l); + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) { + intravisit::walk_local(self, l, e); let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty; let var_ty = self.resolve(var_ty, &l.span); self.write_ty_to_typeck_results(l.hir_id, var_ty); diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 920e3d578c812..12581286941f3 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -252,7 +252,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } hir::ExprKind::Let(hir::Let { pat, init, .. }) => { - self.walk_local(init, pat, |t| t.borrow_expr(init, ty::ImmBorrow)); + self.walk_local(init, pat, None, |t| t.borrow_expr(init, ty::ImmBorrow)) } hir::ExprKind::Match(ref discr, arms, _) => { @@ -453,11 +453,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) { match stmt.kind { - hir::StmtKind::Local(hir::Local { pat, init: Some(expr), .. }) => { - self.walk_local(expr, pat, |_| {}); + hir::StmtKind::Local(hir::Local { pat, init: Some(expr), .. }, els) => { + self.walk_local(expr, pat, els, |_| {}) } - hir::StmtKind::Local(_) => {} + hir::StmtKind::Local(_, _) => {} hir::StmtKind::Item(_) => { // We don't visit nested items in this visitor, @@ -470,13 +470,23 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } - fn walk_local(&mut self, expr: &hir::Expr<'_>, pat: &hir::Pat<'_>, mut f: F) - where + fn walk_local( + &mut self, + expr: &hir::Expr<'_>, + pat: &hir::Pat<'_>, + els: Option<&hir::Block<'_>>, + mut f: F, + ) where F: FnMut(&mut Self), { self.walk_expr(expr); let expr_place = return_if_err!(self.mc.cat_expr(expr)); f(self); + if let Some(els) = els { + // borrowing because we need to test the descriminant + self.borrow_expr(expr, ImmBorrow); + self.walk_block(els) + } self.walk_irrefutable_pat(&expr_place, &pat); } @@ -667,7 +677,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self; return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| { if let PatKind::Binding(_, canonical_id, ..) = pat.kind { - debug!("walk_pat: binding place={:?} pat={:?}", place, pat,); + debug!("walk_pat: binding place={:?} pat={:?}", place, pat); if let Some(bm) = mc.typeck_results.extract_binding_mode(tcx.sess, pat.hir_id, pat.span) { diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr index fdec7e7f6a753..065787cab08ff 100644 --- a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr +++ b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/let-else-binding-explicit-mut-annotated.rs:9:37 | LL | let Some(n): &mut Option = &&Some(5i32) else { return }; - | ^^^^^^^^^^^^ types differ in mutability + | ---------------- ^^^^^^^^^^^^ types differ in mutability + | | + | expected due to this | = note: expected mutable reference `&mut Option` found reference `&&Option` @@ -11,7 +13,9 @@ error[E0308]: mismatched types --> $DIR/let-else-binding-explicit-mut-annotated.rs:13:37 | LL | let Some(n): &mut Option = &&mut Some(5i32) else { return }; - | ^^^^^^^^^^^^^^^^ types differ in mutability + | ---------------- ^^^^^^^^^^^^^^^^ types differ in mutability + | | + | expected due to this | = note: expected mutable reference `&mut Option` found reference `&&mut Option` diff --git a/src/test/ui/let-else/let-else-check.stderr b/src/test/ui/let-else/let-else-check.stderr index b3da412ec280e..3d647a4c05d86 100644 --- a/src/test/ui/let-else/let-else-check.stderr +++ b/src/test/ui/let-else/let-else-check.stderr @@ -1,8 +1,8 @@ error: unused variable: `x` - --> $DIR/let-else-check.rs:18:9 + --> $DIR/let-else-check.rs:14:13 | -LL | let x = 1; - | ^ help: if this is intentional, prefix it with an underscore: `_x` +LL | let x = 1; + | ^ help: if this is intentional, prefix it with an underscore: `_x` | note: the lint level is defined here --> $DIR/let-else-check.rs:3:9 @@ -11,10 +11,10 @@ LL | #![deny(unused_variables)] | ^^^^^^^^^^^^^^^^ error: unused variable: `x` - --> $DIR/let-else-check.rs:14:13 + --> $DIR/let-else-check.rs:18:9 | -LL | let x = 1; - | ^ help: if this is intentional, prefix it with an underscore: `_x` +LL | let x = 1; + | ^ help: if this is intentional, prefix it with an underscore: `_x` error: aborting due to 2 previous errors diff --git a/src/test/ui/let-else/let-else-non-diverging.stderr b/src/test/ui/let-else/let-else-non-diverging.stderr index b961b16b6f6ef..05e45f689890d 100644 --- a/src/test/ui/let-else/let-else-non-diverging.stderr +++ b/src/test/ui/let-else/let-else-non-diverging.stderr @@ -1,8 +1,11 @@ error[E0308]: `else` clause of `let...else` does not diverge - --> $DIR/let-else-non-diverging.rs:12:32 + --> $DIR/let-else-non-diverging.rs:4:32 | -LL | let Some(x) = Some(1) else { Some(2) }; - | ^^^^^^^^^^^ expected `!`, found enum `Option` +LL | let Some(x) = Some(1) else { + | ________________________________^ +LL | | Some(2) +LL | | }; + | |_____^ expected `!`, found enum `Option` | = note: expected type `!` found enum `Option<{integer}>` @@ -26,13 +29,10 @@ LL | | }; = help: ...or use `match` instead of `let...else` error[E0308]: `else` clause of `let...else` does not diverge - --> $DIR/let-else-non-diverging.rs:4:32 + --> $DIR/let-else-non-diverging.rs:12:32 | -LL | let Some(x) = Some(1) else { - | ________________________________^ -LL | | Some(2) -LL | | }; - | |_____^ expected `!`, found enum `Option` +LL | let Some(x) = Some(1) else { Some(2) }; + | ^^^^^^^^^^^ expected `!`, found enum `Option` | = note: expected type `!` found enum `Option<{integer}>` diff --git a/src/test/ui/let-else/let-else-ref-bindings.stderr b/src/test/ui/let-else/let-else-ref-bindings.stderr index 650f4ec5e779f..56b9e073330a6 100644 --- a/src/test/ui/let-else/let-else-ref-bindings.stderr +++ b/src/test/ui/let-else/let-else-ref-bindings.stderr @@ -20,7 +20,9 @@ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:24:34 | LL | let Some(a): Option<&[u8]> = some else { return }; - | ^^^^ expected `&[u8]`, found struct `Vec` + | ------------- ^^^^ expected `&[u8]`, found struct `Vec` + | | + | expected due to this | = note: expected enum `Option<&[u8]>` found enum `Option>` @@ -29,7 +31,9 @@ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:27:34 | LL | let Some(a): Option<&[u8]> = &some else { return }; - | ^^^^^ expected enum `Option`, found `&Option>` + | ------------- ^^^^^ expected enum `Option`, found `&Option>` + | | + | expected due to this | = note: expected enum `Option<&[u8]>` found reference `&Option>` @@ -56,7 +60,9 @@ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:52:38 | LL | let Some(a): Option<&mut [u8]> = some else { return }; - | ^^^^ expected `&mut [u8]`, found struct `Vec` + | ----------------- ^^^^ expected `&mut [u8]`, found struct `Vec` + | | + | expected due to this | = note: expected enum `Option<&mut [u8]>` found enum `Option>` @@ -65,7 +71,9 @@ error[E0308]: mismatched types --> $DIR/let-else-ref-bindings.rs:55:38 | LL | let Some(a): Option<&mut [u8]> = &mut some else { return }; - | ^^^^^^^^^ expected enum `Option`, found mutable reference + | ----------------- ^^^^^^^^^ expected enum `Option`, found mutable reference + | | + | expected due to this | = note: expected enum `Option<&mut [u8]>` found mutable reference `&mut Option>` diff --git a/src/test/ui/let-else/let-else-temporary-lifetime.rs b/src/test/ui/let-else/let-else-temporary-lifetime.rs new file mode 100644 index 0000000000000..624c2ea37a70b --- /dev/null +++ b/src/test/ui/let-else/let-else-temporary-lifetime.rs @@ -0,0 +1,25 @@ +// run-pass +#![feature(let_else)] + +use std::sync::atomic::{AtomicU8, Ordering}; + +static TRACKER: AtomicU8 = AtomicU8::new(0); + +#[derive(Default)] +struct Droppy { + inner: u32, +} + +impl Drop for Droppy { + fn drop(&mut self) { + TRACKER.store(1, Ordering::Release); + println!("I've been dropped"); + } +} + +fn main() { + assert_eq!(TRACKER.load(Ordering::Acquire), 0); + let 0 = Droppy::default().inner else { return }; + assert_eq!(TRACKER.load(Ordering::Acquire), 1); + println!("Should have dropped 👆"); +} diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 4bcbeacf9feb5..93ce3b30fb1d3 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -505,7 +505,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_ .as_ref() .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)), |stmt| match &stmt.kind { - StmtKind::Local(_) => true, + StmtKind::Local(_, _) => true, StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), StmtKind::Item(_) => false, }, diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 1deff9684a140..0b9fdb891b15c 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -324,7 +324,7 @@ impl BlockEq { /// If the statement is a local, checks if the bound names match the expected list of names. fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { - if let StmtKind::Local(l) = s.kind { + if let StmtKind::Local(l, _) = s.kind { let mut i = 0usize; let mut res = true; l.pat.each_binding_or_first(&mut |_, _, _, name| { @@ -349,7 +349,7 @@ fn eq_stmts( eq: &mut HirEqInterExpr<'_, '_, '_>, moved_bindings: &mut Vec<(HirId, Symbol)>, ) -> bool { - (if let StmtKind::Local(l) = stmt.kind { + (if let StmtKind::Local(l, _) = stmt.kind { let old_count = moved_bindings.len(); l.pat.each_binding_or_first(&mut |_, id, _, name| { moved_bindings.push((id, name.name)); @@ -435,7 +435,7 @@ fn scan_block_for_eq(cx: &LateContext<'_>, _conds: &[&Expr<'_>], block: &Block<' // Clear out all locals seen at the end so far. None of them can be moved. let stmts = &blocks[0].stmts; for stmt in &stmts[stmts.len() - init..=stmts.len() - offset] { - if let StmtKind::Local(l) = stmt.kind { + if let StmtKind::Local(l, _) = stmt.kind { l.pat.each_binding_or_first(&mut |_, id, _, _| { eq.locals.remove(&id); }); diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index d99a1aa296946..7fe3443858a01 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // checked and the name of the bound variable let (local, variant, binding_name, binding_type, span) = if_chain! { // only take `let ...` statements - if let StmtKind::Local(local) = stmt.kind; + if let StmtKind::Local(local, _) = stmt.kind; if let Some(expr) = local.init; if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); if !expr.span.from_expansion(); diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index fb418a3251f58..0f374d12a84f6 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -192,7 +192,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { match stmt.kind { - StmtKind::Local(local) => { + StmtKind::Local(local, _) => { if local.ty.is_some() { self.ty_bounds.push(TyBound::Any); } else { diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 27743a0ebec7e..e0986b710c508 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -386,7 +386,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { } }, StmtKind::Expr(e) => self.visit_expr(e), - StmtKind::Local(l) => { + StmtKind::Local(l, _) => { self.visit_pat(l.pat); if let Some(e) = l.init { self.allow_insert_closure &= !self.in_tail_pos; diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index 5bf4313b41a49..bd1ac3371b063 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -116,7 +116,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>) if_chain! { if let ExprKind::Block(block, _label @ None) = kind; if let Block { - stmts: [Stmt { kind: StmtKind::Local(local), .. }], + stmts: [Stmt { kind: StmtKind::Local(local, _), .. }], expr: Some(expr_end_of_block), rules: BlockCheckMode::DefaultBlock, .. diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs index 56bbbbbc819e5..5dcb86feb7622 100644 --- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs +++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { while let Some(stmt) = it.next() { if_chain! { if let Some(expr) = it.peek(); - if let hir::StmtKind::Local(local) = stmt.kind; + if let hir::StmtKind::Local(local, _) = stmt.kind; if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind; if let hir::StmtKind::Expr(if_) = expr.kind; if let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind; diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 176787497ebf2..a37dfb7b7151d 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{is_must_use_ty, match_type}; use clippy_utils::{is_must_use_func_call, paths}; use if_chain::if_chain; -use rustc_hir::{Local, PatKind}; +use rustc_hir::{Block, Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; @@ -109,7 +109,7 @@ const SYNC_GUARD_PATHS: [&[&str]; 6] = [ ]; impl<'tcx> LateLintPass<'tcx> for LetUnderscore { - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>, _: Option<&Block<'_>>) { if in_external_macro(cx.tcx.sess, local.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs index ddaffc751880d..ba0f01d9ed25b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs @@ -76,7 +76,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo if let ExprKind::Block(block, _) = expr.kind { for stmt in block.stmts { if_chain! { - if let StmtKind::Local(local) = stmt.kind; + if let StmtKind::Local(local, _) = stmt.kind; if let PatKind::Binding(_, id, ..) = local.pat.kind; if let Some(init_expr) = local.init; if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind; @@ -276,7 +276,7 @@ fn get_expr_and_hir_id_from_stmt<'v>(stmt: &'v Stmt<'v>) -> Option<(&'v Expr<'v> match stmt.kind { StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some((expr, None)), StmtKind::Item(..) => None, - StmtKind::Local(Local { init, pat, .. }) => { + StmtKind::Local(Local { init, pat, .. }, _) => { if let PatKind::Binding(_, hir_id, ..) = pat.kind { init.map(|init_expr| (init_expr, Some(hir_id))) } else { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 32de20f6531fe..c60d551806067 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -104,7 +104,7 @@ fn never_loop_expr_seq<'a, T: Iterator>>(es: &mut T, main_lo fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> { match stmt.kind { StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some(e), - StmtKind::Local(local) => local.init, + StmtKind::Local(local, _) => local.init, StmtKind::Item(..) => None, } } diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index 4801a84eb92ce..661af8fe642f9 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, Visitor}; -use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, Pat, PatKind, Stmt}; +use rustc_hir::{BinOpKind, Block, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, Pat, PatKind, Stmt}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; @@ -148,7 +148,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_local(&mut self, l: &'tcx Local<'_>) { + fn visit_local(&mut self, l: &'tcx Local<'_>, e: Option<&'tcx Block<'_>>) { // Look for declarations of the variable if_chain! { if l.pat.hir_id == self.var_id; @@ -166,7 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } } - walk_local(self, l); + walk_local(self, l, e); } fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs index 45af6be2653f3..8c3524942520b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs @@ -11,7 +11,7 @@ use rustc_lint::LateContext; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) { ([stmt, stmts @ ..], expr) => { - if let StmtKind::Local(&Local { init: Some(e), .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind { + if let StmtKind::Local(&Local { init: Some(e), .. }, None) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind { (e, !stmts.is_empty() || expr.is_some()) } else { return; diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index a57159750664f..1abdfaac7ec64 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -8,7 +8,7 @@ use clippy_utils::{ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp}; +use rustc_hir::{def::Res, Block, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_span::{symbol::sym, Symbol}; @@ -283,7 +283,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & used_after: bool, } impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> { - fn visit_local(&mut self, l: &'tcx Local<'_>) { + fn visit_local(&mut self, l: &'tcx Local<'_>, _: Option<&'tcx Block<'_>>) { if !self.after_loop { l.pat.each_binding_or_first(&mut |_, id, _, _| { if id == self.local_id { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 663246b4c8622..3bfe5428133fc 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -144,7 +144,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> // If block only contains statements, // reduce `{ X; }` to `X` or `X;` match inner_stmt.kind { - hir::StmtKind::Local(local) => Some(local.span), + hir::StmtKind::Local(local, _) => Some(local.span), hir::StmtKind::Expr(e) => Some(e.span), hir::StmtKind::Semi(..) => Some(inner_stmt.span), hir::StmtKind::Item(..) => None, diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index b2a873ef5823c..cc8674a200652 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -1,6 +1,6 @@ use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context}; use clippy_utils::{higher, in_constant, meets_msrv, msrvs}; -use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; +use rustc_hir::{Arm, Block, Expr, ExprKind, Local, MatchSource, Pat}; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -1040,8 +1040,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } } - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { - self.infallible_destructuring_match_linted |= infallible_destructuring_match::check(cx, local); + fn check_local( + &mut self, + cx: &LateContext<'tcx>, + local: &'tcx Local<'_>, + els: Option<&'tcx Block<'_>>, + ) { + self.infallible_destructuring_match_linted |= + els.is_none() && infallible_destructuring_match::check(cx, local); } fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 4ac738272d085..80dbd14b2c56a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -220,7 +220,7 @@ fn indirect_usage<'tcx>( init: Some(init_expr), hir_id: local_hir_id, .. - }) = stmt.kind + }, _) = stmt.kind { let mut path_to_binding = None; expr_visitor(cx, |expr| { diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index be7df08d89f05..2ad7ac60b9250 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if_chain! { if !in_external_macro(cx.tcx.sess, stmt.span); - if let StmtKind::Local(local) = stmt.kind; + if let StmtKind::Local(local, _) = stmt.kind; if let PatKind::Binding(an, .., name, None) = local.pat.kind; if let Some(init) = local.init; if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut; diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index a2419c277e9c2..de993c3c0a47a 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { match stmt.kind { - StmtKind::Local(local) => { + StmtKind::Local(local, _) => { if let Local { init: Some(e), .. } = local { DivergenceVisitor { cx }.visit_expr(e); } @@ -273,7 +273,7 @@ fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) - StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr), // If the declaration is of a local variable, check its initializer // expression if it has one. Otherwise, keep going. - StmtKind::Local(local) => local + StmtKind::Local(local, _) => local .init .as_ref() .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)), diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 4db103bbc1305..251181165b022 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -101,7 +101,12 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { } } - fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) { + fn check_local( + &mut self, + cx: &LateContext<'_>, + local: &hir::Local<'_>, + _: Option<&hir::Block<'_>>, + ) { if let hir::PatKind::Wild = local.pat.kind { return; } diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index ff2999b1f4a51..fa1c09d8f9032 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -92,7 +92,7 @@ fn contains_let(cond: &Expr<'_>) -> bool { } fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { - let StmtKind::Local(local) = stmt.kind else { return false }; + let StmtKind::Local(local, _) = stmt.kind else { return false }; !local.pat.walk_short(|pat| { if let PatKind::Binding(.., None) = pat.kind { !needs_ordered_drop(cx, cx.typeck_results().pat_ty(pat)) @@ -367,7 +367,7 @@ fn check<'tcx>( } impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>, _: Option<&'tcx Block<'tcx>>) { let mut parents = cx.tcx.hir().parent_iter(local.hir_id); if_chain! { if let Local { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 6598413c77ecc..105e145ac3069 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -88,10 +88,11 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect"); return true; } - } else if let StmtKind::Local(local) = stmt.kind { + } else if let StmtKind::Local(local, els) = stmt.kind { if_chain! { if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id); if let Some(init) = local.init; + if els.is_none(); if !local.pat.span.from_expansion(); if has_no_effect(cx, init); if let PatKind::Binding(_, _, ident, _) = local.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index 677ac998b5682..c7f8f2f8d7045 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -261,13 +261,13 @@ impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> { match s.kind { StmtKind::Local(Local { pat, init: Some(init), .. - }) => { + }, _) => { self.visit_pat_expr(pat, init, false); }, StmtKind::Item(_) | StmtKind::Expr(_) | StmtKind::Semi(_) => { walk_stmt(self, s); }, - StmtKind::Local(_) => {}, + StmtKind::Local(_, _) => {}, } self.ret_vars.clear(); } diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index a4d265111f9ae..83e18e207117a 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -83,7 +83,7 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]); impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let StmtKind::Local(local) = stmt.kind { + if let StmtKind::Local(local, _) = stmt.kind { if in_external_macro(cx.sess(), local.pat.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index 9538a8104739e..8316efad1ffed 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { for (idx, stmt) in block.stmts.iter().enumerate() { if !stmt.span.from_expansion() // matches `let v = Vec::new();` - && let StmtKind::Local(local) = stmt.kind + && let StmtKind::Local(local, _) = stmt.kind && let Local { pat, init: Some(init), .. } = local && let PatKind::Binding(_, _, ident, _) = pat.kind && let Some(vec_init_kind) = get_vec_init_kind(cx, init) diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 65ed798867d19..48bf14d511c71 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { for w in block.stmts.windows(2) { if_chain! { - if let hir::StmtKind::Local(local) = w[0].kind; + if let hir::StmtKind::Local(local, _) = w[0].kind; if let Option::Some(t) = local.init; if let hir::ExprKind::Closure { .. } = t.kind; if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 5ae04947b82d0..b2ec32abb442a 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -10,7 +10,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Span; use rustc_span::sym; @@ -83,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { if_chain! { if let Some(retexpr) = block.expr; if let Some(stmt) = block.stmts.iter().last(); - if let StmtKind::Local(local) = &stmt.kind; + if let StmtKind::Local(local, _) = &stmt.kind; if local.ty.is_none(); if cx.tcx.hir().attrs(local.hir_id).is_empty(); if let Some(initexpr) = &local.init; @@ -203,9 +202,7 @@ fn check_final_expr<'tcx>( check_block_return(cx, ifblock); } if let Some(else_clause) = else_clause_opt { - if expr.span.desugaring_kind() != Some(DesugaringKind::LetElse) { - check_final_expr(cx, else_clause, None, RetReplacement::Empty); - } + check_final_expr(cx, else_clause, None, RetReplacement::Empty); } }, // a match expr, check all arms diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 2c8aa17e80dbd..3d7ef747a86c8 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` if_chain! { - if let StmtKind::Local(local) = stmt.kind; + if let StmtKind::Local(local, _) = stmt.kind; if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind; if let Some(init) = local.init; if let Some(len_arg) = Self::is_vec_with_capacity(cx, init); diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 1885f3ca414df..a8c96543c7c6e 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -141,7 +141,7 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { for w in block.stmts.windows(3) { if_chain! { // let t = foo(); - if let StmtKind::Local(tmp) = w[0].kind; + if let StmtKind::Local(tmp, _) = w[0].kind; if let Some(tmp_init) = tmp.init; if let PatKind::Binding(.., ident, None) = tmp.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 353a6f6b899ea..2a7d5f2623e2c 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -12,7 +12,7 @@ mod vec_box; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Body, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem, + Block, Body, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem, TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -406,7 +406,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { } } - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>, _: Option<&Block<'_>>) { if let Some(ty) = local.ty { self.check_ty( cx, diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs index 9f4c5555f11b7..eab3b9b7b01c2 100644 --- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs +++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs @@ -155,7 +155,7 @@ impl<'tcx> VecLocation<'tcx> { /// or `self` expression for `Vec::reserve()`. fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option> { match stmt.kind { - StmtKind::Local(local) => { + StmtKind::Local(local, _) => { if_chain! { if let Some(init_expr) = local.init; if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index cf509455aad0a..80e7b8de392c7 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitable, TypeSuperVisitable, TypeVisitor} use super::LET_UNIT_VALUE; pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) { - if let StmtKind::Local(local) = stmt.kind + if let StmtKind::Local(local, _) = stmt.kind && let Some(init) = local.init && !local.pat.span.from_expansion() && !in_external_macro(cx.sess(), stmt.span) diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 2c8820eb7e1a1..99ac84fbaabae 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -685,7 +685,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } match stmt.value.kind { - StmtKind::Local(local) => { + StmtKind::Local(local, _) => { bind!(self, local); kind!("Local({local})"); self.option(field!(local.init), "init", |init| { diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index 35db45e2b0c99..c71bacfa29a70 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -155,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { self.searcher = None; } - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>, _: Option<&'tcx Block<'tcx>>) { if let Some(init_expr) = local.init && let PatKind::Binding(BindingAnnotation::Mutable, id, name, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 793e3cc58c21d..0b5325adfed20 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -102,7 +102,7 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> { impl HirEqInterExpr<'_, '_, '_> { pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool { match (&left.kind, &right.kind) { - (&StmtKind::Local(l), &StmtKind::Local(r)) => { + (&StmtKind::Local(l, le), &StmtKind::Local(r, re)) => { // This additional check ensures that the type of the locals are equivalent even if the init // expression or type have some inferred parts. if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results { @@ -117,6 +117,7 @@ impl HirEqInterExpr<'_, '_, '_> { // these only get added if the init and type is equal. both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) + && both(&le, &re, |l, r| self.eq_block(l, r)) && self.eq_pat(l.pat, r.pat) }, (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r), @@ -921,11 +922,14 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { std::mem::discriminant(&b.kind).hash(&mut self.s); match &b.kind { - StmtKind::Local(local) => { + StmtKind::Local(local, els) => { self.hash_pat(local.pat); if let Some(init) = local.init { self.hash_expr(init); } + if let Some(els) = els { + self.hash_block(els); + } }, StmtKind::Item(..) => {}, StmtKind::Expr(expr) | StmtKind::Semi(expr) => { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 1b32f0aaeb8df..ac6490cfd2c72 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1826,7 +1826,7 @@ pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { .. }, .. - }), + }, _), .. }), _ From 1cd30e7b32df602cf455d34ff8042079b8e082a3 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Tue, 5 Jul 2022 23:31:18 +0200 Subject: [PATCH 22/31] move else block into the `Local` struct --- compiler/rustc_ast_lowering/src/block.rs | 18 ++++++++++++++++-- compiler/rustc_ast_lowering/src/index.rs | 4 ++-- compiler/rustc_ast_lowering/src/lib.rs | 12 ++++++++++-- compiler/rustc_hir/src/hir.rs | 4 +++- compiler/rustc_hir/src/intravisit.rs | 14 +++++--------- compiler/rustc_hir_pretty/src/lib.rs | 6 +++--- .../infer/error_reporting/need_type_info.rs | 6 +++--- compiler/rustc_lint/src/late.rs | 6 +++--- compiler/rustc_lint/src/levels.rs | 4 ++-- compiler/rustc_lint/src/passes.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/block.rs | 4 ++-- .../src/thir/pattern/check_match.rs | 11 ++++++----- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/hir_stats.rs | 4 ++-- compiler/rustc_passes/src/liveness.rs | 14 +++++++------- compiler/rustc_privacy/src/lib.rs | 4 ++-- .../rustc_save_analysis/src/dump_visitor.rs | 4 ++-- .../src/traits/error_reporting/suggestions.rs | 2 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 14 +++++--------- .../rustc_typeck/src/check/gather_locals.rs | 4 ++-- compiler/rustc_typeck/src/check/region.rs | 4 ++-- compiler/rustc_typeck/src/check/writeback.rs | 4 ++-- compiler/rustc_typeck/src/expr_use_visitor.rs | 6 +++--- src/tools/clippy/clippy_lints/src/attrs.rs | 2 +- src/tools/clippy/clippy_lints/src/copies.rs | 6 +++--- src/tools/clippy/clippy_lints/src/default.rs | 2 +- .../src/default_numeric_fallback.rs | 2 +- src/tools/clippy/clippy_lints/src/entry.rs | 2 +- .../clippy/clippy_lints/src/explicit_write.rs | 2 +- .../clippy/clippy_lints/src/let_if_seq.rs | 2 +- .../clippy/clippy_lints/src/let_underscore.rs | 4 ++-- .../clippy_lints/src/loops/needless_collect.rs | 4 ++-- .../clippy_lints/src/loops/never_loop.rs | 2 +- .../clippy/clippy_lints/src/loops/utils.rs | 6 +++--- .../clippy_lints/src/loops/while_let_loop.rs | 2 +- .../src/loops/while_let_on_iterator.rs | 4 ++-- .../clippy/clippy_lints/src/map_unit_fn.rs | 2 +- .../clippy/clippy_lints/src/matches/mod.rs | 11 +++-------- .../clippy_lints/src/methods/str_splitn.rs | 2 +- src/tools/clippy/clippy_lints/src/misc.rs | 2 +- .../src/mixed_read_write_in_expression.rs | 4 ++-- src/tools/clippy/clippy_lints/src/mut_key.rs | 7 +------ .../clippy_lints/src/needless_late_init.rs | 4 ++-- src/tools/clippy/clippy_lints/src/no_effect.rs | 4 ++-- .../clippy_lints/src/only_used_in_recursion.rs | 4 ++-- .../clippy_lints/src/pattern_type_mismatch.rs | 2 +- .../clippy_lints/src/read_zero_byte_vec.rs | 2 +- .../clippy_lints/src/redundant_closure_call.rs | 2 +- src/tools/clippy/clippy_lints/src/returns.rs | 2 +- .../src/slow_vector_initialization.rs | 2 +- src/tools/clippy/clippy_lints/src/swap.rs | 2 +- src/tools/clippy/clippy_lints/src/types/mod.rs | 4 ++-- .../clippy/clippy_lints/src/uninit_vec.rs | 2 +- .../src/unit_types/let_unit_value.rs | 2 +- .../clippy/clippy_lints/src/utils/author.rs | 2 +- .../clippy_lints/src/vec_init_then_push.rs | 2 +- src/tools/clippy/clippy_utils/src/hir_utils.rs | 8 ++++---- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- 59 files changed, 138 insertions(+), 131 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 0ec596e705374..09fcdfc1c9716 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -52,7 +52,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let local = self.lower_local(local); self.alias_attrs(hir_id, local.hir_id); - let kind = hir::StmtKind::Local(local, els); + let kind = hir::StmtKind::Local(local); let span = self.lower_span(s.span); stmts.push(hir::Stmt { hir_id, kind, span }); } @@ -105,10 +105,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let init = l.kind.init().map(|init| self.lower_expr(init)); let hir_id = self.lower_node_id(l.id); let pat = self.lower_pat(&l.pat); + let els = if let LocalKind::InitElse(_, els) = &l.kind { + if !self.sess.features_untracked().let_else { + feature_err( + &self.sess.parse_sess, + sym::let_else, + l.span, + "`let...else` statements are unstable", + ) + .emit(); + } + Some(self.lower_block(els, false)) + } else { + None + }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; self.lower_attrs(hir_id, &l.attrs); - self.arena.alloc(hir::Local { hir_id, ty, pat, init, span, source }) + self.arena.alloc(hir::Local { hir_id, ty, pat, init, els, span, source }) } fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode { diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 05210e9b89eac..ddd54f7c2089d 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -284,10 +284,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_local(&mut self, l: &'hir Local<'hir>, e: Option<&'hir Block<'hir>>) { + fn visit_local(&mut self, l: &'hir Local<'hir>) { self.insert(l.span, l.hir_id, Node::Local(l)); self.with_parent(l.hir_id, |this| { - intravisit::walk_local(this, l, e); + intravisit::walk_local(this, l); }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6b420c42d6152..4da3096f7c3aa 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2146,8 +2146,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug_assert!(!a.is_empty()); self.attrs.insert(hir_id.local_id, a); } - let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None }; - self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local), None)) + let local = hir::Local { + hir_id, + init, + pat, + els: None, + source, + span: self.lower_span(span), + ty: None, + }; + self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local))) } fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 65cb5f77e0629..c8a0ed3951100 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1297,7 +1297,7 @@ pub struct Stmt<'hir> { pub enum StmtKind<'hir> { /// A local (`let`) binding. /// FIXME: bundle the last two components into another `struct` - Local(&'hir Local<'hir>, Option<&'hir Block<'hir>>), + Local(&'hir Local<'hir>), /// An item binding. Item(ItemId), @@ -1317,6 +1317,8 @@ pub struct Local<'hir> { pub ty: Option<&'hir Ty<'hir>>, /// Initializer expression to set the value, if any. pub init: Option<&'hir Expr<'hir>>, + /// Else block for a `let...else` binding. + pub els: Option<&'hir Block<'hir>>, pub hir_id: HirId, pub span: Span, /// Can be `ForLoopDesugar` if the `let` statement is part of a `for` loop diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3585aba5f3db0..ef1a30e142cf6 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -310,8 +310,8 @@ pub trait Visitor<'v>: Sized { fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) { walk_foreign_item(self, i) } - fn visit_local(&mut self, l: &'v Local<'v>, els: Option<&'v Block<'v>>) { - walk_local(self, l, els) + fn visit_local(&mut self, l: &'v Local<'v>) { + walk_local(self, l) } fn visit_block(&mut self, b: &'v Block<'v>) { walk_block(self, b) @@ -466,17 +466,13 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) { visitor.visit_expr(&body.value); } -pub fn walk_local<'v, V: Visitor<'v>>( - visitor: &mut V, - local: &'v Local<'v>, - els: Option<&'v Block<'v>>, -) { +pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) { // Intentionally visiting the expr first - the initialization expr // dominates the local's definition. walk_list!(visitor, visit_expr, &local.init); visitor.visit_id(local.hir_id); visitor.visit_pat(&local.pat); - if let Some(els) = els { + if let Some(els) = local.els { visitor.visit_block(els); } walk_list!(visitor, visit_ty, &local.ty); @@ -1063,7 +1059,7 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) { pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { visitor.visit_id(statement.hir_id); match &statement.kind { - StmtKind::Local(ref local, els) => visitor.visit_local(local, *els), + StmtKind::Local(ref local) => visitor.visit_local(local), StmtKind::Item(item) => visitor.visit_nested_item(*item), StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { visitor.visit_expr(expression) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 7f8601308734f..e3c97ec357e87 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -915,8 +915,8 @@ impl<'a> State<'a> { pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) { self.maybe_print_comment(st.span.lo()); match st.kind { - hir::StmtKind::Local(loc, els) => { - self.print_local(loc.init, els, |this| this.print_local_decl(loc)); + hir::StmtKind::Local(loc) => { + self.print_local(loc.init, loc.els, |this| this.print_local_decl(loc)); } hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)), hir::StmtKind::Expr(expr) => { @@ -2305,7 +2305,7 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr<'_>) -> bool { /// seen the semicolon, and thus don't need another. fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool { match *stmt { - hir::StmtKind::Local(_, _) => true, + hir::StmtKind::Local(_) => true, hir::StmtKind::Item(_) => false, hir::StmtKind::Expr(e) => expr_requires_semi_to_be_stmt(e), hir::StmtKind::Semi(..) => false, diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index ace30e61769f8..a0ec7f4fc6f84 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,6 +1,6 @@ use crate::infer::type_variable::TypeVariableOriginKind; use crate::infer::InferCtxt; -use hir::{Block, LocalSource}; +use hir::LocalSource; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::Res; @@ -953,8 +953,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { self.infcx.tcx.hir() } - fn visit_local(&mut self, local: &'tcx Local<'tcx>, els: Option<&'tcx Block<'tcx>>) { - intravisit::walk_local(self, local, els); + fn visit_local(&mut self, local: &'tcx Local<'tcx>) { + intravisit::walk_local(self, local); if let Some(ty) = self.opt_node_type(local.hir_id) { if self.generic_arg_contains_target(ty.into()) { diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 695d89e791202..27f67207209dd 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -251,10 +251,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas } } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) { + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { self.with_lint_attrs(l.hir_id, |cx| { - lint_callback!(cx, check_local, l, e); - hir_visit::walk_local(cx, l, e); + lint_callback!(cx, check_local, l); + hir_visit::walk_local(cx, l); }) } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 43c7ff3c4bb20..00e96f20d1aaa 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -783,9 +783,9 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { }) } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) { + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { self.with_lint_attrs(l.hir_id, |builder| { - intravisit::walk_local(builder, l, e); + intravisit::walk_local(builder, l); }) } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 41d8e5cf859dd..b1b4229b1f738 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -24,7 +24,7 @@ macro_rules! late_lint_methods { fn check_foreign_item_post(a: &$hir hir::ForeignItem<$hir>); fn check_item(a: &$hir hir::Item<$hir>); fn check_item_post(a: &$hir hir::Item<$hir>); - fn check_local(a: &$hir hir::Local<$hir>, b: Option<&$hir hir::Block<$hir>>); + fn check_local(a: &$hir hir::Local<$hir>); fn check_block(a: &$hir hir::Block<$hir>); fn check_block_post(a: &$hir hir::Block<$hir>); fn check_stmt(a: &$hir hir::Stmt<$hir>); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 85fc897c7ff03..3e99ba5742a4b 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -789,7 +789,7 @@ impl<'hir> Map<'hir> { | Node::ForeignItem(_) | Node::TraitItem(_) | Node::ImplItem(_) - | Node::Stmt(Stmt { kind: StmtKind::Local(_, _), .. }) => break, + | Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break, Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => { return Some(expr); } diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index d77d74e25f6e5..4079470c25518 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -66,7 +66,7 @@ impl<'tcx> Cx<'tcx> { // ignore for purposes of the MIR None } - hir::StmtKind::Local(local, els) => { + hir::StmtKind::Local(local) => { let remainder_scope = region::Scope { id: block_id, data: region::ScopeData::Remainder(region::FirstStatementIndex::new( @@ -74,7 +74,7 @@ impl<'tcx> Cx<'tcx> { )), }; - let else_block = els.map(|els| self.mirror_block(els)); + let else_block = local.els.map(|els| self.mirror_block(els)); let mut pattern = self.pattern_from_hir(local.pat); debug!(?pattern); diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index daaabd855c87e..5bd1fad0bcb9f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -75,10 +75,11 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { } } - fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) { - intravisit::walk_local(self, loc, els); - if let Some(init) = &loc.init && els.is_some() { - self.check_let(&loc.pat, &init, loc.span); + fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) { + intravisit::walk_local(self, loc); + let els = loc.els; + if let Some(init) = loc.init && els.is_some() { + self.check_let(&loc.pat, init, loc.span); } let (msg, sp) = match loc.source { @@ -1135,7 +1136,7 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option) -> L let parent_parent = hir.get_parent_node(parent); let parent_parent_node = hir.get(parent_parent); - if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_, Some(_)), span, .. }) = + if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) = parent_parent_node { return LetSource::LetElse(*span); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f78c0f4f545ff..d0723c68a77e8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2311,7 +2311,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { // When checking statements ignore expressions, they will be checked later. - if let hir::StmtKind::Local(ref l, _) = stmt.kind { + if let hir::StmtKind::Local(ref l) = stmt.kind { self.check_attributes(l.hir_id, stmt.span, Target::Statement, None); } intravisit::walk_stmt(self, stmt) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d8e97e5adef2f..a3be827a7ccec 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -131,9 +131,9 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_foreign_item(self, i) } - fn visit_local(&mut self, l: &'v hir::Local<'v>, e: Option<&'v hir::Block<'v>>) { + fn visit_local(&mut self, l: &'v hir::Local<'v>) { self.record("Local", Id::Node(l.hir_id), l); - hir_visit::walk_local(self, l, e) + hir_visit::walk_local(self, l) } fn visit_block(&mut self, b: &'v hir::Block<'v>) { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index f125f107fe2a5..eed3e1579a231 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -366,12 +366,12 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { lsets.warn_about_unused_args(body, entry_ln); } - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { self.add_from_pat(&local.pat); - if els.is_some() { + if local.els.is_some() { self.add_live_node_for_node(local.hir_id, ExprNode(local.span, local.hir_id)); } - intravisit::walk_local(self, local, els); + intravisit::walk_local(self, local); } fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { @@ -788,7 +788,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_stmt(&mut self, stmt: &hir::Stmt<'_>, succ: LiveNode) -> LiveNode { match stmt.kind { - hir::StmtKind::Local(ref local, els) => { + hir::StmtKind::Local(ref local) => { // Note: we mark the variable as defined regardless of whether // there is an initializer. Initially I had thought to only mark // the live variable as defined if it was initialized, and then we @@ -803,7 +803,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // initialization, which is mildly more complex than checking // once at the func header but otherwise equivalent. - if let Some(els) = els { + if let Some(els) = local.els { // Eventually, `let pat: ty = init else { els };` is mostly equivalent to // `let (bindings, ...) = match init { pat => (bindings, ...), _ => els };` // except that extended lifetime applies at the `init` location. @@ -1341,14 +1341,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Checking for error conditions impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> { - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| { if local.init.is_some() { self.warn_about_dead_assign(spans, hir_id, ln, var); } }); - intravisit::walk_local(self, local, els); + intravisit::walk_local(self, local); } fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 05345f73ef65f..5560d44aa0d52 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1275,7 +1275,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { intravisit::walk_pat(self, pattern); } - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { if let Some(init) = local.init { if self.check_expr_pat_type(init.hir_id, init.span) { // Do not report duplicate errors for `let x = y`. @@ -1283,7 +1283,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { } } - intravisit::walk_local(self, local, els); + intravisit::walk_local(self, local); } // Check types in item interfaces. diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 2aaacad4ba4e2..a4175f4c5f377 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -1414,14 +1414,14 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { intravisit::walk_stmt(self, s) } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) { + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { self.process_macro_use(l.span); self.process_var_decl(&l.pat); // Just walk the initializer, the else branch and type (don't want to walk the pattern again). walk_list!(self, visit_ty, &l.ty); walk_list!(self, visit_expr, &l.init); - walk_list!(self, visit_block, e); + walk_list!(self, visit_block, l.els); } fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index adbe71b83ed92..b08fc48218602 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -734,7 +734,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?); let parent_node = hir.get_parent_node(hir_id); match hir.find(parent_node) { - Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local, _), .. })) => { + Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => { get_name(err, &local.pat.kind) } // Different to previous arm because one is `&hir::Local` and the other diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index fcd610e677a75..097b9c3f0f706 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1218,13 +1218,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Type check a `let` statement. - pub fn check_decl_local( - &self, - local: &'tcx hir::Local<'tcx>, - els: Option<&'tcx hir::Block<'tcx>>, - ) { + pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { self.check_decl(local.into()); - if let Some(blk) = els { + if let Some(blk) = local.els { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); @@ -1251,8 +1247,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let old_has_errors = self.has_errors.replace(false); match stmt.kind { - hir::StmtKind::Local(l, e) => { - self.check_decl_local(l, e); + hir::StmtKind::Local(l) => { + self.check_decl_local(l); } // Ignore for now. hir::StmtKind::Item(_) => {} @@ -1411,7 +1407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: hir::LocalSource::AssignDesugar(_), .. - }, _), + }), .. }, hir::Stmt { diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index 956f315f68426..859fc91f517cb 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -99,9 +99,9 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // Add explicitly-declared locals. - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>, els: Option<&'tcx hir::Block<'tcx>>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { self.declare(local.into()); - intravisit::walk_local(self, local, els) + intravisit::walk_local(self, local) } fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) { diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs index 54fb17734f4de..a1a92c62ad22f 100644 --- a/compiler/rustc_typeck/src/check/region.rs +++ b/compiler/rustc_typeck/src/check/region.rs @@ -796,8 +796,8 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { resolve_expr(self, ex); } - fn visit_local(&mut self, l: &'tcx Local<'tcx>, e: Option<&'tcx Block<'tcx>>) { - resolve_local(self, Some(&l.pat), l.init, e) + fn visit_local(&mut self, l: &'tcx Local<'tcx>) { + resolve_local(self, Some(&l.pat), l.init, l.els) } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index b61ec13e388ac..41d241f84acea 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -321,8 +321,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { intravisit::walk_pat(self, p); } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>, e: Option<&'tcx hir::Block<'tcx>>) { - intravisit::walk_local(self, l, e); + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + intravisit::walk_local(self, l); let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty; let var_ty = self.resolve(var_ty, &l.span); self.write_ty_to_typeck_results(l.hir_id, var_ty); diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 12581286941f3..a344404b97057 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -453,11 +453,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) { match stmt.kind { - hir::StmtKind::Local(hir::Local { pat, init: Some(expr), .. }, els) => { - self.walk_local(expr, pat, els, |_| {}) + hir::StmtKind::Local(hir::Local { pat, init: Some(expr), els, .. }) => { + self.walk_local(expr, pat, *els, |_| {}) } - hir::StmtKind::Local(_, _) => {} + hir::StmtKind::Local(_) => {} hir::StmtKind::Item(_) => { // We don't visit nested items in this visitor, diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 93ce3b30fb1d3..4bcbeacf9feb5 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -505,7 +505,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_ .as_ref() .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)), |stmt| match &stmt.kind { - StmtKind::Local(_, _) => true, + StmtKind::Local(_) => true, StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), StmtKind::Item(_) => false, }, diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 0b9fdb891b15c..1deff9684a140 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -324,7 +324,7 @@ impl BlockEq { /// If the statement is a local, checks if the bound names match the expected list of names. fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { - if let StmtKind::Local(l, _) = s.kind { + if let StmtKind::Local(l) = s.kind { let mut i = 0usize; let mut res = true; l.pat.each_binding_or_first(&mut |_, _, _, name| { @@ -349,7 +349,7 @@ fn eq_stmts( eq: &mut HirEqInterExpr<'_, '_, '_>, moved_bindings: &mut Vec<(HirId, Symbol)>, ) -> bool { - (if let StmtKind::Local(l, _) = stmt.kind { + (if let StmtKind::Local(l) = stmt.kind { let old_count = moved_bindings.len(); l.pat.each_binding_or_first(&mut |_, id, _, name| { moved_bindings.push((id, name.name)); @@ -435,7 +435,7 @@ fn scan_block_for_eq(cx: &LateContext<'_>, _conds: &[&Expr<'_>], block: &Block<' // Clear out all locals seen at the end so far. None of them can be moved. let stmts = &blocks[0].stmts; for stmt in &stmts[stmts.len() - init..=stmts.len() - offset] { - if let StmtKind::Local(l, _) = stmt.kind { + if let StmtKind::Local(l) = stmt.kind { l.pat.each_binding_or_first(&mut |_, id, _, _| { eq.locals.remove(&id); }); diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 7fe3443858a01..d99a1aa296946 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // checked and the name of the bound variable let (local, variant, binding_name, binding_type, span) = if_chain! { // only take `let ...` statements - if let StmtKind::Local(local, _) = stmt.kind; + if let StmtKind::Local(local) = stmt.kind; if let Some(expr) = local.init; if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); if !expr.span.from_expansion(); diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 0f374d12a84f6..fb418a3251f58 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -192,7 +192,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { match stmt.kind { - StmtKind::Local(local, _) => { + StmtKind::Local(local) => { if local.ty.is_some() { self.ty_bounds.push(TyBound::Any); } else { diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index e0986b710c508..27743a0ebec7e 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -386,7 +386,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { } }, StmtKind::Expr(e) => self.visit_expr(e), - StmtKind::Local(l, _) => { + StmtKind::Local(l) => { self.visit_pat(l.pat); if let Some(e) = l.init { self.allow_insert_closure &= !self.in_tail_pos; diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index bd1ac3371b063..5bf4313b41a49 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -116,7 +116,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>) if_chain! { if let ExprKind::Block(block, _label @ None) = kind; if let Block { - stmts: [Stmt { kind: StmtKind::Local(local, _), .. }], + stmts: [Stmt { kind: StmtKind::Local(local), .. }], expr: Some(expr_end_of_block), rules: BlockCheckMode::DefaultBlock, .. diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs index 5dcb86feb7622..56bbbbbc819e5 100644 --- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs +++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { while let Some(stmt) = it.next() { if_chain! { if let Some(expr) = it.peek(); - if let hir::StmtKind::Local(local, _) = stmt.kind; + if let hir::StmtKind::Local(local) = stmt.kind; if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind; if let hir::StmtKind::Expr(if_) = expr.kind; if let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind; diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index a37dfb7b7151d..176787497ebf2 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{is_must_use_ty, match_type}; use clippy_utils::{is_must_use_func_call, paths}; use if_chain::if_chain; -use rustc_hir::{Block, Local, PatKind}; +use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; @@ -109,7 +109,7 @@ const SYNC_GUARD_PATHS: [&[&str]; 6] = [ ]; impl<'tcx> LateLintPass<'tcx> for LetUnderscore { - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>, _: Option<&Block<'_>>) { + fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { if in_external_macro(cx.tcx.sess, local.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs index ba0f01d9ed25b..ddaffc751880d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs @@ -76,7 +76,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo if let ExprKind::Block(block, _) = expr.kind { for stmt in block.stmts { if_chain! { - if let StmtKind::Local(local, _) = stmt.kind; + if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(_, id, ..) = local.pat.kind; if let Some(init_expr) = local.init; if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind; @@ -276,7 +276,7 @@ fn get_expr_and_hir_id_from_stmt<'v>(stmt: &'v Stmt<'v>) -> Option<(&'v Expr<'v> match stmt.kind { StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some((expr, None)), StmtKind::Item(..) => None, - StmtKind::Local(Local { init, pat, .. }, _) => { + StmtKind::Local(Local { init, pat, .. }) => { if let PatKind::Binding(_, hir_id, ..) = pat.kind { init.map(|init_expr| (init_expr, Some(hir_id))) } else { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index c60d551806067..32de20f6531fe 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -104,7 +104,7 @@ fn never_loop_expr_seq<'a, T: Iterator>>(es: &mut T, main_lo fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> { match stmt.kind { StmtKind::Semi(e, ..) | StmtKind::Expr(e, ..) => Some(e), - StmtKind::Local(local, _) => local.init, + StmtKind::Local(local) => local.init, StmtKind::Item(..) => None, } } diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index 661af8fe642f9..4801a84eb92ce 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, Visitor}; -use rustc_hir::{BinOpKind, Block, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, Pat, PatKind, Stmt}; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, Pat, PatKind, Stmt}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; @@ -148,7 +148,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_local(&mut self, l: &'tcx Local<'_>, e: Option<&'tcx Block<'_>>) { + fn visit_local(&mut self, l: &'tcx Local<'_>) { // Look for declarations of the variable if_chain! { if l.pat.hir_id == self.var_id; @@ -166,7 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } } - walk_local(self, l, e); + walk_local(self, l); } fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs index 8c3524942520b..ca617859db49d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs @@ -11,7 +11,7 @@ use rustc_lint::LateContext; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) { ([stmt, stmts @ ..], expr) => { - if let StmtKind::Local(&Local { init: Some(e), .. }, None) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind { + if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind { (e, !stmts.is_empty() || expr.is_some()) } else { return; diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index 1abdfaac7ec64..a57159750664f 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -8,7 +8,7 @@ use clippy_utils::{ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{def::Res, Block, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp}; +use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_span::{symbol::sym, Symbol}; @@ -283,7 +283,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & used_after: bool, } impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> { - fn visit_local(&mut self, l: &'tcx Local<'_>, _: Option<&'tcx Block<'_>>) { + fn visit_local(&mut self, l: &'tcx Local<'_>) { if !self.after_loop { l.pat.each_binding_or_first(&mut |_, id, _, _| { if id == self.local_id { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 3bfe5428133fc..663246b4c8622 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -144,7 +144,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> // If block only contains statements, // reduce `{ X; }` to `X` or `X;` match inner_stmt.kind { - hir::StmtKind::Local(local, _) => Some(local.span), + hir::StmtKind::Local(local) => Some(local.span), hir::StmtKind::Expr(e) => Some(e.span), hir::StmtKind::Semi(..) => Some(inner_stmt.span), hir::StmtKind::Item(..) => None, diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index cc8674a200652..3077b999f4ee4 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -1,6 +1,6 @@ use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context}; use clippy_utils::{higher, in_constant, meets_msrv, msrvs}; -use rustc_hir::{Arm, Block, Expr, ExprKind, Local, MatchSource, Pat}; +use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -1040,14 +1040,9 @@ impl<'tcx> LateLintPass<'tcx> for Matches { } } - fn check_local( - &mut self, - cx: &LateContext<'tcx>, - local: &'tcx Local<'_>, - els: Option<&'tcx Block<'_>>, - ) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { self.infallible_destructuring_match_linted |= - els.is_none() && infallible_destructuring_match::check(cx, local); + local.els.is_none() && infallible_destructuring_match::check(cx, local); } fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 80dbd14b2c56a..4ac738272d085 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -220,7 +220,7 @@ fn indirect_usage<'tcx>( init: Some(init_expr), hir_id: local_hir_id, .. - }, _) = stmt.kind + }) = stmt.kind { let mut path_to_binding = None; expr_visitor(cx, |expr| { diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 2ad7ac60b9250..be7df08d89f05 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if_chain! { if !in_external_macro(cx.tcx.sess, stmt.span); - if let StmtKind::Local(local, _) = stmt.kind; + if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(an, .., name, None) = local.pat.kind; if let Some(init) = local.init; if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut; diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index de993c3c0a47a..a2419c277e9c2 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { match stmt.kind { - StmtKind::Local(local, _) => { + StmtKind::Local(local) => { if let Local { init: Some(e), .. } = local { DivergenceVisitor { cx }.visit_expr(e); } @@ -273,7 +273,7 @@ fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) - StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr), // If the declaration is of a local variable, check its initializer // expression if it has one. Otherwise, keep going. - StmtKind::Local(local, _) => local + StmtKind::Local(local) => local .init .as_ref() .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)), diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 251181165b022..4db103bbc1305 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -101,12 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { } } - fn check_local( - &mut self, - cx: &LateContext<'_>, - local: &hir::Local<'_>, - _: Option<&hir::Block<'_>>, - ) { + fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) { if let hir::PatKind::Wild = local.pat.kind { return; } diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index fa1c09d8f9032..ff2999b1f4a51 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -92,7 +92,7 @@ fn contains_let(cond: &Expr<'_>) -> bool { } fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { - let StmtKind::Local(local, _) = stmt.kind else { return false }; + let StmtKind::Local(local) = stmt.kind else { return false }; !local.pat.walk_short(|pat| { if let PatKind::Binding(.., None) = pat.kind { !needs_ordered_drop(cx, cx.typeck_results().pat_ty(pat)) @@ -367,7 +367,7 @@ fn check<'tcx>( } impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>, _: Option<&'tcx Block<'tcx>>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { let mut parents = cx.tcx.hir().parent_iter(local.hir_id); if_chain! { if let Local { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 105e145ac3069..819646bb6780e 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -88,11 +88,11 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect"); return true; } - } else if let StmtKind::Local(local, els) = stmt.kind { + } else if let StmtKind::Local(local) = stmt.kind { if_chain! { if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id); if let Some(init) = local.init; - if els.is_none(); + if local.els.is_none(); if !local.pat.span.from_expansion(); if has_no_effect(cx, init); if let PatKind::Binding(_, _, ident, _) = local.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index c7f8f2f8d7045..677ac998b5682 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -261,13 +261,13 @@ impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> { match s.kind { StmtKind::Local(Local { pat, init: Some(init), .. - }, _) => { + }) => { self.visit_pat_expr(pat, init, false); }, StmtKind::Item(_) | StmtKind::Expr(_) | StmtKind::Semi(_) => { walk_stmt(self, s); }, - StmtKind::Local(_, _) => {}, + StmtKind::Local(_) => {}, } self.ret_vars.clear(); } diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 83e18e207117a..a4d265111f9ae 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -83,7 +83,7 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]); impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let StmtKind::Local(local, _) = stmt.kind { + if let StmtKind::Local(local) = stmt.kind { if in_external_macro(cx.sess(), local.pat.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index 8316efad1ffed..9538a8104739e 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { for (idx, stmt) in block.stmts.iter().enumerate() { if !stmt.span.from_expansion() // matches `let v = Vec::new();` - && let StmtKind::Local(local, _) = stmt.kind + && let StmtKind::Local(local) = stmt.kind && let Local { pat, init: Some(init), .. } = local && let PatKind::Binding(_, _, ident, _) = pat.kind && let Some(vec_init_kind) = get_vec_init_kind(cx, init) diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 48bf14d511c71..65ed798867d19 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { for w in block.stmts.windows(2) { if_chain! { - if let hir::StmtKind::Local(local, _) = w[0].kind; + if let hir::StmtKind::Local(local) = w[0].kind; if let Option::Some(t) = local.init; if let hir::ExprKind::Closure { .. } = t.kind; if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index b2ec32abb442a..1d9a2abf7066c 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { if_chain! { if let Some(retexpr) = block.expr; if let Some(stmt) = block.stmts.iter().last(); - if let StmtKind::Local(local, _) = &stmt.kind; + if let StmtKind::Local(local) = &stmt.kind; if local.ty.is_none(); if cx.tcx.hir().attrs(local.hir_id).is_empty(); if let Some(initexpr) = &local.init; diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 3d7ef747a86c8..2c8aa17e80dbd 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` if_chain! { - if let StmtKind::Local(local, _) = stmt.kind; + if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind; if let Some(init) = local.init; if let Some(len_arg) = Self::is_vec_with_capacity(cx, init); diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index a8c96543c7c6e..1885f3ca414df 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -141,7 +141,7 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { for w in block.stmts.windows(3) { if_chain! { // let t = foo(); - if let StmtKind::Local(tmp, _) = w[0].kind; + if let StmtKind::Local(tmp) = w[0].kind; if let Some(tmp_init) = tmp.init; if let PatKind::Binding(.., ident, None) = tmp.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 2a7d5f2623e2c..353a6f6b899ea 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -12,7 +12,7 @@ mod vec_box; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Block, Body, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem, + Body, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem, TraitItemKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -406,7 +406,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { } } - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>, _: Option<&Block<'_>>) { + fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { if let Some(ty) = local.ty { self.check_ty( cx, diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs index eab3b9b7b01c2..9f4c5555f11b7 100644 --- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs +++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs @@ -155,7 +155,7 @@ impl<'tcx> VecLocation<'tcx> { /// or `self` expression for `Vec::reserve()`. fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option> { match stmt.kind { - StmtKind::Local(local, _) => { + StmtKind::Local(local) => { if_chain! { if let Some(init_expr) = local.init; if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index 80e7b8de392c7..cf509455aad0a 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitable, TypeSuperVisitable, TypeVisitor} use super::LET_UNIT_VALUE; pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) { - if let StmtKind::Local(local, _) = stmt.kind + if let StmtKind::Local(local) = stmt.kind && let Some(init) = local.init && !local.pat.span.from_expansion() && !in_external_macro(cx.sess(), stmt.span) diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 99ac84fbaabae..2c8820eb7e1a1 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -685,7 +685,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } match stmt.value.kind { - StmtKind::Local(local, _) => { + StmtKind::Local(local) => { bind!(self, local); kind!("Local({local})"); self.option(field!(local.init), "init", |init| { diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index c71bacfa29a70..35db45e2b0c99 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -155,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { self.searcher = None; } - fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>, _: Option<&'tcx Block<'tcx>>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { if let Some(init_expr) = local.init && let PatKind::Binding(BindingAnnotation::Mutable, id, name, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 0b5325adfed20..942f14ddd3d51 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -102,7 +102,7 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> { impl HirEqInterExpr<'_, '_, '_> { pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool { match (&left.kind, &right.kind) { - (&StmtKind::Local(l, le), &StmtKind::Local(r, re)) => { + (&StmtKind::Local(l, ), &StmtKind::Local(r, )) => { // This additional check ensures that the type of the locals are equivalent even if the init // expression or type have some inferred parts. if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results { @@ -117,7 +117,7 @@ impl HirEqInterExpr<'_, '_, '_> { // these only get added if the init and type is equal. both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) - && both(&le, &re, |l, r| self.eq_block(l, r)) + && both(&l.els, &r.els, |l, r| self.eq_block(l, r)) && self.eq_pat(l.pat, r.pat) }, (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r), @@ -922,12 +922,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { std::mem::discriminant(&b.kind).hash(&mut self.s); match &b.kind { - StmtKind::Local(local, els) => { + StmtKind::Local(local, ) => { self.hash_pat(local.pat); if let Some(init) = local.init { self.hash_expr(init); } - if let Some(els) = els { + if let Some(els) = local.els { self.hash_block(els); } }, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index ac6490cfd2c72..1b32f0aaeb8df 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1826,7 +1826,7 @@ pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { .. }, .. - }, _), + }), .. }), _ From 8e4a9710841a21f77856ae1d8207015c220a1873 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 11 Jul 2022 21:11:03 +0200 Subject: [PATCH 23/31] extract method to read scrutinee conditionally --- compiler/rustc_ast_lowering/src/block.rs | 18 +- compiler/rustc_typeck/src/expr_use_visitor.rs | 190 ++++++++++-------- 2 files changed, 105 insertions(+), 103 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 09fcdfc1c9716..7cbfe143b4d83 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -36,20 +36,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match s.kind { StmtKind::Local(ref local) => { let hir_id = self.lower_node_id(s.id); - let els = if let LocalKind::InitElse(_, els) = &local.kind { - if !self.tcx.features().let_else { - feature_err( - &self.tcx.sess.parse_sess, - sym::let_else, - s.span, - "`let...else` statements are unstable", - ) - .emit(); - } - Some(self.lower_block(els, false)) - } else { - None - }; let local = self.lower_local(local); self.alias_attrs(hir_id, local.hir_id); let kind = hir::StmtKind::Local(local); @@ -106,9 +92,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let hir_id = self.lower_node_id(l.id); let pat = self.lower_pat(&l.pat); let els = if let LocalKind::InitElse(_, els) = &l.kind { - if !self.sess.features_untracked().let_else { + if !self.tcx.features().let_else { feature_err( - &self.sess.parse_sess, + &self.tcx.sess.parse_sess, sym::let_else, l.span, "`let...else` statements are unstable", diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index a344404b97057..53a456cf94643 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -2,7 +2,10 @@ //! normal visitor, which just walks the entire body in one shot, the //! `ExprUseVisitor` determines how expressions are being used. +use std::slice::from_ref; + use hir::def::DefKind; +use hir::Expr; // Export these here so that Clippy can use them. pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; @@ -257,91 +260,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { hir::ExprKind::Match(ref discr, arms, _) => { let discr_place = return_if_err!(self.mc.cat_expr(discr)); - - // Matching should not always be considered a use of the place, hence - // discr does not necessarily need to be borrowed. - // We only want to borrow discr if the pattern contain something other - // than wildcards. - let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self; - let mut needs_to_be_read = false; - for arm in arms.iter() { - return_if_err!(mc.cat_pattern(discr_place.clone(), arm.pat, |place, pat| { - match &pat.kind { - PatKind::Binding(.., opt_sub_pat) => { - // If the opt_sub_pat is None, than the binding does not count as - // a wildcard for the purpose of borrowing discr. - if opt_sub_pat.is_none() { - needs_to_be_read = true; - } - } - PatKind::Path(qpath) => { - // A `Path` pattern is just a name like `Foo`. This is either a - // named constant or else it refers to an ADT variant - - let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id); - match res { - Res::Def(DefKind::Const, _) - | Res::Def(DefKind::AssocConst, _) => { - // Named constants have to be equated with the value - // being matched, so that's a read of the value being matched. - // - // FIXME: We don't actually reads for ZSTs. - needs_to_be_read = true; - } - _ => { - // Otherwise, this is a struct/enum variant, and so it's - // only a read if we need to read the discriminant. - needs_to_be_read |= is_multivariant_adt(place.place.ty()); - } - } - } - PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => { - // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching - // against a multivariant enum or struct. In that case, we have to read - // the discriminant. Otherwise this kind of pattern doesn't actually - // read anything (we'll get invoked for the `...`, which may indeed - // perform some reads). - - let place_ty = place.place.ty(); - needs_to_be_read |= is_multivariant_adt(place_ty); - } - PatKind::Lit(_) | PatKind::Range(..) => { - // If the PatKind is a Lit or a Range then we want - // to borrow discr. - needs_to_be_read = true; - } - PatKind::Or(_) - | PatKind::Box(_) - | PatKind::Slice(..) - | PatKind::Ref(..) - | PatKind::Wild => { - // If the PatKind is Or, Box, Slice or Ref, the decision is made later - // as these patterns contains subpatterns - // If the PatKind is Wild, the decision is made based on the other patterns being - // examined - } - } - })); - } - - if needs_to_be_read { - self.borrow_expr(discr, ty::ImmBorrow); - } else { - let closure_def_id = match discr_place.place.base { - PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()), - _ => None, - }; - - self.delegate.fake_read( - &discr_place, - FakeReadCause::ForMatchedPlace(closure_def_id), - discr_place.hir_id, - ); - - // We always want to walk the discriminant. We want to make sure, for instance, - // that the discriminant has been initialized. - self.walk_expr(discr); - } + self.maybe_read_scrutinee( + discr, + discr_place.clone(), + arms.iter().map(|arm| arm.pat), + ); // treatment of the discriminant is handled while walking the arms. for arm in arms { @@ -470,6 +393,97 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } + fn maybe_read_scrutinee<'t>( + &mut self, + discr: &Expr<'_>, + discr_place: PlaceWithHirId<'tcx>, + pats: impl Iterator>, + ) { + // Matching should not always be considered a use of the place, hence + // discr does not necessarily need to be borrowed. + // We only want to borrow discr if the pattern contain something other + // than wildcards. + let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self; + let mut needs_to_be_read = false; + for pat in pats { + return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| { + match &pat.kind { + PatKind::Binding(.., opt_sub_pat) => { + // If the opt_sub_pat is None, than the binding does not count as + // a wildcard for the purpose of borrowing discr. + if opt_sub_pat.is_none() { + needs_to_be_read = true; + } + } + PatKind::Path(qpath) => { + // A `Path` pattern is just a name like `Foo`. This is either a + // named constant or else it refers to an ADT variant + + let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id); + match res { + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => { + // Named constants have to be equated with the value + // being matched, so that's a read of the value being matched. + // + // FIXME: We don't actually reads for ZSTs. + needs_to_be_read = true; + } + _ => { + // Otherwise, this is a struct/enum variant, and so it's + // only a read if we need to read the discriminant. + needs_to_be_read |= is_multivariant_adt(place.place.ty()); + } + } + } + PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => { + // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching + // against a multivariant enum or struct. In that case, we have to read + // the discriminant. Otherwise this kind of pattern doesn't actually + // read anything (we'll get invoked for the `...`, which may indeed + // perform some reads). + + let place_ty = place.place.ty(); + needs_to_be_read |= is_multivariant_adt(place_ty); + } + PatKind::Lit(_) | PatKind::Range(..) => { + // If the PatKind is a Lit or a Range then we want + // to borrow discr. + needs_to_be_read = true; + } + PatKind::Or(_) + | PatKind::Box(_) + | PatKind::Slice(..) + | PatKind::Ref(..) + | PatKind::Wild => { + // If the PatKind is Or, Box, Slice or Ref, the decision is made later + // as these patterns contains subpatterns + // If the PatKind is Wild, the decision is made based on the other patterns being + // examined + } + } + })); + } + + if needs_to_be_read { + self.borrow_expr(discr, ty::ImmBorrow); + } else { + let closure_def_id = match discr_place.place.base { + PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()), + _ => None, + }; + + self.delegate.fake_read( + &discr_place, + FakeReadCause::ForMatchedPlace(closure_def_id), + discr_place.hir_id, + ); + + // We always want to walk the discriminant. We want to make sure, for instance, + // that the discriminant has been initialized. + self.walk_expr(discr); + } + } + fn walk_local( &mut self, expr: &hir::Expr<'_>, @@ -484,10 +498,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { f(self); if let Some(els) = els { // borrowing because we need to test the descriminant - self.borrow_expr(expr, ImmBorrow); + // self.borrow_expr(expr, ImmBorrow); + self.maybe_read_scrutinee(expr, expr_place, from_ref(pat).iter()); self.walk_block(els) + } else { + self.walk_irrefutable_pat(&expr_place, &pat); } - self.walk_irrefutable_pat(&expr_place, &pat); } /// Indicates that the value of `blk` will be consumed, meaning either copied or moved From 5374688e1d8cbcff7d1d14bb34e38fe6fe7c233e Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 11 Jul 2022 23:20:27 +0200 Subject: [PATCH 24/31] add tests for async await --- compiler/rustc_hir/src/hir.rs | 1 - compiler/rustc_hir/src/intravisit.rs | 4 +- .../infer/error_reporting/need_type_info.rs | 3 +- compiler/rustc_mir_build/src/thir/cx/block.rs | 4 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 11 ++- .../rustc_typeck/src/check/gather_locals.rs | 7 +- .../ui/async-await/async-await-let-else.rs | 53 +++++++++++ .../async-await/async-await-let-else.stderr | 94 +++++++++++++++++++ 8 files changed, 162 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/async-await/async-await-let-else.rs create mode 100644 src/test/ui/async-await/async-await-let-else.stderr diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c8a0ed3951100..ed874ae829b46 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1296,7 +1296,6 @@ pub struct Stmt<'hir> { #[derive(Debug, HashStable_Generic)] pub enum StmtKind<'hir> { /// A local (`let`) binding. - /// FIXME: bundle the last two components into another `struct` Local(&'hir Local<'hir>), /// An item binding. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index ef1a30e142cf6..b5d9769c578a5 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1058,9 +1058,9 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) { pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { visitor.visit_id(statement.hir_id); - match &statement.kind { + match statement.kind { StmtKind::Local(ref local) => visitor.visit_local(local), - StmtKind::Item(item) => visitor.visit_nested_item(*item), + StmtKind::Item(item) => visitor.visit_nested_item(item), StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { visitor.visit_expr(expression) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index a0ec7f4fc6f84..4d29fc469462c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,13 +1,12 @@ use crate::infer::type_variable::TypeVariableOriginKind; use crate::infer::InferCtxt; -use hir::LocalSource; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local}; +use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource}; use rustc_middle::hir::nested_filter; use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 4079470c25518..dccaa61ed89d4 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -48,7 +48,7 @@ impl<'tcx> Cx<'tcx> { .filter_map(|(index, stmt)| { let hir_id = stmt.hir_id; let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id); - match &stmt.kind { + match stmt.kind { hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { let stmt = Stmt { kind: StmtKind::Expr { @@ -66,7 +66,7 @@ impl<'tcx> Cx<'tcx> { // ignore for purposes of the MIR None } - hir::StmtKind::Local(local) => { + hir::StmtKind::Local(ref local) => { let remainder_scope = region::Scope { id: block_id, data: region::ScopeData::Remainder(region::FirstStatementIndex::new( diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 097b9c3f0f706..60ee2233ed9c0 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1215,12 +1215,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr); let pat_ty = self.node_ty(decl.pat.hir_id); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty); - } - /// Type check a `let` statement. - pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { - self.check_decl(local.into()); - if let Some(blk) = local.els { + if let Some(blk) = decl.els { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); @@ -1233,6 +1229,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Type check a `let` statement. + pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { + self.check_decl(local.into()); + } + pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>, is_last: bool) { // Don't do all the complex logic below for `DeclItem`. match stmt.kind { diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index 859fc91f517cb..8f34a970f6ff7 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -16,19 +16,20 @@ pub(super) struct Declaration<'a> { pub ty: Option<&'a hir::Ty<'a>>, pub span: Span, pub init: Option<&'a hir::Expr<'a>>, + pub els: Option<&'a hir::Block<'a>>, } impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { fn from(local: &'a hir::Local<'a>) -> Self { - let hir::Local { hir_id, pat, ty, span, init, .. } = *local; - Declaration { hir_id, pat, ty, span, init } + let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local; + Declaration { hir_id, pat, ty, span, init, els } } } impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { fn from(let_expr: &'a hir::Let<'a>) -> Self { let hir::Let { hir_id, pat, ty, span, init } = *let_expr; - Declaration { hir_id, pat, ty, span, init: Some(init) } + Declaration { hir_id, pat, ty, span, init: Some(init), els: None } } } diff --git a/src/test/ui/async-await/async-await-let-else.rs b/src/test/ui/async-await/async-await-let-else.rs new file mode 100644 index 0000000000000..7ea07ae9add1b --- /dev/null +++ b/src/test/ui/async-await/async-await-let-else.rs @@ -0,0 +1,53 @@ +// edition:2021 +#![feature(let_else)] +use std::rc::Rc; + +async fn foo(x: Option) { + let Some(_) = x else { + let r = Rc::new(()); + bar().await + }; +} + +async fn bar() -> ! { + panic!() +} + +fn is_send(_: T) {} + +async fn foo2(x: Option) { + let Some(_) = x else { + bar2(Rc::new(())).await + }; +} + +async fn bar2(_: T) -> ! { + panic!() +} + +async fn foo3(x: Option) { + let Some(_) = x else { + (Rc::new(()), bar().await); + return; + }; +} + +async fn foo4(x: Option) { + let Some(_) = x else { + let r = Rc::new(()); + bar().await; + println!("{:?}", r); + return; + }; +} + +fn main() { + is_send(foo(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo2(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo3(Some(true))); + //~^ ERROR future cannot be sent between threads safely + is_send(foo4(Some(true))); + //~^ ERROR future cannot be sent between threads safely +} diff --git a/src/test/ui/async-await/async-await-let-else.stderr b/src/test/ui/async-await/async-await-let-else.stderr new file mode 100644 index 0000000000000..4d23e27c426b2 --- /dev/null +++ b/src/test/ui/async-await/async-await-let-else.stderr @@ -0,0 +1,94 @@ +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:45:13 + | +LL | is_send(foo(Some(true))); + | ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:8:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await + | ^^^^^^ await occurs here, with `r` maybe used later +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:47:13 + | +LL | is_send(foo2(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo2` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:20:26 + | +LL | bar2(Rc::new(())).await + | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later + | | + | has type `Rc<()>` which is not `Send` +LL | }; + | - `Rc::new(())` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:49:13 + | +LL | is_send(foo3(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:30:28 + | +LL | (Rc::new(()), bar().await); + | ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later + | | + | has type `Rc<()>` which is not `Send` +note: `Rc::new(())` is later dropped here + --> $DIR/async-await-let-else.rs:30:35 + | +LL | (Rc::new(()), bar().await); + | ^ +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: future cannot be sent between threads safely + --> $DIR/async-await-let-else.rs:51:13 + | +LL | is_send(foo4(Some(true))); + | ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` +note: future is not `Send` as this value is used across an await + --> $DIR/async-await-let-else.rs:38:14 + | +LL | let r = Rc::new(()); + | - has type `Rc<()>` which is not `Send` +LL | bar().await; + | ^^^^^^ await occurs here, with `r` maybe used later +... +LL | }; + | - `r` is later dropped here +note: required by a bound in `is_send` + --> $DIR/async-await-let-else.rs:16:15 + | +LL | fn is_send(_: T) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 4 previous errors + From 24e87965ae35843fe340a5104482be1d1f827af7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 12 Jul 2022 07:22:52 +0000 Subject: [PATCH 25/31] Use some more visible sigils than `,` --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 9eed2ad361ce3..e82eaa38612cd 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -26,7 +26,7 @@ macro_rules! check_sizes { (check_one_specific_size: $ty:ty, $size:expr) => { const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; }; - ($ty:ty, $size:expr, $optioned_size:expr) => { + ($ty:ty: $size:expr => $optioned_size:expr) => { check_sizes!(check_one_specific_size: $ty, $size); check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size); check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty); @@ -41,30 +41,30 @@ macro_rules! check_sizes { const PTR_SIZE: usize = std::mem::size_of::<*const ()>(); -check_sizes!(Wrapper, 4, 8); -check_sizes!(Wrapper, 4, 4); // (✓ niche opt) -check_sizes!(Transparent, 4, 8); -check_sizes!(Transparent, 4, 4); // (✓ niche opt) -check_sizes!(NoNiche, 4, 8); -check_sizes!(NoNiche, 4, 8); +check_sizes!(Wrapper: 4 => 8); +check_sizes!(Wrapper: 4 => 4); // (✓ niche opt) +check_sizes!(Transparent: 4 => 8); +check_sizes!(Transparent: 4 => 4); // (✓ niche opt) +check_sizes!(NoNiche: 4 => 8); +check_sizes!(NoNiche: 4 => 8); -check_sizes!(UnsafeCell, 4, 8); -check_sizes!(UnsafeCell, 4, 8); +check_sizes!(UnsafeCell: 4 => 8); +check_sizes!(UnsafeCell: 4 => 8); -check_sizes!(UnsafeCell<&()> , PTR_SIZE, PTR_SIZE * 2); -check_sizes!( Cell<&()> , PTR_SIZE, PTR_SIZE * 2); -check_sizes!( RefCell<&()> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2); +check_sizes!( Cell<&()>: PTR_SIZE => PTR_SIZE * 2); +check_sizes!( RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3); check_sizes!(RwLock<&()>); check_sizes!(Mutex<&()>); -check_sizes!(UnsafeCell<&[i32]> , PTR_SIZE * 2, PTR_SIZE * 3); -check_sizes!(UnsafeCell<(&(), &())> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(UnsafeCell<&[i32]>: PTR_SIZE * 2 => PTR_SIZE * 3); +check_sizes!(UnsafeCell<(&(), &())>: PTR_SIZE * 2 => PTR_SIZE * 3); trait Trait {} -check_sizes!(UnsafeCell<&dyn Trait> , PTR_SIZE * 2, PTR_SIZE * 3); +check_sizes!(UnsafeCell<&dyn Trait>: PTR_SIZE * 2 => PTR_SIZE * 3); #[repr(simd)] pub struct Vec4([T; 4]); -check_sizes!(UnsafeCell> , 16, 32); +check_sizes!(UnsafeCell>: 16 => 32); From 726919629e0ca3660a41843f9565469e5dd2b2d9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 12 Jul 2022 07:29:36 +0000 Subject: [PATCH 26/31] Always check Cell alongside with `UnsafeCell` --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index e82eaa38612cd..fce101d7bb173 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -26,11 +26,23 @@ macro_rules! check_sizes { (check_one_specific_size: $ty:ty, $size:expr) => { const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>; }; + // Any tests run on `UnsafeCell` must be the same for `Cell` + (UnsafeCell<$ty:ty>: $size:expr => $optioned_size:expr) => { + check_sizes!(Cell<$ty>: $size => $optioned_size); + check_sizes!(@actual_check: UnsafeCell<$ty>: $size => $optioned_size); + }; ($ty:ty: $size:expr => $optioned_size:expr) => { + check_sizes!(@actual_check: $ty: $size => $optioned_size); + }; + // This branch does the actual checking logic, the `@actual_check` prefix is here to distinguish + // it from other branches and not accidentally match any. + (@actual_check: $ty:ty: $size:expr => $optioned_size:expr) => { check_sizes!(check_one_specific_size: $ty, $size); check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size); check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty); }; + // only check that there is no niche (size goes up when wrapped in an option), + // don't check actual sizes ($ty:ty) => { check_sizes!(check_no_niche_opt: true, $ty); }; @@ -52,7 +64,6 @@ check_sizes!(UnsafeCell: 4 => 8); check_sizes!(UnsafeCell: 4 => 8); check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2); -check_sizes!( Cell<&()>: PTR_SIZE => PTR_SIZE * 2); check_sizes!( RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3); check_sizes!(RwLock<&()>); From 947cbda5eb557ee3015b2310adfc80a393e42051 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Tue, 12 Jul 2022 13:24:08 +0200 Subject: [PATCH 27/31] fix the typo --- compiler/rustc_typeck/src/expr_use_visitor.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 53a456cf94643..9d7420acd2662 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -498,12 +498,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { f(self); if let Some(els) = els { // borrowing because we need to test the descriminant - // self.borrow_expr(expr, ImmBorrow); - self.maybe_read_scrutinee(expr, expr_place, from_ref(pat).iter()); + self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter()); self.walk_block(els) - } else { - self.walk_irrefutable_pat(&expr_place, &pat); } + self.walk_irrefutable_pat(&expr_place, &pat); } /// Indicates that the value of `blk` will be consumed, meaning either copied or moved From 9fcb9c6648331f372ee58ce4489d3d43a0723c59 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 12 Jul 2022 07:34:49 -0700 Subject: [PATCH 28/31] Update compiler/rustc_parse/src/parser/expr.rs Co-authored-by: Vadim Petrochenkov --- compiler/rustc_parse/src/parser/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f2765e4997ce4..52fefa2ebe590 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3012,7 +3012,7 @@ impl<'a> Parser<'a> { } }; - let is_shorthand = parsed_field.as_ref().map_or(false, |f| f.ident.span == f.expr.span); + let is_shorthand = parsed_field.as_ref().map_or(false, |f| f.is_shorthand); // A shorthand field can be turned into a full field with `:`. // We should point this out. self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon)); From 5188bdbccd6eaf0724d7237ce589454f3bec7026 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 13 Jul 2022 13:24:06 +0900 Subject: [PATCH 29/31] remove an unnecessary `span_to_snippet` --- .../src/diagnostics/conflict_errors.rs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 687ff0fb50580..0ceb63477c809 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1598,21 +1598,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let return_ty = tcx.erase_regions(return_ty); // to avoid panics - if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) { - if self + if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) + && self .infcx .type_implements_trait(iter_trait, return_ty, ty_params, self.param_env) .must_apply_modulo_regions() - { - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) { - err.span_suggestion_hidden( - return_span, - "use `.collect()` to allocate the iterator", - format!("{snippet}.collect::>()"), - Applicability::MaybeIncorrect, - ); - } - } + { + err.span_suggestion_hidden( + return_span.shrink_to_hi(), + "use `.collect()` to allocate the iterator", + ".collect::>()", + Applicability::MaybeIncorrect, + ); } } From f65bf0b2bb1a99f73095c01a118f3c37d3ee614c Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 13 Jul 2022 13:24:38 +0900 Subject: [PATCH 30/31] avoid `&str` to `String` conversions --- compiler/rustc_resolve/src/diagnostics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2851b08cd934e..a820f700869b2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -508,7 +508,7 @@ impl<'a> Resolver<'a> { E0401, "can't use generic parameters from outer function", ); - err.span_label(span, "use of generic parameter from outer function".to_string()); + err.span_label(span, "use of generic parameter from outer function"); let sm = self.session.source_map(); match outer_res { @@ -990,7 +990,7 @@ impl<'a> Resolver<'a> { E0735, "generic parameters cannot use `Self` in their defaults" ); - err.span_label(span, "`Self` in generic parameter default".to_string()); + err.span_label(span, "`Self` in generic parameter default"); err } ResolutionError::UnreachableLabel { name, definition_span, suggestion } => { From 519c07b3ce7f34975aacbe128e55d84411348229 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 13 Jul 2022 10:11:35 +0000 Subject: [PATCH 31/31] Limit test to x86 targets for reproducability --- src/test/ui/layout/unsafe-cell-hides-niche.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index fce101d7bb173..73b32066fadcd 100644 --- a/src/test/ui/layout/unsafe-cell-hides-niche.rs +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -5,6 +5,7 @@ // check-pass // compile-flags: --crate-type=lib +// only-x86 #![feature(repr_simd)]