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.
This commit is contained in:
parent
4e0d3973fa
commit
3f778f31b6
4 changed files with 103 additions and 1 deletions
|
@ -258,6 +258,9 @@ where
|
|||
if Q::in_adt_inherently(cx, def, substs) {
|
||||
return true;
|
||||
}
|
||||
if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, proceed structurally...
|
||||
|
|
|
@ -42,9 +42,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
|
||||
fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, mut value: bool) {
|
||||
debug_assert!(!place.is_indirect());
|
||||
|
||||
if !value {
|
||||
for (base, _elem) in place.iter_projections() {
|
||||
let base_ty = base.ty(self.ccx.body, self.ccx.tcx);
|
||||
if base_ty.ty.is_union() && Q::in_any_value_of_ty(self.ccx, base_ty.ty) {
|
||||
value = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match (value, place.as_ref()) {
|
||||
(true, mir::PlaceRef { local, .. }) => {
|
||||
self.qualifs_per_local.insert(local);
|
||||
|
|
32
src/test/ui/consts/qualif-union.rs
Normal file
32
src/test/ui/consts/qualif-union.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Checks that unions use type based qualification. Regression test for issue #90268.
|
||||
#![feature(untagged_unions)]
|
||||
use std::cell::Cell;
|
||||
|
||||
union U { i: u32, c: Cell<u32> }
|
||||
|
||||
const C1: Cell<u32> = {
|
||||
unsafe { U { c: Cell::new(0) }.c }
|
||||
};
|
||||
|
||||
const C2: Cell<u32> = {
|
||||
unsafe { U { i : 0 }.c }
|
||||
};
|
||||
|
||||
const C3: Cell<u32> = {
|
||||
let mut u = U { i: 0 };
|
||||
u.i = 1;
|
||||
unsafe { u.c }
|
||||
};
|
||||
|
||||
const C4: U = U { i: 0 };
|
||||
|
||||
const C5: [U; 1] = [U {i : 0}; 1];
|
||||
|
||||
fn main() {
|
||||
// Interior mutability should prevent promotion.
|
||||
let _: &'static _ = &C1; //~ ERROR temporary value dropped while borrowed
|
||||
let _: &'static _ = &C2; //~ ERROR temporary value dropped while borrowed
|
||||
let _: &'static _ = &C3; //~ ERROR temporary value dropped while borrowed
|
||||
let _: &'static _ = &C4; //~ ERROR temporary value dropped while borrowed
|
||||
let _: &'static _ = &C5; //~ ERROR temporary value dropped while borrowed
|
||||
}
|
57
src/test/ui/consts/qualif-union.stderr
Normal file
57
src/test/ui/consts/qualif-union.stderr
Normal file
|
@ -0,0 +1,57 @@
|
|||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/qualif-union.rs:27:26
|
||||
|
|
||||
LL | let _: &'static _ = &C1;
|
||||
| ---------- ^^ creates a temporary which is freed while still in use
|
||||
| |
|
||||
| type annotation requires that borrow lasts for `'static`
|
||||
...
|
||||
LL | }
|
||||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/qualif-union.rs:28:26
|
||||
|
|
||||
LL | let _: &'static _ = &C2;
|
||||
| ---------- ^^ creates a temporary which is freed while still in use
|
||||
| |
|
||||
| type annotation requires that borrow lasts for `'static`
|
||||
...
|
||||
LL | }
|
||||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/qualif-union.rs:29:26
|
||||
|
|
||||
LL | let _: &'static _ = &C3;
|
||||
| ---------- ^^ creates a temporary which is freed while still in use
|
||||
| |
|
||||
| type annotation requires that borrow lasts for `'static`
|
||||
...
|
||||
LL | }
|
||||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/qualif-union.rs:30:26
|
||||
|
|
||||
LL | let _: &'static _ = &C4;
|
||||
| ---------- ^^ creates a temporary which is freed while still in use
|
||||
| |
|
||||
| type annotation requires that borrow lasts for `'static`
|
||||
LL | let _: &'static _ = &C5;
|
||||
LL | }
|
||||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/qualif-union.rs:31:26
|
||||
|
|
||||
LL | let _: &'static _ = &C5;
|
||||
| ---------- ^^ creates a temporary which is freed while still in use
|
||||
| |
|
||||
| type annotation requires that borrow lasts for `'static`
|
||||
LL | }
|
||||
| - temporary value is freed at the end of this statement
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0716`.
|
Loading…
Add table
Reference in a new issue