about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-10-29 12:21:09 +0000
committerbors <bors@rust-lang.org>2021-10-29 12:21:09 +0000
commit9ed5b94b28e758996db395d472e0345d0ffe612d (patch)
tree1ad7db17a867c13471425e8578737298ad440099
parent37f70a0e1e04086aee7ae57fbefd6d4071953506 (diff)
parent3f778f31b6b285d41973a36ee1f4a2291d5f6a03 (diff)
downloadrust-9ed5b94b28e758996db395d472e0345d0ffe612d.tar.gz
rust-9ed5b94b28e758996db395d472e0345d0ffe612d.zip
Auto merge of #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 #90268.

`@rust-lang/wg-const-eval`
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs3
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs12
-rw-r--r--src/test/ui/consts/qualif-union.rs32
-rw-r--r--src/test/ui/consts/qualif-union.stderr57
4 files changed, 103 insertions, 1 deletions
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index aa42f8936f3..0fdb772c262 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -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...
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index ff2271fb396..38576230883 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -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);
diff --git a/src/test/ui/consts/qualif-union.rs b/src/test/ui/consts/qualif-union.rs
new file mode 100644
index 00000000000..2054b5b89ed
--- /dev/null
+++ b/src/test/ui/consts/qualif-union.rs
@@ -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
+}
diff --git a/src/test/ui/consts/qualif-union.stderr b/src/test/ui/consts/qualif-union.stderr
new file mode 100644
index 00000000000..fda8ad4a3bc
--- /dev/null
+++ b/src/test/ui/consts/qualif-union.stderr
@@ -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`.