@@ -45,9 +45,6 @@ struct UnsafetyVisitor<'a, 'tcx> {
4545 /// Flag to ensure that we only suggest wrapping the entire function body in
4646 /// an unsafe block once.
4747 suggest_unsafe_block : bool ,
48- /// Track whether we're currently inside a `&raw const/mut` expression.
49- /// Used to allow safe access to union fields when only taking their address.
50- in_raw_borrow : bool ,
5148}
5249
5350impl < ' tcx > UnsafetyVisitor < ' _ , ' tcx > {
@@ -221,7 +218,6 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
221218 inside_adt : false ,
222219 warnings : self . warnings ,
223220 suggest_unsafe_block : self . suggest_unsafe_block ,
224- in_raw_borrow : false ,
225221 } ;
226222 // params in THIR may be unsafe, e.g. a union pattern.
227223 for param in & inner_thir. params {
@@ -542,22 +538,28 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
542538 }
543539 }
544540 ExprKind :: RawBorrow { arg, .. } => {
545- // Set flag when entering raw borrow context
546- let old_in_raw_borrow = self . in_raw_borrow ;
547- self . in_raw_borrow = is_direct_place_expr ( self . thir , arg) ;
541+ // Handle the case where we're taking a raw pointer to a union field
542+ if let ExprKind :: Scope { value : arg, .. } = self . thir [ arg] . kind {
543+ if self . is_union_field_access ( arg) {
544+ // Taking a raw pointer to a union field is safe - just check the base expression
545+ // but skip the union field safety check
546+ self . visit_union_field_for_raw_borrow ( arg) ;
547+ return ;
548+ }
549+ } else if self . is_union_field_access ( arg) {
550+ // Direct raw borrow of union field
551+ self . visit_union_field_for_raw_borrow ( arg) ;
552+ return ;
553+ }
548554
549555 if let ExprKind :: Scope { value : arg, .. } = self . thir [ arg] . kind
550556 && let ExprKind :: Deref { arg } = self . thir [ arg] . kind
551557 {
552558 // Taking a raw ref to a deref place expr is always safe.
553559 // Make sure the expression we're deref'ing is safe, though.
554560 visit:: walk_expr ( self , & self . thir [ arg] ) ;
561+ return ;
555562 }
556-
557- visit:: walk_expr ( self , & self . thir [ arg] ) ;
558- // Restore previous state
559- self . in_raw_borrow = old_in_raw_borrow;
560- return ;
561563 }
562564 ExprKind :: Deref { arg } => {
563565 if let ExprKind :: StaticRef { def_id, .. } | ExprKind :: ThreadLocalRef ( def_id) =
@@ -654,6 +656,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
654656 if adt_def. variant ( variant_index) . fields [ name] . safety . is_unsafe ( ) {
655657 self . requires_unsafe ( expr. span , UseOfUnsafeField ) ;
656658 } else if adt_def. is_union ( ) {
659+ // Check if this field access is part of a raw borrow operation
660+ // If so, we've already handled it above and shouldn't reach here
657661 if let Some ( assigned_ty) = self . assignment_info {
658662 if assigned_ty. needs_drop ( self . tcx , self . typing_env ) {
659663 // This would be unsafe, but should be outright impossible since we
@@ -663,10 +667,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
663667 "union fields that need dropping should be impossible: {assigned_ty}"
664668 ) ;
665669 }
666- } else if !self . in_raw_borrow {
667- // Union field access is unsafe because the field may be uninitialized.
668- // However, `&raw const/mut union.field` is safe since it only computes
669- // the field's address without reading the potentially uninitialized value.
670+ } else {
671+ // Only require unsafe if this is not a raw borrow operation
670672 self . requires_unsafe ( expr. span , AccessToUnionField ) ;
671673 }
672674 }
@@ -720,16 +722,43 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
720722 }
721723}
722724
723- fn is_direct_place_expr < ' a , ' tcx > ( thir : & ' a Thir < ' tcx > , expr_id : ExprId ) -> bool {
724- match thir[ expr_id] . kind {
725- // Direct place expressions that don't read values
726- ExprKind :: Field { .. } | ExprKind :: VarRef { .. } | ExprKind :: UpvarRef { .. } => true ,
727-
728- // Scope is transparent for place expressions
729- ExprKind :: Scope { value, .. } => is_direct_place_expr ( thir, value) ,
725+ impl < ' a , ' tcx > UnsafetyVisitor < ' a , ' tcx > {
726+ /// Check if an expression is a union field access
727+ fn is_union_field_access ( & self , expr_id : ExprId ) -> bool {
728+ match self . thir [ expr_id] . kind {
729+ ExprKind :: Field { lhs, .. } => {
730+ let lhs = & self . thir [ lhs] ;
731+ if let ty:: Adt ( adt_def, _) = lhs. ty . kind ( ) { adt_def. is_union ( ) } else { false }
732+ }
733+ _ => false ,
734+ }
735+ }
730736
731- // Any other expression (including Deref, method calls, etc.) reads values
732- _ => false ,
737+ /// Visit a union field access in the context of a raw borrow operation
738+ /// This ensures we still check safety of nested operations while allowing
739+ /// the raw pointer creation itself
740+ fn visit_union_field_for_raw_borrow ( & mut self , expr_id : ExprId ) {
741+ match self . thir [ expr_id] . kind {
742+ ExprKind :: Field { lhs, variant_index, name } => {
743+ let lhs_expr = & self . thir [ lhs] ;
744+ if let ty:: Adt ( adt_def, _) = lhs_expr. ty . kind ( ) {
745+ // Check for unsafe fields but skip the union access check
746+ if adt_def. variant ( variant_index) . fields [ name] . safety . is_unsafe ( ) {
747+ self . requires_unsafe ( self . thir [ expr_id] . span , UseOfUnsafeField ) ;
748+ }
749+ // For unions, we don't require unsafe for raw pointer creation
750+ // But we still need to check the LHS for safety
751+ self . visit_expr ( lhs_expr) ;
752+ } else {
753+ // Not a union, use normal visiting
754+ visit:: walk_expr ( self , & self . thir [ expr_id] ) ;
755+ }
756+ }
757+ _ => {
758+ // Not a field access, use normal visiting
759+ visit:: walk_expr ( self , & self . thir [ expr_id] ) ;
760+ }
761+ }
733762 }
734763}
735764
@@ -1215,7 +1244,6 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
12151244 inside_adt : false ,
12161245 warnings : & mut warnings,
12171246 suggest_unsafe_block : true ,
1218- in_raw_borrow : false ,
12191247 } ;
12201248 // params in THIR may be unsafe, e.g. a union pattern.
12211249 for param in & thir. params {
0 commit comments