diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index e44a440b5c13c..a44afed5492d3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -319,9 +319,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } PatKind::Deref { subpattern } } - hir::PatKind::Box(subpattern) => { - PatKind::Deref { subpattern: self.lower_pattern(subpattern) } - } + hir::PatKind::Box(subpattern) => PatKind::DerefPattern { + subpattern: self.lower_pattern(subpattern), + borrow: hir::ByRef::No, + }, hir::PatKind::Slice(prefix, slice, suffix) => { self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix) diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 46ced7500ea20..e53cebc59baf3 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -221,27 +221,19 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let slice = match ctor { Struct | Variant(_) | UnionField => match ty.kind() { ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()), - ty::Adt(adt, args) => { - if adt.is_box() { - // The only legal patterns of type `Box` (outside `std`) are `_` and box - // patterns. If we're here we can assume this is a box pattern. - reveal_and_alloc(cx, once(args.type_at(0))) - } else { - let variant = - &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt)); - let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| { - let is_visible = - adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(*ty); - let is_unstable = - cx.tcx.lookup_stability(field.did).is_some_and(|stab| { - stab.is_unstable() && stab.feature != sym::rustc_private - }); - let skip = is_uninhabited && (!is_visible || is_unstable); - (ty, PrivateUninhabitedField(skip)) + ty::Adt(adt, _) => { + let variant = &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt)); + let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| { + let is_visible = + adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); + let is_uninhabited = cx.is_uninhabited(*ty); + let is_unstable = cx.tcx.lookup_stability(field.did).is_some_and(|stab| { + stab.is_unstable() && stab.feature != sym::rustc_private }); - cx.dropless_arena.alloc_from_iter(tys) - } + let skip = is_uninhabited && (!is_visible || is_unstable); + (ty, PrivateUninhabitedField(skip)) + }); + cx.dropless_arena.alloc_from_iter(tys) } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, @@ -273,14 +265,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { Struct | Variant(_) | UnionField => match ty.kind() { ty::Tuple(fs) => fs.len(), ty::Adt(adt, ..) => { - if adt.is_box() { - // The only legal patterns of type `Box` (outside `std`) are `_` and box - // patterns. If we're here we can assume this is a box pattern. - 1 - } else { - let variant_idx = RustcPatCtxt::variant_index_for_adt(&ctor, *adt); - adt.variant(variant_idx).fields.len() - } + let variant_idx = RustcPatCtxt::variant_index_for_adt(&ctor, *adt); + adt.variant(variant_idx).fields.len() } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, @@ -470,8 +456,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { fields = vec![self.lower_pat(subpattern).at_index(0)]; arity = 1; ctor = match ty.kind() { - // This is a box pattern. - ty::Adt(adt, ..) if adt.is_box() => Struct, ty::Ref(..) => Ref, _ => span_bug!( pat.span, @@ -501,28 +485,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index())) .collect(); } - ty::Adt(adt, _) if adt.is_box() => { - // The only legal patterns of type `Box` (outside `std`) are `_` and box - // patterns. If we're here we can assume this is a box pattern. - // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_, - // _)` or a box pattern. As a hack to avoid an ICE with the former, we - // ignore other fields than the first one. This will trigger an error later - // anyway. - // See https://github.com/rust-lang/rust/issues/82772, - // explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977 - // The problem is that we can't know from the type whether we'll match - // normally or through box-patterns. We'll have to figure out a proper - // solution when we introduce generalized deref patterns. Also need to - // prevent mixing of those two options. - let pattern = subpatterns.into_iter().find(|pat| pat.field.index() == 0); - if let Some(pat) = pattern { - fields = vec![self.lower_pat(&pat.pattern).at_index(0)]; - } else { - fields = vec![]; - } - ctor = Struct; - arity = 1; - } ty::Adt(adt, _) => { ctor = match pat.kind { PatKind::Leaf { .. } if adt.is_union() => UnionField, @@ -825,11 +787,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { Bool(b) => b.to_string(), Str(s) => s.to_string(), IntRange(range) => return self.print_pat_range(range, *pat.ty()), - Struct if pat.ty().is_box() => { - // Outside of the `alloc` crate, the only way to create a struct pattern - // of type `Box` is to use a `box` pattern via #[feature(box_patterns)]. - format!("box {}", print(&pat.fields[0])) - } Struct | Variant(_) | UnionField => { let enum_info = match *pat.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_enum() => EnumInfo::Enum { @@ -866,6 +823,14 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap(); s } + DerefPattern(_) if pat.ty().is_box() && !self.tcx.features().deref_patterns() => { + // FIXME(deref_patterns): Remove this special handling once `box_patterns` is gone. + // HACK(@dianne): `box _` syntax is exposed on stable in diagnostics, e.g. to + // witness non-exhaustiveness of `match Box::new(0) { Box { .. } if false => {} }`. + // To avoid changing diagnostics before deref pattern syntax is finalized, let's use + // `box _` syntax unless `deref_patterns` is enabled. + format!("box {}", print(&pat.fields[0])) + } DerefPattern(_) => format!("deref!({})", print(&pat.fields[0])), Slice(slice) => { let (prefix_len, has_dot_dot) = match slice.kind { @@ -964,12 +929,8 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { ty: &Self::Ty, ) -> fmt::Result { if let ty::Adt(adt, _) = ty.kind() { - if adt.is_box() { - write!(f, "Box")? - } else { - let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt)); - write!(f, "{}", variant.name)?; - } + let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt)); + write!(f, "{}", variant.name)?; } Ok(()) } diff --git a/tests/ui/uninhabited/uninhabited-patterns.rs b/tests/ui/uninhabited/uninhabited-patterns.rs index b7429464fa5a0..1f30af2acc697 100644 --- a/tests/ui/uninhabited/uninhabited-patterns.rs +++ b/tests/ui/uninhabited/uninhabited-patterns.rs @@ -27,7 +27,11 @@ fn main() { let x: Result, &[Result]> = Err(&[]); match x { - Ok(box _) => (), //~ ERROR unreachable pattern + Ok(box _) => (), // We'd get a non-exhaustiveness error if this arm was removed; don't lint. + Err(&[]) => (), + Err(&[..]) => (), + } + match x { //~ ERROR non-exhaustive patterns Err(&[]) => (), Err(&[..]) => (), } diff --git a/tests/ui/uninhabited/uninhabited-patterns.stderr b/tests/ui/uninhabited/uninhabited-patterns.stderr index 7a872767d959a..62113c82a3648 100644 --- a/tests/ui/uninhabited/uninhabited-patterns.stderr +++ b/tests/ui/uninhabited/uninhabited-patterns.stderr @@ -1,21 +1,23 @@ -error: unreachable pattern - --> $DIR/uninhabited-patterns.rs:30:9 +error[E0004]: non-exhaustive patterns: `Ok(_)` not covered + --> $DIR/uninhabited-patterns.rs:34:11 | -LL | Ok(box _) => (), - | ^^^^^^^^^------- - | | - | matches no values because `NotSoSecretlyEmpty` is uninhabited - | help: remove the match arm +LL | match x { + | ^ pattern `Ok(_)` not covered | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types -note: the lint level is defined here - --> $DIR/uninhabited-patterns.rs:4:9 +note: `Result, &[Result]>` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result, &[Result]>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Err(&[..]) => (), +LL ~ Ok(_) => todo!(), | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/uninhabited-patterns.rs:39:9 + --> $DIR/uninhabited-patterns.rs:43:9 | LL | Err(Ok(_y)) => (), | ^^^^^^^^^^^------- @@ -24,9 +26,14 @@ LL | Err(Ok(_y)) => (), | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types +note: the lint level is defined here + --> $DIR/uninhabited-patterns.rs:4:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/uninhabited-patterns.rs:42:15 + --> $DIR/uninhabited-patterns.rs:46:15 | LL | while let Some(_y) = foo() { | ^^^^^^^^ matches no values because `NotSoSecretlyEmpty` is uninhabited @@ -35,3 +42,4 @@ LL | while let Some(_y) = foo() { error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0004`.