Skip to content

Commit

Permalink
Auto merge of #90373 - tmiasko:union-qualification, r=oli-obk
Browse files Browse the repository at this point in the history
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 #90268.

`@rust-lang/wg-const-eval`
  • Loading branch information
bors committed Oct 29, 2021
2 parents 37f70a0 + 3f778f3 commit 9ed5b94
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -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...
Expand Down
12 changes: 11 additions & 1 deletion compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,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.state.qualif.insert(local);
Expand Down
32 changes: 32 additions & 0 deletions src/test/ui/consts/qualif-union.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 57 additions & 0 deletions src/test/ui/consts/qualif-union.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 9ed5b94

Please sign in to comment.