diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e23128c1a491f..5d6821d3f3b44 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1707,6 +1707,10 @@ impl DotDotPos { pub fn as_opt_usize(&self) -> Option { if self.0 == u32::MAX { None } else { Some(self.0 as usize) } } + + pub fn is_some(&self) -> bool { + self.0 != u32::MAX + } } impl fmt::Debug for DotDotPos { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7413215b15ba1..a8bb740e61483 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1835,7 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check subpatterns. if subpats.len() == variant.fields.len() - || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some() + || subpats.len() < variant.fields.len() && ddpos.is_some() { let ty::Adt(_, args) = pat_ty.kind() else { bug!("unexpected pattern type {:?}", pat_ty); @@ -2041,7 +2041,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); - if ddpos.as_opt_usize().is_some() { + if ddpos.is_some() { // Require known type only when `..` is present. if let ty::Tuple(tys) = self.structurally_resolve_type(span, expected).kind() { expected_len = tys.len(); diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index e16f91f656386..f9f1937f77021 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -804,6 +804,9 @@ pub enum PatKind<'tcx> { /// a single variant. Leaf { subpatterns: Vec>, + /// Whether this leaf pattern contains a rest pattern `..`. + /// Used in unsafety checking of union field patterns + has_rest: bool, }, /// Explicit or implicit `&P` or `&mut P`, for some subpattern `P`. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index c76e993f92f7d..78988e8e79160 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -253,10 +253,9 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( if let PatKind::Guard { subpattern, condition } = &pat.kind { visitor.visit_pat(subpattern); visitor.visit_expr(&visitor.thir()[*condition]); - return; - }; - - for_each_immediate_subpat(pat, |p| visitor.visit_pat(p)); + } else { + for_each_immediate_subpat(pat, |p| visitor.visit_pat(p)); + } } /// Invokes `callback` on each immediate subpattern of `pat`, if any. @@ -279,7 +278,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( | PatKind::Deref { subpattern, .. } | PatKind::DerefPattern { subpattern, .. } => callback(subpattern), - PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => { + PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns, .. } => { for field_pat in subpatterns { callback(&field_pat.pattern); } diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 7ad21b3272783..89c4053b2d14d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -406,7 +406,7 @@ impl<'tcx> InterPat<'tcx> { } } - PatKind::Leaf { ref subpatterns } => { + PatKind::Leaf { ref subpatterns, .. } => { let mut subpats = vec![]; for &FieldPat { field, pattern: ref subpat } in subpatterns { let subplace = place_builder.clone_project(PlaceElem::Field(field, subpat.ty)); diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index a520acda5e6c8..170bc52a036da 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -904,7 +904,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f); } - PatKind::Leaf { ref subpatterns } => { + PatKind::Leaf { ref subpatterns, .. } => { for subpattern in subpatterns { let subpattern_user_tys = user_tys.leaf(subpattern.field); debug!("visit_primary_bindings: subpattern_user_tys={subpattern_user_tys:?}"); diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index c2366b78a7786..37701a56883b4 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -258,34 +258,73 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { // match is conditional on having this value | PatKind::Constant { .. } | PatKind::Variant { .. } - | PatKind::Leaf { .. } | PatKind::Deref { .. } | PatKind::DerefPattern { .. } | PatKind::Range { .. } | PatKind::Slice { .. } - | PatKind::Array { .. } - | PatKind::Guard { .. } // Never constitutes a witness of uninhabitedness. | PatKind::Never => { self.requires_unsafe(pat.span, AccessToUnionField); return; // we can return here since this already requires unsafe } // wildcard doesn't read anything. - PatKind::Wild | + PatKind::Wild // these just wrap other patterns, which we recurse on below. - PatKind::Or { .. } | - PatKind::Error(_) => {} + | PatKind::Or { .. } + | PatKind::Leaf { .. } // We do extra checks below for patterns lowered from consts + | PatKind::Array { .. } + | PatKind::Guard { .. } + | PatKind::Error(_) => {} } }; match &pat.kind { - PatKind::Leaf { subpatterns, .. } => { + PatKind::Leaf { subpatterns, has_rest } => { if let ty::Adt(adt_def, ..) = pat.ty.kind() { - for pat in subpatterns { - if adt_def.non_enum_variant().fields[pat.field].safety.is_unsafe() { - self.requires_unsafe(pat.pattern.span, UseOfUnsafeField); + let single_variant = adt_def.non_enum_variant(); + + let scope = self.tcx.parent_module(self.hir_context).to_def_id(); + + if self.in_union_destructure + && !has_rest + && ( + // Check if we are matching against a foreign `non_exhaustive` struct + // without a rest pattern. + // (This is only possible in patterns lowered from constants.) + single_variant.field_list_has_applicable_non_exhaustive() + // Check if we are matching against a struct containing inaccessible private fields + // without a rest pattern. + // (This is only possible in patterns lowered from constants.) + || adt_def.is_struct() + && single_variant + .fields + .iter() + .any(|f| !f.vis.is_accessible_from(scope, self.tcx)) + ) + { + // Ensure we don't expose private implementation details of the const. + self.requires_unsafe(pat.span, AccessToUnionField); + return; + } + + for subpat in subpatterns { + let field = &single_variant.fields[subpat.field]; + + // This assert should always pass, because union constants can't be used as patterns, + // and struct constants are handled by the check above. + // But maybe with e.g. some weird future macro hygiene feature, there could be new ways + // of referencing inaccessible private fields from a pattern. + // So let's assert just in case. + debug_assert!( + !(self.in_union_destructure + && !field.vis.is_accessible_from(scope, self.tcx)) + ); + + if field.safety.is_unsafe() { + self.requires_unsafe(subpat.pattern.span, UseOfUnsafeField); } } + if adt_def.is_union() { let old_in_union_destructure = std::mem::replace(&mut self.in_union_destructure, true); @@ -334,6 +373,14 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_pat(self, pat); self.inside_adt = old_inside_adt; } + PatKind::Guard { subpattern, condition } => { + self.visit_pat(subpattern); + + let old_in_union_destructure = + std::mem::replace(&mut self.in_union_destructure, false); + self.visit_expr(&self.thir()[*condition]); + self.in_union_destructure = old_in_union_destructure; + } _ => { visit::walk_pat(self, pat); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 7c6885bf8020c..7432dcd9938e7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -393,12 +393,14 @@ impl<'tcx> ConstToPat<'tcx> { subpatterns: self.lower_field_values_to_fieldpats( valtree.to_branch().iter().map(|ct| ct.to_value()), ), + has_rest: false, } } ty::Tuple(_) => PatKind::Leaf { subpatterns: self.lower_field_values_to_fieldpats( valtree.to_branch().iter().map(|ct| ct.to_value()), ), + has_rest: false, }, ty::Slice(_) => PatKind::Slice { prefix: valtree diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index d64f98542b3a3..656e00240452e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -361,7 +361,7 @@ impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> { span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty); }; let subpatterns = self.lower_tuple_subpats(pats, tys.len(), ddpos); - PatKind::Leaf { subpatterns } + PatKind::Leaf { subpatterns, has_rest: ddpos.is_some() } } hir::PatKind::Binding(explicit_ba, id, ident, sub) => { @@ -420,10 +420,10 @@ impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> { }; let variant_def = adt_def.variant_of_res(res); let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos); - return self.lower_variant_or_leaf(pat, None, res, subpatterns); + return self.lower_variant_or_leaf(pat, None, res, subpatterns, ddpos.is_some()); } - hir::PatKind::Struct(ref qpath, fields, _) => { + hir::PatKind::Struct(ref qpath, fields, rest) => { let res = self.typeck_results.qpath_res(qpath, pat.hir_id); let subpatterns = fields .iter() @@ -437,7 +437,7 @@ impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> { }) .collect(); - return self.lower_variant_or_leaf(pat, None, res, subpatterns); + return self.lower_variant_or_leaf(pat, None, res, subpatterns, rest.is_some()); } hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) }, @@ -513,6 +513,7 @@ impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> { expr: Option<&'tcx hir::PatExpr<'tcx>>, res: Res, subpatterns: Vec>, + has_rest: bool, ) -> Box> { // Check whether the caller should have provided an `expr` for this pattern kind. assert_matches!( @@ -563,7 +564,7 @@ impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> { subpatterns, } } else { - PatKind::Leaf { subpatterns } + PatKind::Leaf { subpatterns, has_rest } } } @@ -577,7 +578,7 @@ impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> { ) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } - | Res::SelfCtor(..) => PatKind::Leaf { subpatterns }, + | Res::SelfCtor(..) => PatKind::Leaf { subpatterns, has_rest }, _ => { let e = match res { Res::Def(DefKind::ConstParam, def_id) => { @@ -645,7 +646,7 @@ impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> { _ => { // The path isn't the name of a constant, so it must actually // be a unit struct or unit variant (e.g. `Option::None`). - return self.lower_variant_or_leaf(pat, Some(expr), res, vec![]); + return self.lower_variant_or_leaf(pat, Some(expr), res, vec![], false); } }; diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 7cfd313218d33..68ed29fcd1e99 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -769,13 +769,14 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "}", depth_lvl + 1); } - PatKind::Leaf { subpatterns } => { + PatKind::Leaf { subpatterns, has_rest } => { print_indented!(self, "Leaf { ", depth_lvl + 1); print_indented!(self, "subpatterns: [", depth_lvl + 2); for field_pat in subpatterns.iter() { self.print_pat(&field_pat.pattern, depth_lvl + 3); } print_indented!(self, "]", depth_lvl + 2); + print_indented!(self, format!("has_rest: {has_rest:?}"), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } PatKind::Deref { pin, subpattern } => { diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d030756cfa954..aa4308e48b8f9 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -501,7 +501,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ctor = DerefPattern(cx.reveal_opaque_ty(subpattern.ty)); self.internal_state.has_lowered_deref_pat.set(true); } - PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { + PatKind::Leaf { subpatterns, .. } | PatKind::Variant { subpatterns, .. } => { match ty.kind() { ty::Tuple(fs) => { ctor = Struct; diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/union.rs b/tests/ui/pattern/rfc-3637-guard-patterns/union.rs new file mode 100644 index 0000000000000..2699f0b2ca620 --- /dev/null +++ b/tests/ui/pattern/rfc-3637-guard-patterns/union.rs @@ -0,0 +1,17 @@ +//@ run-pass +//! Test that guard patterns in union fields don't impose an `unsafe` requirement. + +#![feature(guard_patterns)] +#![expect(incomplete_features)] + +union Foo { + field: u8, +} + +fn main() { + let foo = Foo { field: 42 }; + match foo { + Foo { field: _ if matches!(1, 1) } => (), + _ => panic!(), //~ WARN unreachable + } +} diff --git a/tests/ui/pattern/rfc-3637-guard-patterns/union.stderr b/tests/ui/pattern/rfc-3637-guard-patterns/union.stderr new file mode 100644 index 0000000000000..ff56662f641c9 --- /dev/null +++ b/tests/ui/pattern/rfc-3637-guard-patterns/union.stderr @@ -0,0 +1,12 @@ +warning: unreachable pattern + --> $DIR/union.rs:15:9 + | +LL | Foo { field: _ if matches!(1, 1) } => (), + | ---------------------------------- matches all the relevant values +LL | _ => panic!(), + | ^ no value can reach this + | + = note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default + +warning: 1 warning emitted + diff --git a/tests/ui/union/auxiliary/zst-const.rs b/tests/ui/union/auxiliary/zst-const.rs new file mode 100644 index 0000000000000..cf02440973d21 --- /dev/null +++ b/tests/ui/union/auxiliary/zst-const.rs @@ -0,0 +1,32 @@ +#[derive(Clone, Copy, PartialEq)] +pub struct HasPrivateField { + not_pub: (), +} + +pub const HAS_PRIVATE_FIELD: HasPrivateField = HasPrivateField { not_pub: () }; + +#[derive(Clone, Copy, PartialEq)] +#[non_exhaustive] +pub struct HasNonExhaustiveFieldList {} + +pub const HAS_NON_EXHAUSTIVE_FIELD_LIST: HasNonExhaustiveFieldList = HasNonExhaustiveFieldList {}; + +#[derive(Clone, Copy, PartialEq)] +pub struct HasPrivateTupleField(()); + +pub const HAS_PRIVATE_TUPLE_FIELD: HasPrivateTupleField = HasPrivateTupleField(()); + +#[derive(Clone, Copy, PartialEq)] +#[non_exhaustive] +pub struct HasNonExhaustiveTupleFieldList(); + +pub const HAS_NON_EXHAUSTIVE_TUPLE_FIELD_LIST: HasNonExhaustiveTupleFieldList = + HasNonExhaustiveTupleFieldList(); + +pub const NESTED_CONST: (HasPrivateField,) = (HAS_PRIVATE_FIELD,); + +#[derive(Clone, Copy)] +pub union MixedVisibilityUnion { + pub zst: (), + not_pub: u8, +} diff --git a/tests/ui/union/union.rs b/tests/ui/union/union.rs index ae81708aa191c..8cc0599c9ebde 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -1,12 +1,32 @@ +//@ aux-build: zst-const.rs + +extern crate zst_const; +use zst_const::{ + HAS_NON_EXHAUSTIVE_FIELD_LIST, HAS_NON_EXHAUSTIVE_TUPLE_FIELD_LIST, HAS_PRIVATE_FIELD, + HAS_PRIVATE_TUPLE_FIELD, HasNonExhaustiveFieldList, HasNonExhaustiveTupleFieldList, + HasPrivateField, HasPrivateTupleField, MixedVisibilityUnion, NESTED_CONST, +}; + union Foo { bar: i8, zst: (), + tuple: (i32,), pizza: Pizza, + tuple_struct: TupleStruct, + array: [u32; 2], + single_variant_enum: SingleVariant, + has_private_field: HasPrivateField, + has_non_exhaustive_field_list: HasNonExhaustiveFieldList, + has_private_tuple_field: HasPrivateTupleField, + has_non_exhaustive_tuple_field_list: HasNonExhaustiveTupleFieldList, + local_non_exhaustive_field_list: LocalNonExhaustiveFieldList, + nested_const: (HasPrivateField,), + mixed_visibility_union: MixedVisibilityUnion, } #[derive(Clone, Copy)] struct Pizza { - topping: Option + topping: Option, } #[allow(dead_code)] @@ -16,34 +36,134 @@ enum PizzaTopping { Pineapple, } +#[derive(Clone, Copy)] +struct TupleStruct(i32); + +#[derive(Clone, Copy)] +enum SingleVariant { + Single {}, +} + +#[derive(Clone, Copy, PartialEq)] +#[non_exhaustive] +pub struct LocalNonExhaustiveFieldList {} + +pub const LOCAL_NON_EXHAUSTIVE_FIELD_LIST: LocalNonExhaustiveFieldList = + LocalNonExhaustiveFieldList {}; + fn do_nothing(_x: &mut Foo) {} +const UNIT: () = (); + pub fn main() { let mut foo = Foo { bar: 5 }; do_nothing(&mut foo); // This is UB, so this test isn't run match foo { - Foo { bar: _a } => {}, //~ ERROR access to union field is unsafe + Foo { bar: _a } => {} //~ ERROR access to union field is unsafe } match foo { Foo { - pizza: Pizza { //~ ERROR access to union field is unsafe - topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None - } - } => {}, + pizza: + Pizza { + topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, + //~^ ERROR access to union field is unsafe + //~| ERROR access to union field is unsafe + //~| ERROR access to union field is unsafe + }, + } => {} + } + match foo { + Foo { + pizza: + Pizza { + topping: Some { .. } + //~^ ERROR access to union field is unsafe + }, + } => {} + _ => {} + } + match foo { + Foo { tuple: (_a,) } => {} //~ ERROR access to union field is unsafe + } + match foo { + Foo { tuple_struct: TupleStruct(_a) } => {} //~ ERROR access to union field is unsafe + } + match foo { + Foo { array: [_a, _] } => {} //~ ERROR access to union field is unsafe + } + match foo { + Foo { single_variant_enum: SingleVariant::Single {} } => {} //~ ERROR access to union field is unsafe + } + + // Known bug (#162213): these matches should also be considered non-exhaustive + match foo { + Foo { has_private_field: HAS_PRIVATE_FIELD } => {} //~ ERROR access to union field is unsafe + } + match foo { + Foo { has_non_exhaustive_field_list: HAS_NON_EXHAUSTIVE_FIELD_LIST } => {} //~ ERROR access to union field is unsafe + } + match foo { + Foo { has_private_tuple_field: HAS_PRIVATE_TUPLE_FIELD } => {} //~ ERROR access to union field is unsafe + } + match foo { + Foo { has_non_exhaustive_tuple_field_list: HAS_NON_EXHAUSTIVE_TUPLE_FIELD_LIST } => {} //~ ERROR access to union field is unsafe + } + match foo { + Foo { has_non_exhaustive_tuple_field_list: HAS_NON_EXHAUSTIVE_TUPLE_FIELD_LIST } => {} //~ ERROR access to union field is unsafe + } + match foo { + Foo { nested_const: NESTED_CONST } => {} //~ ERROR access to union field is unsafe } + // binding to a tuple, struct, or array pattern is okay if no fields are read + match foo { + Foo { zst: () } => {} + } + match foo { + Foo { zst: (..) } => {} + } + match foo { + Foo { zst: UNIT } => {} + } + match foo { + Foo { tuple: (..) } => {} + } + match foo { + Foo { tuple: (_,) } => {} + } + match foo { + Foo { pizza: Pizza { .. } } => {} + } + match foo { + Foo { pizza: Pizza { topping: _ } } => {} + } + match foo { + Foo { tuple_struct: TupleStruct(_) } => {} + } + match foo { + Foo { array: [..] } => {} + } + match foo { + Foo { array: [_, _] } => {} + } + match foo { + Foo { has_private_field: HasPrivateField { .. } } => {} + } + match foo { + Foo { has_non_exhaustive_field_list: HasNonExhaustiveFieldList { .. } } => {} + } match foo { - Foo { zst: () } => {} //~ ERROR access to union field is unsafe + Foo { local_non_exhaustive_field_list: LOCAL_NON_EXHAUSTIVE_FIELD_LIST } => {} } match foo { - Foo { pizza: Pizza { .. } } => {} //~ ERROR access to union field is unsafe + Foo { mixed_visibility_union: MixedVisibilityUnion { zst: () } } => {} } // binding to wildcard is okay match foo { - Foo { bar: _ } => {}, + Foo { bar: _ } => {} } let Foo { bar: _ } = foo; } diff --git a/tests/ui/union/union.stderr b/tests/ui/union/union.stderr index 1506bdb919bda..5c42780ce7b46 100644 --- a/tests/ui/union/union.stderr +++ b/tests/ui/union/union.stderr @@ -1,38 +1,123 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:27:20 + --> $DIR/union.rs:64:20 | -LL | Foo { bar: _a } => {}, +LL | Foo { bar: _a } => {} | ^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:31:20 + --> $DIR/union.rs:70:30 | -LL | pizza: Pizza { - | ____________________^ -LL | | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None -LL | | } - | |_____________^ access to union field +LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:38:20 + --> $DIR/union.rs:70:59 | -LL | Foo { zst: () } => {} - | ^^ access to union field +LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:70:91 + | +LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, + | ^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:81:30 + | +LL | topping: Some { .. } + | ^^^^^^^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:88:23 + | +LL | Foo { tuple: (_a,) } => {} + | ^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:91:41 + | +LL | Foo { tuple_struct: TupleStruct(_a) } => {} + | ^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:94:23 + | +LL | Foo { array: [_a, _] } => {} + | ^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:97:36 + | +LL | Foo { single_variant_enum: SingleVariant::Single {} } => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:102:34 + | +LL | Foo { has_private_field: HAS_PRIVATE_FIELD } => {} + | ^^^^^^^^^^^^^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:105:46 + | +LL | Foo { has_non_exhaustive_field_list: HAS_NON_EXHAUSTIVE_FIELD_LIST } => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:108:40 + | +LL | Foo { has_private_tuple_field: HAS_PRIVATE_TUPLE_FIELD } => {} + | ^^^^^^^^^^^^^^^^^^^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:111:52 + | +LL | ... Foo { has_non_exhaustive_tuple_field_list: HAS_NON_EXHAUSTIVE_TUPLE_FIELD_LIST } => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:114:52 + | +LL | ... Foo { has_non_exhaustive_tuple_field_list: HAS_NON_EXHAUSTIVE_TUPLE_FIELD_LIST } => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:41:22 + --> $DIR/union.rs:117:29 | -LL | Foo { pizza: Pizza { .. } } => {} - | ^^^^^^^^^^^^ access to union field +LL | Foo { nested_const: NESTED_CONST } => {} + | ^^^^^^^^^^^^ access to union field | = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior -error: aborting due to 4 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/union/union_destructure.rs b/tests/ui/union/union_destructure.rs index 9c445c9986296..c93e54a669ffa 100644 --- a/tests/ui/union/union_destructure.rs +++ b/tests/ui/union/union_destructure.rs @@ -32,17 +32,14 @@ fn main() { }; let u = Foo { bar: 9 }; - unsafe { - match u { - Foo { baz: Pie { .. } } => {} - }; - } + match u { + Foo { baz: Pie { .. } } => {} + }; + let u = Foo { bar: 10 }; - unsafe { - match u { - Foo { baz: Pie { slices: _, size: _ } } => {} - }; - } + match u { + Foo { baz: Pie { slices: _, size: _ } } => {} + }; let u = Foo { bar: 11 }; match u {