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 | 52 +-- 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, 73 insertions(+), 512 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 ce7c0eb72cd..6673d75d99d 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 9dfdafcb38e..7616e7a63d1 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 0bf78446e37..48ca5913fab 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 6e5a0c813ac..770286599d2 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 b54f0ef361a..117bdad971a 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 be4843c7ff1..4ed9d9b27b2 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 bf7cb610a90..9972199c62e 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 f87b6e4212d..cef8a1dba7f 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 - } 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); - } + 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); + } + } + 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 3a795af2121..058cf1a4183 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 8c123c052e5..cd5357d796d 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 65a2a18e02f..43312105fd6 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 63c83ddb6f7..8a37fadc56f 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 093c7d29873..19775e7acda 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 4ca3f7a1aad..eb65756a5f6 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 2ce4dd56eab..809e0602671 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 a856de322c8..4607f684993 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 8872ee7119e..00000000000 --- 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 34fd417cc99..00000000000 --- 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 870eda89c20..00000000000 --- 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 9af929d4094..00000000000 --- 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 2e6064aeb00..00000000000 --- 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 a1ef32ae608..6bce5fbd4c1 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 4ed9d9b27b2..aca481df2e1 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 2c43563b104..36d63378550 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 9dbf26ef4b6..cf5c621020f 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 bc3358fc6ba..d526c9d0bcc 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 8a489e71990..451057c66a1 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 2c96dceb587..c6ae1ce674f 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 36d63378550..f2765e4997c 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 cf5c621020f..77335c64c21 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 d526c9d0bcc..4737bc71860 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 eb65756a5f6..f6a8e0de27a 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 cef8a1dba7f..6d87328ef5d 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 f6a8e0de27a..2d3bb1d23c0 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 6d87328ef5d..8cbc0169bc7 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 8cbc0169bc7..1ed41db099c 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 2d3bb1d23c0..bb2156a5da7 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 bb2156a5da7..385472ac88a 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 385472ac88a..f5c1fe1320c 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 f5c1fe1320c..7fb55d8219e 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 7fb55d8219e..21ff0cb1e55 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 | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 21ff0cb1e55..2833f49a27b 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<&()> , 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]> , 16); - assert_size!(Option>, 24); // (✗ niche opt) - assert_size!( UnsafeCell<(&(), &())> , 16); - assert_size!(Option>, 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 2833f49a27b..1d0e1fce178 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 9d2e12f9898..da6e7887006 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 58996a9db78..91c1fa6026c 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 913cf4eea13..c87d9a5406d 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 ce6c6e3215c..5b3b7db12b7 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 1e53c73d1bb..779bd3ea278 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 3fa8017dc93..a75383715a9 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 b2c23cda6aa..5a83a1f6cae 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 838980e08aa..016fafd3aec 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 00000000000..bb6201861df --- /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 00000000000..47386ffa4a8 --- /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 | 89 +++++++++---------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 1d0e1fce178..865fc2ae297 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>, 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!(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<&()> , 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) +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) +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]); +#[repr(simd)] +pub struct Vec4([T; 4]); - assert_size!( UnsafeCell> , 16); - assert_size!(Option>>, 32); // (✗ niche opt) -} +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 | 66 ++++++++----------- 1 file changed, 29 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 865fc2ae297..9e80a708f2f 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_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!(Option>, 8); -assert_size!(Option>, 8); // (✗ niche opt) +assert_size_eq!(UnsafeCell, 4, 8); +assert_size_eq!(UnsafeCell, 4, 8); -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!(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 9e80a708f2f..7f159887ba1 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 | 63 +++++++++---------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs index 7f159887ba1..9eed2ad361c 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); +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); -assert_size_eq!(UnsafeCell, 4, 8); -assert_size_eq!(UnsafeCell, 4, 8); +check_sizes!(UnsafeCell, 4, 8); +check_sizes!(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 } -); +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); -assert_size_eq!(UnsafeCell<&[i32]> , PTR_SIZE * 2, PTR_SIZE * 3); -assert_size_eq!(UnsafeCell<(&(), &())> , 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 9444fffc331..0ec596e7053 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 ddd54f7c208..05210e9b89e 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 fdf60e60914..6b420c42d61 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 04f585df34c..65cb5f77e06 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 531d9f14040..3585aba5f3d 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 50acb0270b0..7f860130873 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 4d29fc46946..ace30e61769 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 27f67207209..695d89e7912 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 00e96f20d1a..43c7ff3c4bb 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 b1b4229b1f7..41d8e5cf859 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 3e99ba5742a..85fc897c7ff 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 3fe6394ad7e..3e5f6bb8f0b 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 c8d09875c28..97249fdd175 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 a83328c0cab..cb8be51a085 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 1628f1a4b85..7067a48b783 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 59750d5d0b8..d77d74e25f6 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 75fd156ebfd..daaabd855c8 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 efa45883eab..c48aa9a90ef 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 d0723c68a77..f78c0f4f545 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 a3be827a7cc..d8e97e5adef 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 0070c0699a4..f125f107fe2 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 5560d44aa0d..05345f73ef6 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 6eb2f2d929d..2aaacad4ba4 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 3df4dfb74b3..29879c48b04 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 33585de6001..adbe71b83ed 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 58c01a34cad..5ae6ed4f72f 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 a7c7089234a..fcd610e677a 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 576dc6f127c..956f315f684 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 9f1368a3e07..54fb17734f4 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 41d241f84ac..b61ec13e388 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 920e3d578c8..12581286941 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 fdec7e7f6a7..065787cab08 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 b3da412ec28..3d647a4c05d 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 b961b16b6f6..05e45f68989 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 650f4ec5e77..56b9e073330 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 00000000000..624c2ea37a7 --- /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 4bcbeacf9fe..93ce3b30fb1 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 1deff9684a1..0b9fdb891b1 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 d99a1aa2969..7fe3443858a 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 fb418a3251f..0f374d12a84 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 27743a0ebec..e0986b710c5 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 5bf4313b41a..bd1ac3371b0 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 56bbbbbc819..5dcb86feb76 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 176787497eb..a37dfb7b715 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 ddaffc75188..ba0f01d9ed2 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 32de20f6531..c60d5518060 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 4801a84eb92..661af8fe642 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 45af6be2653..8c352494252 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 a5715975066..1abdfaac7ec 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 663246b4c86..3bfe5428133 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 b2a873ef582..cc8674a2006 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 4ac738272d0..80dbd14b2c5 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 be7df08d89f..2ad7ac60b92 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 a2419c277e9..de993c3c0a4 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 4db103bbc13..251181165b0 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 ff2999b1f4a..fa1c09d8f90 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 6598413c77e..105e145ac30 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 677ac998b56..c7f8f2f8d70 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 a4d265111f9..83e18e20711 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 9538a810473..8316efad1ff 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 65ed798867d..48bf14d511c 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 5ae04947b82..b2ec32abb44 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 2c8aa17e80d..3d7ef747a86 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 1885f3ca414..a8c96543c7c 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 353a6f6b899..2a7d5f2623e 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 9f4c5555f11..eab3b9b7b01 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 cf509455aad..80e7b8de392 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 2c8820eb7e1..99ac84fbaab 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 35db45e2b0c..c71bacfa29a 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 793e3cc58c2..0b5325adfed 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 1b32f0aaeb8..ac6490cfd2c 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 0ec596e7053..09fcdfc1c97 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 05210e9b89e..ddd54f7c208 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 6b420c42d61..4da3096f7c3 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 65cb5f77e06..c8a0ed39511 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 3585aba5f3d..ef1a30e142c 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 7f860130873..e3c97ec357e 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 ace30e61769..a0ec7f4fc6f 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 695d89e7912..27f67207209 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 43c7ff3c4bb..00e96f20d1a 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 41d8e5cf859..b1b4229b1f7 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 85fc897c7ff..3e99ba5742a 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 d77d74e25f6..4079470c255 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 daaabd855c8..5bd1fad0bcb 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 f78c0f4f545..d0723c68a77 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 d8e97e5adef..a3be827a7cc 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 f125f107fe2..eed3e1579a2 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 05345f73ef6..5560d44aa0d 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 2aaacad4ba4..a4175f4c5f3 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 adbe71b83ed..b08fc482186 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 fcd610e677a..097b9c3f0f7 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 956f315f684..859fc91f517 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 54fb17734f4..a1a92c62ad2 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 b61ec13e388..41d241f84ac 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 12581286941..a344404b970 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 93ce3b30fb1..4bcbeacf9fe 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 0b9fdb891b1..1deff9684a1 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 7fe3443858a..d99a1aa2969 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 0f374d12a84..fb418a3251f 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 e0986b710c5..27743a0ebec 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 bd1ac3371b0..5bf4313b41a 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 5dcb86feb76..56bbbbbc819 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 a37dfb7b715..176787497eb 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 ba0f01d9ed2..ddaffc75188 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 c60d5518060..32de20f6531 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 661af8fe642..4801a84eb92 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 8c352494252..ca617859db4 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 1abdfaac7ec..a5715975066 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 3bfe5428133..663246b4c86 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 cc8674a2006..3077b999f4e 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 80dbd14b2c5..4ac738272d0 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 2ad7ac60b92..be7df08d89f 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 de993c3c0a4..a2419c277e9 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 251181165b0..4db103bbc13 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 fa1c09d8f90..ff2999b1f4a 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 105e145ac30..819646bb678 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 c7f8f2f8d70..677ac998b56 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 83e18e20711..a4d265111f9 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 8316efad1ff..9538a810473 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 48bf14d511c..65ed798867d 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 b2ec32abb44..1d9a2abf706 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 3d7ef747a86..2c8aa17e80d 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 a8c96543c7c..1885f3ca414 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 2a7d5f2623e..353a6f6b899 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 eab3b9b7b01..9f4c5555f11 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 80e7b8de392..cf509455aad 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 99ac84fbaab..2c8820eb7e1 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 c71bacfa29a..35db45e2b0c 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 0b5325adfed..942f14ddd3d 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 ac6490cfd2c..1b32f0aaeb8 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 09fcdfc1c97..7cbfe143b4d 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 a344404b970..53a456cf946 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 c8a0ed39511..ed874ae829b 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 ef1a30e142c..b5d9769c578 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 a0ec7f4fc6f..4d29fc46946 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 4079470c255..dccaa61ed89 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 097b9c3f0f7..60ee2233ed9 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 859fc91f517..8f34a970f6f 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 00000000000..7ea07ae9add --- /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 00000000000..4d23e27c426 --- /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 9eed2ad361c..e82eaa38612 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 e82eaa38612..fce101d7bb1 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 53a456cf946..9d7420acd26 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 f2765e4997c..52fefa2ebe5 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 687ff0fb505..0ceb63477c8 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 2851b08cd93..a820f700869 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 fce101d7bb1..73b32066fad 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)]