From e347fa646d69ed98684d1ad2f99ebb7efbabc542 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 25 Aug 2026 11:28:49 -0400 Subject: [PATCH 01/10] Don't require `unsafe` for `PatKind::Leaf` against union fields These patterns don't access the union directly, only their subpatterns do. So there is no need to require `unsafe`. --- .../rustc_mir_build/src/check_unsafety.rs | 10 ++-- tests/ui/union/union.rs | 49 +++++++++++++++---- tests/ui/union/union.stderr | 43 ++++++++++------ tests/ui/union/union_destructure.rs | 17 +++---- 4 files changed, 80 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index c2366b78a7786..524081d20dbf4 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -258,7 +258,6 @@ 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 { .. } @@ -271,10 +270,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { return; // we can return here since this already requires unsafe } // wildcard doesn't read anything. - PatKind::Wild | - // these just wrap other patterns, which we recurse on below. - PatKind::Or { .. } | - PatKind::Error(_) => {} + PatKind::Wild + // these two just wrap other patterns, which we recurse on below. + | PatKind::Or { .. } + | PatKind::Leaf { .. } + | PatKind::Error(_) => {} } }; diff --git a/tests/ui/union/union.rs b/tests/ui/union/union.rs index ae81708aa191c..e0c469bdb058f 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -1,12 +1,14 @@ union Foo { bar: i8, zst: (), + tuple: (i32,), pizza: Pizza, + tuple_struct: TupleStruct, } #[derive(Clone, Copy)] struct Pizza { - topping: Option + topping: Option, } #[allow(dead_code)] @@ -16,6 +18,9 @@ enum PizzaTopping { Pineapple, } +#[derive(Clone, Copy)] +struct TupleStruct(i32); + fn do_nothing(_x: &mut Foo) {} pub fn main() { @@ -24,26 +29,52 @@ pub fn main() { // 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 { tuple: (_a,) } => {} //~ ERROR access to union field is unsafe + } + match foo { + Foo { tuple_struct: TupleStruct(_a) } => {} //~ ERROR access to union field is unsafe } + // binding to a struct pattern is okay if no fields are read + match foo { + Foo { zst: () } => {} + } + match foo { + Foo { zst: (..) } => {} + } + match foo { + Foo { tuple: (..) } => {} + } + match foo { + Foo { tuple: (_,) } => {} + } + match foo { + Foo { pizza: Pizza { .. } } => {} + } match foo { - Foo { zst: () } => {} //~ ERROR access to union field is unsafe + Foo { pizza: Pizza { topping: _ } } => {} } match foo { - Foo { pizza: Pizza { .. } } => {} //~ ERROR access to union field is unsafe + Foo { tuple_struct: TupleStruct(_) } => {} } // 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..d9264131fa35c 100644 --- a/tests/ui/union/union.stderr +++ b/tests/ui/union/union.stderr @@ -1,38 +1,51 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:27:20 + --> $DIR/union.rs:32: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:38: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:38: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:38: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:46: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:41:22 + --> $DIR/union.rs:49:41 | -LL | Foo { pizza: Pizza { .. } } => {} - | ^^^^^^^^^^^^ access to union field +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: aborting due to 4 previous errors +error: aborting due to 6 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 { From 43da42dc82992ef64567bee8465e2bc76b4c02e2 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 25 Aug 2026 12:05:01 -0400 Subject: [PATCH 02/10] Don't require `unsafe` for guard patterns --- compiler/rustc_mir_build/src/check_unsafety.rs | 4 ++-- .../ui/pattern/rfc-3637-guard-patterns/union.rs | 17 +++++++++++++++++ .../rfc-3637-guard-patterns/union.stderr | 12 ++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/ui/pattern/rfc-3637-guard-patterns/union.rs create mode 100644 tests/ui/pattern/rfc-3637-guard-patterns/union.stderr diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 524081d20dbf4..8141421f6bea4 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -263,7 +263,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | PatKind::Range { .. } | PatKind::Slice { .. } | PatKind::Array { .. } - | PatKind::Guard { .. } // Never constitutes a witness of uninhabitedness. | PatKind::Never => { self.requires_unsafe(pat.span, AccessToUnionField); @@ -271,9 +270,10 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } // wildcard doesn't read anything. PatKind::Wild - // these two just wrap other patterns, which we recurse on below. + // these just wrap other patterns, which we recurse on below. | PatKind::Or { .. } | PatKind::Leaf { .. } + | PatKind::Guard { .. } | PatKind::Error(_) => {} } }; 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..a84a686904360 --- /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 true } => (), + _ => 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..34bf194e80f86 --- /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 true } => (), + | ------------------------ 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 + From cd1d1aa41a0463c8f5063a20c7040d6940081608 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 25 Aug 2026 12:18:21 -0400 Subject: [PATCH 03/10] Don't require unsafe for `PatKind::Array` against union fields --- .../rustc_mir_build/src/check_unsafety.rs | 2 +- tests/ui/union/union.rs | 12 +++++++++- tests/ui/union/union.stderr | 22 +++++++++++++------ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 8141421f6bea4..d9e36ff2134ed 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -262,7 +262,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | PatKind::DerefPattern { .. } | PatKind::Range { .. } | PatKind::Slice { .. } - | PatKind::Array { .. } // Never constitutes a witness of uninhabitedness. | PatKind::Never => { self.requires_unsafe(pat.span, AccessToUnionField); @@ -273,6 +272,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { // these just wrap other patterns, which we recurse on below. | PatKind::Or { .. } | PatKind::Leaf { .. } + | PatKind::Array { .. } | PatKind::Guard { .. } | PatKind::Error(_) => {} } diff --git a/tests/ui/union/union.rs b/tests/ui/union/union.rs index e0c469bdb058f..f841437293774 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -4,6 +4,7 @@ union Foo { tuple: (i32,), pizza: Pizza, tuple_struct: TupleStruct, + array: [u32; 2], } #[derive(Clone, Copy)] @@ -48,8 +49,11 @@ pub fn main() { 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 + } - // binding to a struct pattern is okay if no fields are read + // binding to a tuple, struct, or array pattern is okay if no fields are read match foo { Foo { zst: () } => {} } @@ -71,6 +75,12 @@ pub fn main() { match foo { Foo { tuple_struct: TupleStruct(_) } => {} } + match foo { + Foo { array: [..] } => {} + } + match foo { + Foo { array: [_, _] } => {} + } // binding to wildcard is okay match foo { diff --git a/tests/ui/union/union.stderr b/tests/ui/union/union.stderr index d9264131fa35c..c91a16ed04a12 100644 --- a/tests/ui/union/union.stderr +++ b/tests/ui/union/union.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:32:20 + --> $DIR/union.rs:33:20 | LL | Foo { bar: _a } => {} | ^^ access to union field @@ -7,7 +7,7 @@ LL | Foo { bar: _a } => {} = 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:30 + --> $DIR/union.rs:39:30 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -15,7 +15,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:59 + --> $DIR/union.rs:39:59 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -23,7 +23,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:91 + --> $DIR/union.rs:39:91 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^ access to union field @@ -31,7 +31,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:46:23 + --> $DIR/union.rs:47:23 | LL | Foo { tuple: (_a,) } => {} | ^^ access to union field @@ -39,13 +39,21 @@ LL | Foo { tuple: (_a,) } => {} = 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:49:41 + --> $DIR/union.rs:50: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: aborting due to 6 previous errors +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:53: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: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0133`. From db80e4606e0aa8b44090e3fc8af8c2f349e28677 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 2 Sep 2026 16:36:48 -0400 Subject: [PATCH 04/10] Add another test for enum variants --- tests/ui/union/union.rs | 10 ++++++++++ tests/ui/union/union.stderr | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/ui/union/union.rs b/tests/ui/union/union.rs index f841437293774..4bb9858d7adec 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -43,6 +43,16 @@ pub fn main() { }, } => {} } + 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 } diff --git a/tests/ui/union/union.stderr b/tests/ui/union/union.stderr index c91a16ed04a12..dbd5b55755779 100644 --- a/tests/ui/union/union.stderr +++ b/tests/ui/union/union.stderr @@ -31,7 +31,15 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:47:23 + --> $DIR/union.rs:50: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:57:23 | LL | Foo { tuple: (_a,) } => {} | ^^ access to union field @@ -39,7 +47,7 @@ LL | Foo { tuple: (_a,) } => {} = 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:50:41 + --> $DIR/union.rs:60:41 | LL | Foo { tuple_struct: TupleStruct(_a) } => {} | ^^ access to union field @@ -47,13 +55,13 @@ LL | Foo { tuple_struct: TupleStruct(_a) } => {} = 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:53:23 + --> $DIR/union.rs:63: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: aborting due to 7 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0133`. From 9b01a2f5e7b0b88c3d18953a4bbf3d2c7c0cc061 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 2 Sep 2026 17:08:55 -0400 Subject: [PATCH 05/10] Add test for unit constant --- tests/ui/union/union.rs | 5 +++++ tests/ui/union/union.stderr | 16 ++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/ui/union/union.rs b/tests/ui/union/union.rs index 4bb9858d7adec..c8f00e84a49a0 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -24,6 +24,8 @@ struct TupleStruct(i32); fn do_nothing(_x: &mut Foo) {} +const UNIT: () = (); + pub fn main() { let mut foo = Foo { bar: 5 }; do_nothing(&mut foo); @@ -70,6 +72,9 @@ pub fn main() { match foo { Foo { zst: (..) } => {} } + match foo { + Foo { zst: UNIT } => {} + } match foo { Foo { tuple: (..) } => {} } diff --git a/tests/ui/union/union.stderr b/tests/ui/union/union.stderr index dbd5b55755779..233123865248e 100644 --- a/tests/ui/union/union.stderr +++ b/tests/ui/union/union.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:33:20 + --> $DIR/union.rs:35:20 | LL | Foo { bar: _a } => {} | ^^ access to union field @@ -7,7 +7,7 @@ LL | Foo { bar: _a } => {} = 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:39:30 + --> $DIR/union.rs:41:30 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -15,7 +15,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:39:59 + --> $DIR/union.rs:41:59 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -23,7 +23,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:39:91 + --> $DIR/union.rs:41:91 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^ access to union field @@ -31,7 +31,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:50:30 + --> $DIR/union.rs:52:30 | LL | topping: Some { .. } | ^^^^^^^^^^^ access to union field @@ -39,7 +39,7 @@ LL | topping: Some { .. } = 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:57:23 + --> $DIR/union.rs:59:23 | LL | Foo { tuple: (_a,) } => {} | ^^ access to union field @@ -47,7 +47,7 @@ LL | Foo { tuple: (_a,) } => {} = 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:60:41 + --> $DIR/union.rs:62:41 | LL | Foo { tuple_struct: TupleStruct(_a) } => {} | ^^ access to union field @@ -55,7 +55,7 @@ LL | Foo { tuple_struct: TupleStruct(_a) } => {} = 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:63:23 + --> $DIR/union.rs:65:23 | LL | Foo { array: [_a, _] } => {} | ^^ access to union field From 80bc8dd470ee8e0a0cb523dcc2aa8f95bac59b89 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Thu, 3 Sep 2026 00:28:54 -0400 Subject: [PATCH 06/10] Add test for single-variant enum --- tests/ui/union/union.rs | 9 +++++++++ tests/ui/union/union.stderr | 26 +++++++++++++++++--------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/tests/ui/union/union.rs b/tests/ui/union/union.rs index c8f00e84a49a0..7165c200cca1e 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -5,6 +5,7 @@ union Foo { pizza: Pizza, tuple_struct: TupleStruct, array: [u32; 2], + single_variant_enum: SingleVariant, } #[derive(Clone, Copy)] @@ -22,6 +23,11 @@ enum PizzaTopping { #[derive(Clone, Copy)] struct TupleStruct(i32); +#[derive(Clone, Copy)] +enum SingleVariant { + Single {}, +} + fn do_nothing(_x: &mut Foo) {} const UNIT: () = (); @@ -64,6 +70,9 @@ pub fn main() { 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 + } // binding to a tuple, struct, or array pattern is okay if no fields are read match foo { diff --git a/tests/ui/union/union.stderr b/tests/ui/union/union.stderr index 233123865248e..01d9485310e46 100644 --- a/tests/ui/union/union.stderr +++ b/tests/ui/union/union.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:35:20 + --> $DIR/union.rs:41:20 | LL | Foo { bar: _a } => {} | ^^ access to union field @@ -7,7 +7,7 @@ LL | Foo { bar: _a } => {} = 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:30 + --> $DIR/union.rs:47:30 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -15,7 +15,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:59 + --> $DIR/union.rs:47:59 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -23,7 +23,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:91 + --> $DIR/union.rs:47:91 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^ access to union field @@ -31,7 +31,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:52:30 + --> $DIR/union.rs:58:30 | LL | topping: Some { .. } | ^^^^^^^^^^^ access to union field @@ -39,7 +39,7 @@ LL | topping: Some { .. } = 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:59:23 + --> $DIR/union.rs:65:23 | LL | Foo { tuple: (_a,) } => {} | ^^ access to union field @@ -47,7 +47,7 @@ LL | Foo { tuple: (_a,) } => {} = 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:62:41 + --> $DIR/union.rs:68:41 | LL | Foo { tuple_struct: TupleStruct(_a) } => {} | ^^ access to union field @@ -55,13 +55,21 @@ LL | Foo { tuple_struct: TupleStruct(_a) } => {} = 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:65:23 + --> $DIR/union.rs:71: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: aborting due to 8 previous errors +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:74: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: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0133`. From 50570882a7e0452e0728991a3293cf8695fb2bb6 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Sep 2026 11:52:19 -0400 Subject: [PATCH 07/10] Add test for const pattern with private unit field --- tests/ui/union/auxiliary/zst-const.rs | 6 ++++++ tests/ui/union/union.rs | 12 ++++++++++++ tests/ui/union/union.stderr | 18 +++++++++--------- 3 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 tests/ui/union/auxiliary/zst-const.rs diff --git a/tests/ui/union/auxiliary/zst-const.rs b/tests/ui/union/auxiliary/zst-const.rs new file mode 100644 index 0000000000000..34b1c692b6ebb --- /dev/null +++ b/tests/ui/union/auxiliary/zst-const.rs @@ -0,0 +1,6 @@ +#[derive(Clone, Copy, PartialEq)] +pub struct HasPrivateField { + not_pub: (), +} + +pub const HAS_PRIVATE_FIELD: HasPrivateField = HasPrivateField { not_pub: () }; diff --git a/tests/ui/union/union.rs b/tests/ui/union/union.rs index 7165c200cca1e..07ea999b26062 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -1,3 +1,8 @@ +//@ aux-build: zst-const.rs + +extern crate zst_const; +use zst_const::{HAS_PRIVATE_FIELD, HasPrivateField}; + union Foo { bar: i8, zst: (), @@ -6,6 +11,7 @@ union Foo { tuple_struct: TupleStruct, array: [u32; 2], single_variant_enum: SingleVariant, + has_private_field: HasPrivateField, } #[derive(Clone, Copy)] @@ -111,4 +117,10 @@ pub fn main() { Foo { bar: _ } => {} } let Foo { bar: _ } = foo; + + // Known bug: this should be rejected due to privacy, + // but is currently accepted + match foo { + Foo { has_private_field: HAS_PRIVATE_FIELD } => {} + } } diff --git a/tests/ui/union/union.stderr b/tests/ui/union/union.stderr index 01d9485310e46..ecffe485fd8f0 100644 --- a/tests/ui/union/union.stderr +++ b/tests/ui/union/union.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:41:20 + --> $DIR/union.rs:47:20 | LL | Foo { bar: _a } => {} | ^^ access to union field @@ -7,7 +7,7 @@ LL | Foo { bar: _a } => {} = 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:47:30 + --> $DIR/union.rs:53:30 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -15,7 +15,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:47:59 + --> $DIR/union.rs:53:59 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -23,7 +23,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:47:91 + --> $DIR/union.rs:53:91 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^ access to union field @@ -31,7 +31,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:58:30 + --> $DIR/union.rs:64:30 | LL | topping: Some { .. } | ^^^^^^^^^^^ access to union field @@ -39,7 +39,7 @@ LL | topping: Some { .. } = 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:65:23 + --> $DIR/union.rs:71:23 | LL | Foo { tuple: (_a,) } => {} | ^^ access to union field @@ -47,7 +47,7 @@ LL | Foo { tuple: (_a,) } => {} = 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:68:41 + --> $DIR/union.rs:74:41 | LL | Foo { tuple_struct: TupleStruct(_a) } => {} | ^^ access to union field @@ -55,7 +55,7 @@ LL | Foo { tuple_struct: TupleStruct(_a) } => {} = 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:71:23 + --> $DIR/union.rs:77:23 | LL | Foo { array: [_a, _] } => {} | ^^ access to union field @@ -63,7 +63,7 @@ LL | Foo { array: [_a, _] } => {} = 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:74:36 + --> $DIR/union.rs:80:36 | LL | Foo { single_variant_enum: SingleVariant::Single {} } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^ access to union field From 950d61eb8e3600a58af23e233c16e5d535a016aa Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Mon, 7 Sep 2026 13:50:21 -0400 Subject: [PATCH 08/10] Respect privacy in unsafety checks --- compiler/rustc_hir/src/hir.rs | 4 ++ compiler/rustc_hir_typeck/src/pat.rs | 4 +- compiler/rustc_middle/src/thir.rs | 3 + compiler/rustc_middle/src/thir/visit.rs | 2 +- .../src/builder/matches/match_pair.rs | 2 +- .../src/builder/matches/mod.rs | 2 +- .../rustc_mir_build/src/check_unsafety.rs | 31 +++++++-- .../src/thir/pattern/const_to_pat.rs | 2 + .../rustc_mir_build/src/thir/pattern/mod.rs | 15 ++-- compiler/rustc_mir_build/src/thir/print.rs | 3 +- compiler/rustc_pattern_analysis/src/rustc.rs | 2 +- tests/ui/union/auxiliary/zst-const.rs | 20 ++++++ tests/ui/union/union.rs | 53 +++++++++++++-- tests/ui/union/union.stderr | 68 ++++++++++++++++--- 14 files changed, 175 insertions(+), 36 deletions(-) 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..713d3ebccb102 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -279,7 +279,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 d9e36ff2134ed..35c1271d3eb02 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -271,7 +271,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Wild // these just wrap other patterns, which we recurse on below. | PatKind::Or { .. } - | PatKind::Leaf { .. } + | PatKind::Leaf { .. } // We do extra checks below for patterns lowered from consts | PatKind::Array { .. } | PatKind::Guard { .. } | PatKind::Error(_) => {} @@ -279,13 +279,34 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { }; 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 + && (single_variant.field_list_has_applicable_non_exhaustive() + || single_variant + .fields + .iter() + .any(|f| !f.vis.is_accessible_from(scope, self.tcx))) + { + // This pattern must have been lowered from a constant. + // Changes to private implementation details of said constant + // must not affect whether we require `unsafe`. + self.requires_unsafe(pat.span, AccessToUnionField); + return; + } + + for subpat in subpatterns { + let field = &single_variant.fields[subpat.field]; + 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); 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/union/auxiliary/zst-const.rs b/tests/ui/union/auxiliary/zst-const.rs index 34b1c692b6ebb..a22c3934f9335 100644 --- a/tests/ui/union/auxiliary/zst-const.rs +++ b/tests/ui/union/auxiliary/zst-const.rs @@ -4,3 +4,23 @@ pub struct HasPrivateField { } 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,); diff --git a/tests/ui/union/union.rs b/tests/ui/union/union.rs index 07ea999b26062..f61e43ea70208 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -1,7 +1,11 @@ //@ aux-build: zst-const.rs extern crate zst_const; -use zst_const::{HAS_PRIVATE_FIELD, HasPrivateField}; +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, NESTED_CONST, +}; union Foo { bar: i8, @@ -12,6 +16,11 @@ union Foo { 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,), } #[derive(Clone, Copy)] @@ -34,6 +43,13 @@ 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: () = (); @@ -80,6 +96,26 @@ pub fn main() { 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: () } => {} @@ -111,16 +147,19 @@ pub fn main() { match foo { Foo { array: [_, _] } => {} } + match foo { + Foo { has_private_field: HasPrivateField { .. } } => {} + } + match foo { + Foo { has_non_exhaustive_field_list: HasNonExhaustiveFieldList { .. } } => {} + } + match foo { + Foo { local_non_exhaustive_field_list: LOCAL_NON_EXHAUSTIVE_FIELD_LIST } => {} + } // binding to wildcard is okay match foo { Foo { bar: _ } => {} } let Foo { bar: _ } = foo; - - // Known bug: this should be rejected due to privacy, - // but is currently accepted - match foo { - Foo { has_private_field: HAS_PRIVATE_FIELD } => {} - } } diff --git a/tests/ui/union/union.stderr b/tests/ui/union/union.stderr index ecffe485fd8f0..9771958ec2600 100644 --- a/tests/ui/union/union.stderr +++ b/tests/ui/union/union.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:47:20 + --> $DIR/union.rs:63:20 | LL | Foo { bar: _a } => {} | ^^ access to union field @@ -7,7 +7,7 @@ LL | Foo { bar: _a } => {} = 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:53:30 + --> $DIR/union.rs:69:30 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -15,7 +15,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:53:59 + --> $DIR/union.rs:69:59 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -23,7 +23,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:53:91 + --> $DIR/union.rs:69:91 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^ access to union field @@ -31,7 +31,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:64:30 + --> $DIR/union.rs:80:30 | LL | topping: Some { .. } | ^^^^^^^^^^^ access to union field @@ -39,7 +39,7 @@ LL | topping: Some { .. } = 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:71:23 + --> $DIR/union.rs:87:23 | LL | Foo { tuple: (_a,) } => {} | ^^ access to union field @@ -47,7 +47,7 @@ LL | Foo { tuple: (_a,) } => {} = 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:74:41 + --> $DIR/union.rs:90:41 | LL | Foo { tuple_struct: TupleStruct(_a) } => {} | ^^ access to union field @@ -55,7 +55,7 @@ LL | Foo { tuple_struct: TupleStruct(_a) } => {} = 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:77:23 + --> $DIR/union.rs:93:23 | LL | Foo { array: [_a, _] } => {} | ^^ access to union field @@ -63,13 +63,61 @@ LL | Foo { array: [_a, _] } => {} = 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:80:36 + --> $DIR/union.rs:96: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: aborting due to 9 previous errors +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union.rs:101: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:104: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:107: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:110: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:113: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:116:29 + | +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 15 previous errors For more information about this error, try `rustc --explain E0133`. From 5abfdb773dc2056b4de3db66c45b9b29f1d65a02 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 9 Sep 2026 23:29:10 -0400 Subject: [PATCH 09/10] Don't treat guard pattern condition as accessing union --- compiler/rustc_middle/src/thir/visit.rs | 7 +++---- compiler/rustc_mir_build/src/check_unsafety.rs | 8 ++++++++ tests/ui/pattern/rfc-3637-guard-patterns/union.rs | 2 +- tests/ui/pattern/rfc-3637-guard-patterns/union.stderr | 4 ++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 713d3ebccb102..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. diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 35c1271d3eb02..98a0293c9424e 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -355,6 +355,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/tests/ui/pattern/rfc-3637-guard-patterns/union.rs b/tests/ui/pattern/rfc-3637-guard-patterns/union.rs index a84a686904360..2699f0b2ca620 100644 --- a/tests/ui/pattern/rfc-3637-guard-patterns/union.rs +++ b/tests/ui/pattern/rfc-3637-guard-patterns/union.rs @@ -11,7 +11,7 @@ union Foo { fn main() { let foo = Foo { field: 42 }; match foo { - Foo { field: _ if true } => (), + 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 index 34bf194e80f86..ff56662f641c9 100644 --- a/tests/ui/pattern/rfc-3637-guard-patterns/union.stderr +++ b/tests/ui/pattern/rfc-3637-guard-patterns/union.stderr @@ -1,8 +1,8 @@ warning: unreachable pattern --> $DIR/union.rs:15:9 | -LL | Foo { field: _ if true } => (), - | ------------------------ matches all the relevant values +LL | Foo { field: _ if matches!(1, 1) } => (), + | ---------------------------------- matches all the relevant values LL | _ => panic!(), | ^ no value can reach this | From ebfdb70866c05bceb0631c2e0a2072332f120dea Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 12 Sep 2026 00:07:45 -0400 Subject: [PATCH 10/10] Properly handle nested union patterns --- .../rustc_mir_build/src/check_unsafety.rs | 34 ++++++++++++++----- tests/ui/union/auxiliary/zst-const.rs | 6 ++++ tests/ui/union/union.rs | 6 +++- tests/ui/union/union.stderr | 30 ++++++++-------- 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 98a0293c9424e..37701a56883b4 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -287,21 +287,39 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { if self.in_union_destructure && !has_rest - && (single_variant.field_list_has_applicable_non_exhaustive() - || single_variant - .fields - .iter() - .any(|f| !f.vis.is_accessible_from(scope, self.tcx))) + && ( + // 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)) + ) { - // This pattern must have been lowered from a constant. - // Changes to private implementation details of said constant - // must not affect whether we require `unsafe`. + // 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); } diff --git a/tests/ui/union/auxiliary/zst-const.rs b/tests/ui/union/auxiliary/zst-const.rs index a22c3934f9335..cf02440973d21 100644 --- a/tests/ui/union/auxiliary/zst-const.rs +++ b/tests/ui/union/auxiliary/zst-const.rs @@ -24,3 +24,9 @@ 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 f61e43ea70208..8cc0599c9ebde 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -4,7 +4,7 @@ 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, NESTED_CONST, + HasPrivateField, HasPrivateTupleField, MixedVisibilityUnion, NESTED_CONST, }; union Foo { @@ -21,6 +21,7 @@ union Foo { has_non_exhaustive_tuple_field_list: HasNonExhaustiveTupleFieldList, local_non_exhaustive_field_list: LocalNonExhaustiveFieldList, nested_const: (HasPrivateField,), + mixed_visibility_union: MixedVisibilityUnion, } #[derive(Clone, Copy)] @@ -156,6 +157,9 @@ pub fn main() { match foo { Foo { local_non_exhaustive_field_list: LOCAL_NON_EXHAUSTIVE_FIELD_LIST } => {} } + match foo { + Foo { mixed_visibility_union: MixedVisibilityUnion { zst: () } } => {} + } // binding to wildcard is okay match foo { diff --git a/tests/ui/union/union.stderr b/tests/ui/union/union.stderr index 9771958ec2600..5c42780ce7b46 100644 --- a/tests/ui/union/union.stderr +++ b/tests/ui/union/union.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union.rs:63:20 + --> $DIR/union.rs:64:20 | LL | Foo { bar: _a } => {} | ^^ access to union field @@ -7,7 +7,7 @@ LL | Foo { bar: _a } => {} = 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:69:30 + --> $DIR/union.rs:70:30 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -15,7 +15,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:69:59 + --> $DIR/union.rs:70:59 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -23,7 +23,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:69:91 + --> $DIR/union.rs:70:91 | LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping::Pineapple) | None, | ^^^^ access to union field @@ -31,7 +31,7 @@ LL | topping: Some(PizzaTopping::Cheese) | Some(PizzaTopping = 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:80:30 + --> $DIR/union.rs:81:30 | LL | topping: Some { .. } | ^^^^^^^^^^^ access to union field @@ -39,7 +39,7 @@ LL | topping: Some { .. } = 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:87:23 + --> $DIR/union.rs:88:23 | LL | Foo { tuple: (_a,) } => {} | ^^ access to union field @@ -47,7 +47,7 @@ LL | Foo { tuple: (_a,) } => {} = 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:90:41 + --> $DIR/union.rs:91:41 | LL | Foo { tuple_struct: TupleStruct(_a) } => {} | ^^ access to union field @@ -55,7 +55,7 @@ LL | Foo { tuple_struct: TupleStruct(_a) } => {} = 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:93:23 + --> $DIR/union.rs:94:23 | LL | Foo { array: [_a, _] } => {} | ^^ access to union field @@ -63,7 +63,7 @@ LL | Foo { array: [_a, _] } => {} = 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:96:36 + --> $DIR/union.rs:97:36 | LL | Foo { single_variant_enum: SingleVariant::Single {} } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -71,7 +71,7 @@ LL | Foo { single_variant_enum: SingleVariant::Single {} } => {} = 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:101:34 + --> $DIR/union.rs:102:34 | LL | Foo { has_private_field: HAS_PRIVATE_FIELD } => {} | ^^^^^^^^^^^^^^^^^ access to union field @@ -79,7 +79,7 @@ LL | Foo { has_private_field: HAS_PRIVATE_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:104:46 + --> $DIR/union.rs:105:46 | LL | Foo { has_non_exhaustive_field_list: HAS_NON_EXHAUSTIVE_FIELD_LIST } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -87,7 +87,7 @@ LL | Foo { has_non_exhaustive_field_list: HAS_NON_EXHAUSTIVE_FIELD_LIST = 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:107:40 + --> $DIR/union.rs:108:40 | LL | Foo { has_private_tuple_field: HAS_PRIVATE_TUPLE_FIELD } => {} | ^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -95,7 +95,7 @@ LL | Foo { has_private_tuple_field: HAS_PRIVATE_TUPLE_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:110:52 + --> $DIR/union.rs:111:52 | LL | ... Foo { has_non_exhaustive_tuple_field_list: HAS_NON_EXHAUSTIVE_TUPLE_FIELD_LIST } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -103,7 +103,7 @@ LL | ... Foo { has_non_exhaustive_tuple_field_list: HAS_NON_EXHAUSTIVE_TUPLE_F = 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:113:52 + --> $DIR/union.rs:114:52 | LL | ... Foo { has_non_exhaustive_tuple_field_list: HAS_NON_EXHAUSTIVE_TUPLE_FIELD_LIST } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ access to union field @@ -111,7 +111,7 @@ LL | ... Foo { has_non_exhaustive_tuple_field_list: HAS_NON_EXHAUSTIVE_TUPLE_F = 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:116:29 + --> $DIR/union.rs:117:29 | LL | Foo { nested_const: NESTED_CONST } => {} | ^^^^^^^^^^^^ access to union field