@@ -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 > {
@@ -226,7 +223,6 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
226223 inside_adt : false ,
227224 warnings : self . warnings ,
228225 suggest_unsafe_block : self . suggest_unsafe_block ,
229- in_raw_borrow : false ,
230226 } ;
231227 // params in THIR may be unsafe, e.g. a union pattern.
232228 for param in & inner_thir. params {
@@ -549,22 +545,28 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
549545 }
550546 }
551547 ExprKind :: RawBorrow { arg, .. } => {
552- // Set flag when entering raw borrow context
553- let old_in_raw_borrow = self . in_raw_borrow ;
554- self . in_raw_borrow = is_direct_place_expr ( self . thir , arg) ;
548+ // Handle the case where we're taking a raw pointer to a union field
549+ if let ExprKind :: Scope { value : arg, .. } = self . thir [ arg] . kind {
550+ if self . is_union_field_access ( arg) {
551+ // Taking a raw pointer to a union field is safe - just check the base expression
552+ // but skip the union field safety check
553+ self . visit_union_field_for_raw_borrow ( arg) ;
554+ return ;
555+ }
556+ } else if self . is_union_field_access ( arg) {
557+ // Direct raw borrow of union field
558+ self . visit_union_field_for_raw_borrow ( arg) ;
559+ return ;
560+ }
555561
556562 if let ExprKind :: Scope { value : arg, .. } = self . thir [ arg] . kind
557563 && let ExprKind :: Deref { arg } = self . thir [ arg] . kind
558564 {
559565 // Taking a raw ref to a deref place expr is always safe.
560566 // Make sure the expression we're deref'ing is safe, though.
561567 visit:: walk_expr ( self , & self . thir [ arg] ) ;
568+ return ;
562569 }
563-
564- visit:: walk_expr ( self , & self . thir [ arg] ) ;
565- // Restore previous state
566- self . in_raw_borrow = old_in_raw_borrow;
567- return ;
568570 }
569571 ExprKind :: Deref { arg } => {
570572 if let ExprKind :: StaticRef { def_id, .. } | ExprKind :: ThreadLocalRef ( def_id) =
@@ -661,6 +663,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
661663 if adt_def. variant ( variant_index) . fields [ name] . safety . is_unsafe ( ) {
662664 self . requires_unsafe ( expr. span , UseOfUnsafeField ) ;
663665 } else if adt_def. is_union ( ) {
666+ // Check if this field access is part of a raw borrow operation
667+ // If so, we've already handled it above and shouldn't reach here
664668 if let Some ( assigned_ty) = self . assignment_info {
665669 if assigned_ty. needs_drop ( self . tcx , self . typing_env ) {
666670 // This would be unsafe, but should be outright impossible since we
@@ -670,10 +674,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
670674 "union fields that need dropping should be impossible: {assigned_ty}"
671675 ) ;
672676 }
673- } else if !self . in_raw_borrow {
674- // Union field access is unsafe because the field may be uninitialized.
675- // However, `&raw const/mut union.field` is safe since it only computes
676- // the field's address without reading the potentially uninitialized value.
677+ } else {
678+ // Only require unsafe if this is not a raw borrow operation
677679 self . requires_unsafe ( expr. span , AccessToUnionField ) ;
678680 }
679681 }
@@ -727,16 +729,43 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
727729 }
728730}
729731
730- fn is_direct_place_expr < ' a , ' tcx > ( thir : & ' a Thir < ' tcx > , expr_id : ExprId ) -> bool {
731- match thir[ expr_id] . kind {
732- // Direct place expressions that don't read values
733- ExprKind :: Field { .. } | ExprKind :: VarRef { .. } | ExprKind :: UpvarRef { .. } => true ,
734-
735- // Scope is transparent for place expressions
736- ExprKind :: Scope { value, .. } => is_direct_place_expr ( thir, value) ,
732+ impl < ' a , ' tcx > UnsafetyVisitor < ' a , ' tcx > {
733+ /// Check if an expression is a union field access
734+ fn is_union_field_access ( & self , expr_id : ExprId ) -> bool {
735+ match self . thir [ expr_id] . kind {
736+ ExprKind :: Field { lhs, .. } => {
737+ let lhs = & self . thir [ lhs] ;
738+ if let ty:: Adt ( adt_def, _) = lhs. ty . kind ( ) { adt_def. is_union ( ) } else { false }
739+ }
740+ _ => false ,
741+ }
742+ }
737743
738- // Any other expression (including Deref, method calls, etc.) reads values
739- _ => false ,
744+ /// Visit a union field access in the context of a raw borrow operation
745+ /// This ensures we still check safety of nested operations while allowing
746+ /// the raw pointer creation itself
747+ fn visit_union_field_for_raw_borrow ( & mut self , expr_id : ExprId ) {
748+ match self . thir [ expr_id] . kind {
749+ ExprKind :: Field { lhs, variant_index, name } => {
750+ let lhs_expr = & self . thir [ lhs] ;
751+ if let ty:: Adt ( adt_def, _) = lhs_expr. ty . kind ( ) {
752+ // Check for unsafe fields but skip the union access check
753+ if adt_def. variant ( variant_index) . fields [ name] . safety . is_unsafe ( ) {
754+ self . requires_unsafe ( self . thir [ expr_id] . span , UseOfUnsafeField ) ;
755+ }
756+ // For unions, we don't require unsafe for raw pointer creation
757+ // But we still need to check the LHS for safety
758+ self . visit_expr ( lhs_expr) ;
759+ } else {
760+ // Not a union, use normal visiting
761+ visit:: walk_expr ( self , & self . thir [ expr_id] ) ;
762+ }
763+ }
764+ _ => {
765+ // Not a field access, use normal visiting
766+ visit:: walk_expr ( self , & self . thir [ expr_id] ) ;
767+ }
768+ }
740769 }
741770}
742771
@@ -1227,7 +1256,6 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
12271256 inside_adt : false ,
12281257 warnings : & mut warnings,
12291258 suggest_unsafe_block : true ,
1230- in_raw_borrow : false ,
12311259 } ;
12321260 // params in THIR may be unsafe, e.g. a union pattern.
12331261 for param in & thir. params {
0 commit comments