Skip to content

Commit 1d47c76

Browse files
committed
fixed unsafe suggestion
1 parent 163cb4e commit 1d47c76

File tree

3 files changed

+34
-8
lines changed

3 files changed

+34
-8
lines changed

compiler/rustc_mir_build/src/check_unsafety.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ 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,
4851
}
4952

5053
impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
@@ -218,6 +221,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
218221
inside_adt: false,
219222
warnings: self.warnings,
220223
suggest_unsafe_block: self.suggest_unsafe_block,
224+
in_raw_borrow: false,
221225
};
222226
// params in THIR may be unsafe, e.g. a union pattern.
223227
for param in &inner_thir.params {
@@ -538,14 +542,24 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
538542
}
539543
}
540544
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 = true;
548+
541549
if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind
542550
&& let ExprKind::Deref { arg } = self.thir[arg].kind
543551
{
544552
// Taking a raw ref to a deref place expr is always safe.
545553
// Make sure the expression we're deref'ing is safe, though.
546554
visit::walk_expr(self, &self.thir[arg]);
547-
return;
555+
} else {
556+
// Handle other raw borrow cases (including field access)
557+
visit::walk_expr(self, &self.thir[arg]);
548558
}
559+
560+
// Restore previous state
561+
self.in_raw_borrow = old_in_raw_borrow;
562+
return;
549563
}
550564
ExprKind::Deref { arg } => {
551565
if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
@@ -651,7 +665,10 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
651665
"union fields that need dropping should be impossible: {assigned_ty}"
652666
);
653667
}
654-
} else {
668+
} else if !self.in_raw_borrow {
669+
// Union field access is unsafe because the field may be uninitialized.
670+
// However, `&raw const/mut union.field` is safe since it only computes
671+
// the field's address without reading the potentially uninitialized value.
655672
self.requires_unsafe(expr.span, AccessToUnionField);
656673
}
657674
}
@@ -1187,6 +1204,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
11871204
inside_adt: false,
11881205
warnings: &mut warnings,
11891206
suggest_unsafe_block: true,
1207+
in_raw_borrow: false,
11901208
};
11911209
// params in THIR may be unsafe, e.g. a union pattern.
11921210
for param in &thir.params {

tests/ui/union/union-unsafe.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ fn main() {
5757
let a = u1.a; //~ ERROR access to union field is unsafe
5858
u1.a = 11; // OK
5959

60+
let mut u2 = U1 { a: 10 };
61+
let a = &raw mut u2.a; // OK
62+
unsafe { *a = 3 };
63+
64+
let mut u3 = U1 { a: 10 };
65+
let a = std::ptr::addr_of_mut!(u3.a); // OK
66+
unsafe { *a = 14 };
67+
6068
let U1 { a } = u1; //~ ERROR access to union field is unsafe
6169
if let U1 { a: 12 } = u1 {} //~ ERROR access to union field is unsafe
6270
if let Some(U1 { a: 13 }) = Some(u1) {} //~ ERROR access to union field is unsafe

tests/ui/union/union-unsafe.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,47 +31,47 @@ LL | let a = u1.a;
3131
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
3232

3333
error[E0133]: access to union field is unsafe and requires unsafe function or block
34-
--> $DIR/union-unsafe.rs:60:14
34+
--> $DIR/union-unsafe.rs:68:14
3535
|
3636
LL | let U1 { a } = u1;
3737
| ^ access to union field
3838
|
3939
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
4040

4141
error[E0133]: access to union field is unsafe and requires unsafe function or block
42-
--> $DIR/union-unsafe.rs:61:20
42+
--> $DIR/union-unsafe.rs:69:20
4343
|
4444
LL | if let U1 { a: 12 } = u1 {}
4545
| ^^ access to union field
4646
|
4747
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
4848

4949
error[E0133]: access to union field is unsafe and requires unsafe function or block
50-
--> $DIR/union-unsafe.rs:62:25
50+
--> $DIR/union-unsafe.rs:70:25
5151
|
5252
LL | if let Some(U1 { a: 13 }) = Some(u1) {}
5353
| ^^ access to union field
5454
|
5555
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
5656

5757
error[E0133]: access to union field is unsafe and requires unsafe function or block
58-
--> $DIR/union-unsafe.rs:67:6
58+
--> $DIR/union-unsafe.rs:75:6
5959
|
6060
LL | *u2.a = String::from("new");
6161
| ^^^^ access to union field
6262
|
6363
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
6464

6565
error[E0133]: access to union field is unsafe and requires unsafe function or block
66-
--> $DIR/union-unsafe.rs:71:6
66+
--> $DIR/union-unsafe.rs:79:6
6767
|
6868
LL | *u3.a = 1;
6969
| ^^^^ access to union field
7070
|
7171
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
7272

7373
error[E0133]: access to union field is unsafe and requires unsafe function or block
74-
--> $DIR/union-unsafe.rs:75:6
74+
--> $DIR/union-unsafe.rs:83:6
7575
|
7676
LL | *u3.a = String::from("new");
7777
| ^^^^ access to union field

0 commit comments

Comments
 (0)