Skip to content

Commit 9ed5b94

Browse files
committed
Auto merge of rust-lang#90373 - tmiasko:union-qualification, r=oli-obk
Use type based qualification for unions Union field access is currently qualified based on the qualification of a value previously assigned to the union. At the same time, every union access transmutes the content of the union, which might result in a different qualification. For example, consider constants A and B as defined below, under the current rules neither contains interior mutability, since a value used in the initial assignment did not contain `UnsafeCell` constructor. ```rust #![feature(untagged_unions)] union U { i: u32, c: std::cell::Cell<u32> } const A: U = U { i: 0 }; const B: std::cell::Cell<u32> = unsafe { U { i: 0 }.c }; ``` To avoid the issue, the changes here propose to consider the content of a union as opaque and use type based qualification for union types. Fixes rust-lang#90268. `@rust-lang/wg-const-eval`
2 parents 37f70a0 + 3f778f3 commit 9ed5b94

File tree

4 files changed

+103
-1
lines changed

4 files changed

+103
-1
lines changed

compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

+3
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ where
258258
if Q::in_adt_inherently(cx, def, substs) {
259259
return true;
260260
}
261+
if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) {
262+
return true;
263+
}
261264
}
262265

263266
// Otherwise, proceed structurally...

compiler/rustc_const_eval/src/transform/check_consts/resolver.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,19 @@ where
4747
}
4848
}
4949

50-
fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
50+
fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, mut value: bool) {
5151
debug_assert!(!place.is_indirect());
5252

53+
if !value {
54+
for (base, _elem) in place.iter_projections() {
55+
let base_ty = base.ty(self.ccx.body, self.ccx.tcx);
56+
if base_ty.ty.is_union() && Q::in_any_value_of_ty(self.ccx, base_ty.ty) {
57+
value = true;
58+
break;
59+
}
60+
}
61+
}
62+
5363
match (value, place.as_ref()) {
5464
(true, mir::PlaceRef { local, .. }) => {
5565
self.state.qualif.insert(local);

src/test/ui/consts/qualif-union.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Checks that unions use type based qualification. Regression test for issue #90268.
2+
#![feature(untagged_unions)]
3+
use std::cell::Cell;
4+
5+
union U { i: u32, c: Cell<u32> }
6+
7+
const C1: Cell<u32> = {
8+
unsafe { U { c: Cell::new(0) }.c }
9+
};
10+
11+
const C2: Cell<u32> = {
12+
unsafe { U { i : 0 }.c }
13+
};
14+
15+
const C3: Cell<u32> = {
16+
let mut u = U { i: 0 };
17+
u.i = 1;
18+
unsafe { u.c }
19+
};
20+
21+
const C4: U = U { i: 0 };
22+
23+
const C5: [U; 1] = [U {i : 0}; 1];
24+
25+
fn main() {
26+
// Interior mutability should prevent promotion.
27+
let _: &'static _ = &C1; //~ ERROR temporary value dropped while borrowed
28+
let _: &'static _ = &C2; //~ ERROR temporary value dropped while borrowed
29+
let _: &'static _ = &C3; //~ ERROR temporary value dropped while borrowed
30+
let _: &'static _ = &C4; //~ ERROR temporary value dropped while borrowed
31+
let _: &'static _ = &C5; //~ ERROR temporary value dropped while borrowed
32+
}
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
error[E0716]: temporary value dropped while borrowed
2+
--> $DIR/qualif-union.rs:27:26
3+
|
4+
LL | let _: &'static _ = &C1;
5+
| ---------- ^^ creates a temporary which is freed while still in use
6+
| |
7+
| type annotation requires that borrow lasts for `'static`
8+
...
9+
LL | }
10+
| - temporary value is freed at the end of this statement
11+
12+
error[E0716]: temporary value dropped while borrowed
13+
--> $DIR/qualif-union.rs:28:26
14+
|
15+
LL | let _: &'static _ = &C2;
16+
| ---------- ^^ creates a temporary which is freed while still in use
17+
| |
18+
| type annotation requires that borrow lasts for `'static`
19+
...
20+
LL | }
21+
| - temporary value is freed at the end of this statement
22+
23+
error[E0716]: temporary value dropped while borrowed
24+
--> $DIR/qualif-union.rs:29:26
25+
|
26+
LL | let _: &'static _ = &C3;
27+
| ---------- ^^ creates a temporary which is freed while still in use
28+
| |
29+
| type annotation requires that borrow lasts for `'static`
30+
...
31+
LL | }
32+
| - temporary value is freed at the end of this statement
33+
34+
error[E0716]: temporary value dropped while borrowed
35+
--> $DIR/qualif-union.rs:30:26
36+
|
37+
LL | let _: &'static _ = &C4;
38+
| ---------- ^^ creates a temporary which is freed while still in use
39+
| |
40+
| type annotation requires that borrow lasts for `'static`
41+
LL | let _: &'static _ = &C5;
42+
LL | }
43+
| - temporary value is freed at the end of this statement
44+
45+
error[E0716]: temporary value dropped while borrowed
46+
--> $DIR/qualif-union.rs:31:26
47+
|
48+
LL | let _: &'static _ = &C5;
49+
| ---------- ^^ creates a temporary which is freed while still in use
50+
| |
51+
| type annotation requires that borrow lasts for `'static`
52+
LL | }
53+
| - temporary value is freed at the end of this statement
54+
55+
error: aborting due to 5 previous errors
56+
57+
For more information about this error, try `rustc --explain E0716`.

0 commit comments

Comments
 (0)