Skip to content

Commit 87fb4ad

Browse files
committed
not allow using &raw in other than plain field context
1 parent 1d47c76 commit 87fb4ad

File tree

3 files changed

+75
-15
lines changed

3 files changed

+75
-15
lines changed

compiler/rustc_mir_build/src/check_unsafety.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -544,19 +544,17 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
544544
ExprKind::RawBorrow { arg, .. } => {
545545
// Set flag when entering raw borrow context
546546
let old_in_raw_borrow = self.in_raw_borrow;
547-
self.in_raw_borrow = true;
547+
self.in_raw_borrow = is_direct_place_expr(self.thir, arg);
548548

549549
if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind
550550
&& let ExprKind::Deref { arg } = self.thir[arg].kind
551551
{
552552
// Taking a raw ref to a deref place expr is always safe.
553553
// Make sure the expression we're deref'ing is safe, though.
554554
visit::walk_expr(self, &self.thir[arg]);
555-
} else {
556-
// Handle other raw borrow cases (including field access)
557-
visit::walk_expr(self, &self.thir[arg]);
558555
}
559556

557+
visit::walk_expr(self, &self.thir[arg]);
560558
// Restore previous state
561559
self.in_raw_borrow = old_in_raw_borrow;
562560
return;
@@ -722,6 +720,19 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
722720
}
723721
}
724722

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),
730+
731+
// Any other expression (including Deref, method calls, etc.) reads values
732+
_ => false,
733+
}
734+
}
735+
725736
#[derive(Clone)]
726737
enum SafetyContext {
727738
Safe,

tests/ui/union/union-unsafe.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ union U4<T: Copy> {
1717
a: T,
1818
}
1919

20+
union U5 {
21+
a: usize,
22+
}
23+
2024
union URef {
2125
p: &'static mut i32,
2226
}
@@ -31,6 +35,12 @@ fn deref_union_field(mut u: URef) {
3135
*(u.p) = 13; //~ ERROR access to union field is unsafe
3236
}
3337

38+
fn raw_deref_union_field(mut u: URef) {
39+
let _p = &raw const *(u.p);
40+
//~^ ERROR access to union field is unsafe
41+
//~| ERROR access to union field is unsafe
42+
}
43+
3444
fn assign_noncopy_union_field(mut u: URefCell) {
3545
u.a = (ManuallyDrop::new(RefCell::new(0)), 1); // OK (assignment does not drop)
3646
u.a.0 = ManuallyDrop::new(RefCell::new(0)); // OK (assignment does not drop)
@@ -65,6 +75,11 @@ fn main() {
6575
let a = std::ptr::addr_of_mut!(u3.a); // OK
6676
unsafe { *a = 14 };
6777

78+
let u4 = U5 { a: 2 };
79+
let vec = vec![1, 2, 3];
80+
let _a = &raw const vec[u4.a]; //~ ERROR access to union field is unsafe
81+
//~^ ERROR access to union field is unsafe
82+
6883
let U1 { a } = u1; //~ ERROR access to union field is unsafe
6984
if let U1 { a: 12 } = u1 {} //~ ERROR access to union field is unsafe
7085
if let Some(U1 { a: 13 }) = Some(u1) {} //~ ERROR access to union field is unsafe

tests/ui/union/union-unsafe.stderr

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,117 @@
11
error[E0133]: access to union field is unsafe and requires unsafe function or block
2-
--> $DIR/union-unsafe.rs:31:6
2+
--> $DIR/union-unsafe.rs:35:6
33
|
44
LL | *(u.p) = 13;
55
| ^^^^^ access to union field
66
|
77
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
88

99
error[E0133]: access to union field is unsafe and requires unsafe function or block
10-
--> $DIR/union-unsafe.rs:43:6
10+
--> $DIR/union-unsafe.rs:39:26
11+
|
12+
LL | let _p = &raw const *(u.p);
13+
| ^^^^^ access to union field
14+
|
15+
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
16+
17+
error[E0133]: access to union field is unsafe and requires unsafe function or block
18+
--> $DIR/union-unsafe.rs:39:26
19+
|
20+
LL | let _p = &raw const *(u.p);
21+
| ^^^^^ access to union field
22+
|
23+
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
24+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
25+
26+
error[E0133]: access to union field is unsafe and requires unsafe function or block
27+
--> $DIR/union-unsafe.rs:53:6
1128
|
1229
LL | *u3.a = T::default();
1330
| ^^^^ access to union field
1431
|
1532
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
1633

1734
error[E0133]: access to union field is unsafe and requires unsafe function or block
18-
--> $DIR/union-unsafe.rs:49:6
35+
--> $DIR/union-unsafe.rs:59:6
1936
|
2037
LL | *u3.a = T::default();
2138
| ^^^^ access to union field
2239
|
2340
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
2441

2542
error[E0133]: access to union field is unsafe and requires unsafe function or block
26-
--> $DIR/union-unsafe.rs:57:13
43+
--> $DIR/union-unsafe.rs:67:13
2744
|
2845
LL | let a = u1.a;
2946
| ^^^^ access to union field
3047
|
3148
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
3249

3350
error[E0133]: access to union field is unsafe and requires unsafe function or block
34-
--> $DIR/union-unsafe.rs:68:14
51+
--> $DIR/union-unsafe.rs:80:29
52+
|
53+
LL | let _a = &raw const vec[u4.a];
54+
| ^^^^ access to union field
55+
|
56+
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
57+
58+
error[E0133]: access to union field is unsafe and requires unsafe function or block
59+
--> $DIR/union-unsafe.rs:80:29
60+
|
61+
LL | let _a = &raw const vec[u4.a];
62+
| ^^^^ access to union field
63+
|
64+
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
65+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
66+
67+
error[E0133]: access to union field is unsafe and requires unsafe function or block
68+
--> $DIR/union-unsafe.rs:83:14
3569
|
3670
LL | let U1 { a } = u1;
3771
| ^ access to union field
3872
|
3973
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
4074

4175
error[E0133]: access to union field is unsafe and requires unsafe function or block
42-
--> $DIR/union-unsafe.rs:69:20
76+
--> $DIR/union-unsafe.rs:84:20
4377
|
4478
LL | if let U1 { a: 12 } = u1 {}
4579
| ^^ access to union field
4680
|
4781
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
4882

4983
error[E0133]: access to union field is unsafe and requires unsafe function or block
50-
--> $DIR/union-unsafe.rs:70:25
84+
--> $DIR/union-unsafe.rs:85:25
5185
|
5286
LL | if let Some(U1 { a: 13 }) = Some(u1) {}
5387
| ^^ access to union field
5488
|
5589
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
5690

5791
error[E0133]: access to union field is unsafe and requires unsafe function or block
58-
--> $DIR/union-unsafe.rs:75:6
92+
--> $DIR/union-unsafe.rs:90:6
5993
|
6094
LL | *u2.a = String::from("new");
6195
| ^^^^ access to union field
6296
|
6397
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
6498

6599
error[E0133]: access to union field is unsafe and requires unsafe function or block
66-
--> $DIR/union-unsafe.rs:79:6
100+
--> $DIR/union-unsafe.rs:94:6
67101
|
68102
LL | *u3.a = 1;
69103
| ^^^^ access to union field
70104
|
71105
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
72106

73107
error[E0133]: access to union field is unsafe and requires unsafe function or block
74-
--> $DIR/union-unsafe.rs:83:6
108+
--> $DIR/union-unsafe.rs:98:6
75109
|
76110
LL | *u3.a = String::from("new");
77111
| ^^^^ access to union field
78112
|
79113
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
80114

81-
error: aborting due to 10 previous errors
115+
error: aborting due to 14 previous errors
82116

83117
For more information about this error, try `rustc --explain E0133`.

0 commit comments

Comments
 (0)