diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 03ca85faafff6..f3fba5b47be14 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -566,8 +566,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - if this.mode != Mode::Fn && - this.qualif.intersects(Qualif::STATIC) { + if this.mode == Mode::Fn { + let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx); + if let Some(def) = base_ty.ty_adt_def() { + if def.is_union() { + this.not_const(); + } + } + } else if this.qualif.intersects(Qualif::STATIC) { span_err!(this.tcx.sess, this.span, E0494, "cannot refer to the interior of another \ static, use a constant instead"); diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 74b9315f0c1ee..82ac112b534e9 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -445,9 +445,16 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } + hir::ExprField(ref expr, _) => { + if let Some(def) = v.tables.expr_ty(expr).ty_adt_def() { + if def.is_union() { + v.promotable = false + } + } + } + hir::ExprBlock(..) | hir::ExprIndex(..) | - hir::ExprField(..) | hir::ExprArray(_) | hir::ExprType(..) | hir::ExprTup(..) => {} diff --git a/src/test/run-pass/ctfe/union-ice.rs b/src/test/run-pass/ctfe/union-ice.rs deleted file mode 100644 index f83f49f298b90..0000000000000 --- a/src/test/run-pass/ctfe/union-ice.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(const_fn)] - -type Field1 = i32; -type Field2 = f32; -type Field3 = i64; - -union DummyUnion { - field1: Field1, - field2: Field2, - field3: Field3, -} - -const FLOAT1_AS_I32: i32 = 1065353216; -const UNION: DummyUnion = DummyUnion { field1: FLOAT1_AS_I32 }; - -const fn read_field1() -> Field1 { - const FIELD1: Field1 = unsafe { UNION.field1 }; - FIELD1 -} - -const fn read_field2() -> Field2 { - const FIELD2: Field2 = unsafe { UNION.field2 }; - FIELD2 -} - -const fn read_field3() -> Field3 { - const FIELD3: Field3 = unsafe { UNION.field3 }; - FIELD3 -} - -fn main() { - assert_eq!(read_field1(), FLOAT1_AS_I32); - assert_eq!(read_field2(), 1.0); - assert_eq!(read_field3(), unsafe { UNION.field3 }); -} diff --git a/src/test/run-pass/union/union-const-eval-field.rs b/src/test/run-pass/union/union-const-eval-field.rs index f83f49f298b90..a380b01dcc13f 100644 --- a/src/test/run-pass/union/union-const-eval-field.rs +++ b/src/test/run-pass/union/union-const-eval-field.rs @@ -10,7 +10,7 @@ #![feature(const_fn)] -type Field1 = i32; +type Field1 = (i32, u32); type Field2 = f32; type Field3 = i64; @@ -21,7 +21,7 @@ union DummyUnion { } const FLOAT1_AS_I32: i32 = 1065353216; -const UNION: DummyUnion = DummyUnion { field1: FLOAT1_AS_I32 }; +const UNION: DummyUnion = DummyUnion { field1: (FLOAT1_AS_I32, 0) }; const fn read_field1() -> Field1 { const FIELD1: Field1 = unsafe { UNION.field1 }; @@ -39,7 +39,15 @@ const fn read_field3() -> Field3 { } fn main() { - assert_eq!(read_field1(), FLOAT1_AS_I32); + let foo = FLOAT1_AS_I32; + assert_eq!(read_field1().0, foo); + assert_eq!(read_field1().0, FLOAT1_AS_I32); + + let foo = 1.0; + assert_eq!(read_field2(), foo); assert_eq!(read_field2(), 1.0); + assert_eq!(read_field3(), unsafe { UNION.field3 }); + let foo = unsafe { UNION.field3 }; + assert_eq!(read_field3(), foo); } diff --git a/src/test/ui/const-eval/union_promotion.rs b/src/test/ui/const-eval/union_promotion.rs new file mode 100644 index 0000000000000..714d7a4fc8b27 --- /dev/null +++ b/src/test/ui/const-eval/union_promotion.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(const_err)] + +union Foo { + a: &'static u32, + b: usize, +} + +fn main() { + let x: &'static bool = &unsafe { //~ borrowed value does not live long enough + Foo { a: &1 }.b == Foo { a: &2 }.b + }; +} diff --git a/src/test/ui/const-eval/union_promotion.stderr b/src/test/ui/const-eval/union_promotion.stderr new file mode 100644 index 0000000000000..b4aa91f2de723 --- /dev/null +++ b/src/test/ui/const-eval/union_promotion.stderr @@ -0,0 +1,16 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/union_promotion.rs:19:29 + | +LL | let x: &'static bool = &unsafe { //~ borrowed value does not live long enough + | _____________________________^ +LL | | Foo { a: &1 }.b == Foo { a: &2 }.b +LL | | }; + | |_____^ temporary value does not live long enough +LL | } + | - temporary value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`.