Skip to content

Commit 6059195

Browse files
authored
Rollup merge of #141469 - Kivooeo:remove-usnsafegate, r=compiler-errors
Allow `&raw [mut | const]` for union field in safe code fixes #141264 r? ``@Veykril`` Unresolved questions: - [x] Any edge cases? - [x] How this works with rust-analyzer (because all I've did is prevent compiler from emitting error in `&raw` context) (rust-lang/rust-analyzer#19867) - [x] Should we allow `addr_of!` and `addr_of_mut!` as well? In current version they both (`&raw` and `addr_of!`) are allowed (They are the same) - [x] Is chain of union fields is a safe? (Yes)
2 parents 322dca8 + 23f1767 commit 6059195

File tree

4 files changed

+132
-12
lines changed

4 files changed

+132
-12
lines changed

compiler/rustc_mir_build/src/check_unsafety.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,21 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
554554
visit::walk_expr(self, &self.thir[arg]);
555555
return;
556556
}
557+
558+
// Secondly, we allow raw borrows of union field accesses. Peel
559+
// any of those off, and recurse normally on the LHS, which should
560+
// reject any unsafe operations within.
561+
let mut peeled = arg;
562+
while let ExprKind::Scope { value: arg, .. } = self.thir[peeled].kind
563+
&& let ExprKind::Field { lhs, name: _, variant_index: _ } = self.thir[arg].kind
564+
&& let ty::Adt(def, _) = &self.thir[lhs].ty.kind()
565+
&& def.is_union()
566+
{
567+
peeled = lhs;
568+
}
569+
visit::walk_expr(self, &self.thir[peeled]);
570+
// And return so we don't recurse directly onto the union field access(es).
571+
return;
557572
}
558573
ExprKind::Deref { arg } => {
559574
if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =

src/tools/miri/tests/pass/both_borrows/smallvec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl<T, const N: usize> RawSmallVec<T, N> {
2525
}
2626

2727
const fn as_mut_ptr_inline(&mut self) -> *mut T {
28-
(unsafe { &raw mut self.inline }) as *mut T
28+
&raw mut self.inline as *mut T
2929
}
3030

3131
const unsafe fn as_mut_ptr_heap(&mut self) -> *mut T {

tests/ui/union/union-unsafe.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::cell::RefCell;
22
use std::mem::ManuallyDrop;
3+
use std::ops::Deref;
34

45
union U1 {
56
a: u8,
@@ -17,6 +18,10 @@ union U4<T: Copy> {
1718
a: T,
1819
}
1920

21+
union U5 {
22+
a: usize,
23+
}
24+
2025
union URef {
2126
p: &'static mut i32,
2227
}
@@ -31,6 +36,20 @@ fn deref_union_field(mut u: URef) {
3136
*(u.p) = 13; //~ ERROR access to union field is unsafe
3237
}
3338

39+
union A {
40+
a: usize,
41+
b: &'static &'static B,
42+
}
43+
44+
union B {
45+
c: usize,
46+
}
47+
48+
fn raw_deref_union_field(mut u: URef) {
49+
// This is unsafe because we first dereference u.p (reading uninitialized memory)
50+
let _p = &raw const *(u.p); //~ ERROR access to union field is unsafe
51+
}
52+
3453
fn assign_noncopy_union_field(mut u: URefCell) {
3554
u.a = (ManuallyDrop::new(RefCell::new(0)), 1); // OK (assignment does not drop)
3655
u.a.0 = ManuallyDrop::new(RefCell::new(0)); // OK (assignment does not drop)
@@ -57,6 +76,20 @@ fn main() {
5776
let a = u1.a; //~ ERROR access to union field is unsafe
5877
u1.a = 11; // OK
5978

79+
let mut u2 = U1 { a: 10 };
80+
let a = &raw mut u2.a; // OK
81+
unsafe { *a = 3 };
82+
83+
let mut u3 = U1 { a: 10 };
84+
let a = std::ptr::addr_of_mut!(u3.a); // OK
85+
unsafe { *a = 14 };
86+
87+
let u4 = U5 { a: 2 };
88+
let vec = vec![1, 2, 3];
89+
// This is unsafe because we read u4.a (potentially uninitialized memory)
90+
// to use as an array index
91+
let _a = &raw const vec[u4.a]; //~ ERROR access to union field is unsafe
92+
6093
let U1 { a } = u1; //~ ERROR access to union field is unsafe
6194
if let U1 { a: 12 } = u1 {} //~ ERROR access to union field is unsafe
6295
if let Some(U1 { a: 13 }) = Some(u1) {} //~ ERROR access to union field is unsafe
@@ -73,4 +106,44 @@ fn main() {
73106
let mut u3 = U3 { a: ManuallyDrop::new(String::from("old")) }; // OK
74107
u3.a = ManuallyDrop::new(String::from("new")); // OK (assignment does not drop)
75108
*u3.a = String::from("new"); //~ ERROR access to union field is unsafe
109+
110+
let mut unions = [U1 { a: 1 }, U1 { a: 2 }];
111+
112+
// Array indexing + union field raw borrow - should be OK
113+
let ptr = &raw mut unions[0].a; // OK
114+
let ptr2 = &raw const unions[1].a; // OK
115+
116+
let a = A { a: 0 };
117+
let _p = &raw const (**a.b).c; //~ ERROR access to union field is unsafe
118+
119+
arbitrary_deref();
120+
}
121+
122+
// regression test for https://github.com/rust-lang/rust/pull/141469#discussion_r2312546218
123+
fn arbitrary_deref() {
124+
use std::ops::Deref;
125+
126+
union A {
127+
a: usize,
128+
b: B,
129+
}
130+
131+
#[derive(Copy, Clone)]
132+
struct B(&'static str);
133+
134+
impl Deref for B {
135+
type Target = C;
136+
137+
fn deref(&self) -> &C {
138+
println!("{:?}", self.0);
139+
&C { c: 0 }
140+
}
141+
}
142+
143+
union C {
144+
c: usize,
145+
}
146+
147+
let a = A { a: 0 };
148+
let _p = &raw const (*a.b).c; //~ ERROR access to union field is unsafe
76149
}

tests/ui/union/union-unsafe.stderr

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,115 @@
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:36: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:50: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:62:6
1119
|
1220
LL | *u3.a = T::default();
1321
| ^^^^ access to union field
1422
|
1523
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
1624

1725
error[E0133]: access to union field is unsafe and requires unsafe function or block
18-
--> $DIR/union-unsafe.rs:49:6
26+
--> $DIR/union-unsafe.rs:68:6
1927
|
2028
LL | *u3.a = T::default();
2129
| ^^^^ access to union field
2230
|
2331
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
2432

2533
error[E0133]: access to union field is unsafe and requires unsafe function or block
26-
--> $DIR/union-unsafe.rs:57:13
34+
--> $DIR/union-unsafe.rs:76:13
2735
|
2836
LL | let a = u1.a;
2937
| ^^^^ access to union field
3038
|
3139
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
3240

3341
error[E0133]: access to union field is unsafe and requires unsafe function or block
34-
--> $DIR/union-unsafe.rs:60:14
42+
--> $DIR/union-unsafe.rs:91:29
43+
|
44+
LL | let _a = &raw const vec[u4.a];
45+
| ^^^^ access to union field
46+
|
47+
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
48+
49+
error[E0133]: access to union field is unsafe and requires unsafe function or block
50+
--> $DIR/union-unsafe.rs:93:14
3551
|
3652
LL | let U1 { a } = u1;
3753
| ^ access to union field
3854
|
3955
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
4056

4157
error[E0133]: access to union field is unsafe and requires unsafe function or block
42-
--> $DIR/union-unsafe.rs:61:20
58+
--> $DIR/union-unsafe.rs:94:20
4359
|
4460
LL | if let U1 { a: 12 } = u1 {}
4561
| ^^ access to union field
4662
|
4763
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
4864

4965
error[E0133]: access to union field is unsafe and requires unsafe function or block
50-
--> $DIR/union-unsafe.rs:62:25
66+
--> $DIR/union-unsafe.rs:95:25
5167
|
5268
LL | if let Some(U1 { a: 13 }) = Some(u1) {}
5369
| ^^ access to union field
5470
|
5571
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
5672

5773
error[E0133]: access to union field is unsafe and requires unsafe function or block
58-
--> $DIR/union-unsafe.rs:67:6
74+
--> $DIR/union-unsafe.rs:100:6
5975
|
6076
LL | *u2.a = String::from("new");
6177
| ^^^^ access to union field
6278
|
6379
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
6480

6581
error[E0133]: access to union field is unsafe and requires unsafe function or block
66-
--> $DIR/union-unsafe.rs:71:6
82+
--> $DIR/union-unsafe.rs:104:6
6783
|
6884
LL | *u3.a = 1;
6985
| ^^^^ access to union field
7086
|
7187
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
7288

7389
error[E0133]: access to union field is unsafe and requires unsafe function or block
74-
--> $DIR/union-unsafe.rs:75:6
90+
--> $DIR/union-unsafe.rs:108:6
7591
|
7692
LL | *u3.a = String::from("new");
7793
| ^^^^ access to union field
7894
|
7995
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
8096

81-
error: aborting due to 10 previous errors
97+
error[E0133]: access to union field is unsafe and requires unsafe function or block
98+
--> $DIR/union-unsafe.rs:117:28
99+
|
100+
LL | let _p = &raw const (**a.b).c;
101+
| ^^^ access to union field
102+
|
103+
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
104+
105+
error[E0133]: access to union field is unsafe and requires unsafe function or block
106+
--> $DIR/union-unsafe.rs:148:27
107+
|
108+
LL | let _p = &raw const (*a.b).c;
109+
| ^^^ access to union field
110+
|
111+
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
112+
113+
error: aborting due to 14 previous errors
82114

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

0 commit comments

Comments
 (0)