@@ -45,9 +45,6 @@ struct UnsafetyVisitor<'a, 'tcx> {
45
45
/// Flag to ensure that we only suggest wrapping the entire function body in
46
46
/// an unsafe block once.
47
47
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 ,
51
48
}
52
49
53
50
impl < ' tcx > UnsafetyVisitor < ' _ , ' tcx > {
@@ -221,7 +218,6 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
221
218
inside_adt : false ,
222
219
warnings : self . warnings ,
223
220
suggest_unsafe_block : self . suggest_unsafe_block ,
224
- in_raw_borrow : false ,
225
221
} ;
226
222
// params in THIR may be unsafe, e.g. a union pattern.
227
223
for param in & inner_thir. params {
@@ -542,22 +538,28 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
542
538
}
543
539
}
544
540
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
+ }
548
554
549
555
if let ExprKind :: Scope { value : arg, .. } = self . thir [ arg] . kind
550
556
&& let ExprKind :: Deref { arg } = self . thir [ arg] . kind
551
557
{
552
558
// Taking a raw ref to a deref place expr is always safe.
553
559
// Make sure the expression we're deref'ing is safe, though.
554
560
visit:: walk_expr ( self , & self . thir [ arg] ) ;
561
+ return ;
555
562
}
556
-
557
- visit:: walk_expr ( self , & self . thir [ arg] ) ;
558
- // Restore previous state
559
- self . in_raw_borrow = old_in_raw_borrow;
560
- return ;
561
563
}
562
564
ExprKind :: Deref { arg } => {
563
565
if let ExprKind :: StaticRef { def_id, .. } | ExprKind :: ThreadLocalRef ( def_id) =
@@ -654,6 +656,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
654
656
if adt_def. variant ( variant_index) . fields [ name] . safety . is_unsafe ( ) {
655
657
self . requires_unsafe ( expr. span , UseOfUnsafeField ) ;
656
658
} 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
657
661
if let Some ( assigned_ty) = self . assignment_info {
658
662
if assigned_ty. needs_drop ( self . tcx , self . typing_env ) {
659
663
// 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> {
663
667
"union fields that need dropping should be impossible: {assigned_ty}"
664
668
) ;
665
669
}
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
670
672
self . requires_unsafe ( expr. span , AccessToUnionField ) ;
671
673
}
672
674
}
@@ -720,16 +722,43 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
720
722
}
721
723
}
722
724
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
+ }
730
736
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
+ }
733
762
}
734
763
}
735
764
@@ -1215,7 +1244,6 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
1215
1244
inside_adt : false ,
1216
1245
warnings : & mut warnings,
1217
1246
suggest_unsafe_block : true ,
1218
- in_raw_borrow : false ,
1219
1247
} ;
1220
1248
// params in THIR may be unsafe, e.g. a union pattern.
1221
1249
for param in & thir. params {
0 commit comments