Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc_mir: insert a dummy access to places being matched on, when building MIR. #48092

Merged
merged 2 commits into from
Feb 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,8 @@ impl<'tcx> Rvalue<'tcx> {
if let ty::TyAdt(adt_def, _) = ty.sty {
adt_def.repr.discr_type().to_ty(tcx)
} else {
// Undefined behaviour, bug for now; may want to return something for
// the `discriminant` intrinsic later.
bug!("Rvalue::Discriminant on Place of type {:?}", ty);
// This can only be `0`, for now, so `u8` will suffice.
tcx.types.u8
}
}
Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
Expand Down
16 changes: 16 additions & 0 deletions src/librustc_mir/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
-> BlockAnd<()> {
let discriminant_place = unpack!(block = self.as_place(block, discriminant));

// Matching on a `discriminant_place` with an uninhabited type doesn't
// generate any memory reads by itself, and so if the place "expression"
// contains unsafe operations like raw pointer dereferences or union
// field projections, we wouldn't know to require an `unsafe` block
// around a `match` equivalent to `std::intrinsics::unreachable()`.
// See issue #47412 for this hole being discovered in the wild.
//
// HACK(eddyb) Work around the above issue by adding a dummy inspection
// of `discriminant_place`, specifically by applying `Rvalue::Discriminant`
// (which will work regardless of type) and storing the result in a temp.
let dummy_source_info = self.source_info(span);
let dummy_access = Rvalue::Discriminant(discriminant_place.clone());
let dummy_ty = dummy_access.ty(&self.local_decls, self.hir.tcx());
let dummy_temp = self.temp(dummy_ty, dummy_source_info.span);
self.cfg.push_assign(block, dummy_source_info, &dummy_temp, dummy_access);

let mut arm_blocks = ArmBlocks {
blocks: arms.iter()
.map(|_| self.cfg.start_new_block())
Expand Down
28 changes: 14 additions & 14 deletions src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ fn main() {
{
let mut e = Baz::X(2);
let _e0 = e.x();
match e {
match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
Baz::X(value) => value
//[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed
Expand Down Expand Up @@ -110,7 +110,7 @@ fn main() {
{
let mut e = Box::new(Baz::X(3));
let _e0 = e.x();
match *e {
match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed
Baz::X(value) => value
//[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed
Expand All @@ -127,25 +127,25 @@ fn main() {
{
let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let _v = &mut v;
match v {
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[x, _, .., _, _] => println!("{}", x),
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
match v {
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[_, x, .., _, _] => println!("{}", x),
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
match v {
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[_, _, .., x, _] => println!("{}", x),
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
match v {
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[_, _, .., _, x] => println!("{}", x),
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
Expand All @@ -156,25 +156,25 @@ fn main() {
{
let mut v = &[1, 2, 3, 4, 5];
let _v = &mut v;
match v {
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[x..] => println!("{:?}", x),
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
match v {
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[_, x..] => println!("{:?}", x),
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
match v {
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[x.., _] => println!("{:?}", x),
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
match v {
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[_, x.., _] => println!("{:?}", x),
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
Expand All @@ -187,7 +187,7 @@ fn main() {

let mut e = E::A(3);
let _e = &mut e;
match e {
match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
E::A(ref ax) =>
//[ast]~^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable
//[mir]~^^ ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable
Expand All @@ -205,14 +205,14 @@ fn main() {
struct S { x: F, y: (u32, u32), };
let mut s = S { x: F { x: 1, y: 2}, y: (999, 998) };
let _s = &mut s;
match s {
match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
S { y: (ref y0, _), .. } =>
//[ast]~^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable
//[mir]~^^ ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable
println!("y0: {:?}", y0),
_ => panic!("other case"),
}
match s {
match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
S { x: F { y: ref x0, .. }, .. } =>
//[ast]~^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable
//[mir]~^^ ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable
Expand Down Expand Up @@ -263,7 +263,7 @@ fn main() {
struct F {x: u32, y: u32};
let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}];
let _v = &mut v;
match v {
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[_, F {x: ref xf, ..}] => println!("{}", xf),
//[mir]~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable
// No errors in AST
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ enum Foo {
fn match_enum() {
let mut foo = Foo::B;
let p = &mut foo;
let _ = match foo {
let _ = match foo { //[mir]~ ERROR [E0503]
Foo::B => 1, //[mir]~ ERROR [E0503]
_ => 2,
Foo::A(x) => x //[ast]~ ERROR [E0503]
Expand All @@ -31,7 +31,7 @@ fn match_enum() {
fn main() {
let mut x = 1;
let _x = &mut x;
let _ = match x {
let _ = match x { //[mir]~ ERROR [E0503]
x => x + 1, //[ast]~ ERROR [E0503]
//[mir]~^ ERROR [E0503]
y => y + 2, //[ast]~ ERROR [E0503]
Expand Down
31 changes: 31 additions & 0 deletions src/test/compile-fail/issue-47412.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[derive(Copy, Clone)]
enum Void {}

// Tests that we detect unsafe places (specifically, union fields and
// raw pointer dereferences), even when they're matched on while having
// an uninhabited type (equivalent to `std::intrinsics::unreachable()`).

fn union_field() {
union Union { unit: (), void: Void }
let u = Union { unit: () };
match u.void {}
//~^ ERROR access to union field requires unsafe function or block
}

fn raw_ptr_deref() {
let ptr = std::ptr::null::<Void>();
match *ptr {}
//~^ ERROR dereference of raw pointer requires unsafe function or block
}

fn main() {}
107 changes: 55 additions & 52 deletions src/test/mir-opt/match_false_edges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,18 @@ fn main() {
// bb0: {
// ...
// _2 = std::option::Option<i32>::Some(const 42i32,);
// _5 = discriminant(_2);
// switchInt(move _5) -> [0isize: bb6, 1isize: bb4, otherwise: bb8];
// _3 = discriminant(_2);
// _6 = discriminant(_2);
// switchInt(move _6) -> [0isize: bb6, 1isize: bb4, otherwise: bb8];
// }
// bb1: {
// resume;
// }
// bb2: { // arm1
// StorageLive(_7);
// _7 = _3;
// _1 = (const 1i32, move _7);
// StorageDead(_7);
// StorageLive(_8);
// _8 = _4;
// _1 = (const 1i32, move _8);
// StorageDead(_8);
// goto -> bb13;
// }
// bb3: { // binding3(empty) and arm3
Expand All @@ -86,24 +87,24 @@ fn main() {
// unreachable;
// }
// bb9: { // binding1 and guard
// StorageLive(_3);
// _3 = ((_2 as Some).0: i32);
// StorageLive(_6);
// _6 = const guard() -> [return: bb10, unwind: bb1];
// StorageLive(_4);
// _4 = ((_2 as Some).0: i32);
// StorageLive(_7);
// _7 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: { // end of guard
// switchInt(move _6) -> [0u8: bb11, otherwise: bb2];
// switchInt(move _7) -> [0u8: bb11, otherwise: bb2];
// }
// bb11: { // to pre_binding2
// falseEdges -> [real: bb5, imaginary: bb5];
// }
// bb12: { // bindingNoLandingPads.before.mir2 and arm2
// StorageLive(_4);
// _4 = ((_2 as Some).0: i32);
// StorageLive(_8);
// _8 = _4;
// _1 = (const 2i32, move _8);
// StorageDead(_8);
// StorageLive(_5);
// _5 = ((_2 as Some).0: i32);
// StorageLive(_9);
// _9 = _5;
// _1 = (const 2i32, move _9);
// StorageDead(_9);
// goto -> bb13;
// }
// bb13: {
Expand All @@ -116,17 +117,18 @@ fn main() {
// bb0: {
// ...
// _2 = std::option::Option<i32>::Some(const 42i32,);
// _5 = discriminant(_2);
// switchInt(move _5) -> [0isize: bb5, 1isize: bb4, otherwise: bb8];
// _3 = discriminant(_2);
// _6 = discriminant(_2);
// switchInt(move _6) -> [0isize: bb5, 1isize: bb4, otherwise: bb8];
// }
// bb1: {
// resume;
// }
// bb2: { // arm1
// StorageLive(_7);
// _7 = _3;
// _1 = (const 1i32, move _7);
// StorageDead(_7);
// StorageLive(_8);
// _8 = _4;
// _1 = (const 1i32, move _8);
// StorageDead(_8);
// goto -> bb13;
// }
// bb3: { // binding3(empty) and arm3
Expand All @@ -149,24 +151,24 @@ fn main() {
// unreachable;
// }
// bb9: { // binding1 and guard
// StorageLive(_3);
// _3 = ((_2 as Some).0: i32);
// StorageLive(_6);
// _6 = const guard() -> [return: bb10, unwind: bb1];
// StorageLive(_4);
// _4 = ((_2 as Some).0: i32);
// StorageLive(_7);
// _7 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: { // end of guard
// switchInt(move _6) -> [0u8: bb11, otherwise: bb2];
// switchInt(move _7) -> [0u8: bb11, otherwise: bb2];
// }
// bb11: { // to pre_binding2
// falseEdges -> [real: bb6, imaginary: bb5];
// }
// bb12: { // binding2 and arm2
// StorageLive(_4);
// _4 = ((_2 as Some).0: i32);
// StorageLive(_8);
// _8 = _4;
// _1 = (const 2i32, move _8);
// StorageDead(_8);
// StorageLive(_5);
// _5 = ((_2 as Some).0: i32);
// StorageLive(_9);
// _9 = _5;
// _1 = (const 2i32, move _9);
// StorageDead(_9);
// goto -> bb13;
// }
// bb13: {
Expand All @@ -179,8 +181,9 @@ fn main() {
// bb0: {
// ...
// _2 = std::option::Option<i32>::Some(const 1i32,);
// _7 = discriminant(_2);
// switchInt(move _7) -> [1isize: bb4, otherwise: bb5];
// _3 = discriminant(_2);
// _8 = discriminant(_2);
// switchInt(move _8) -> [1isize: bb4, otherwise: bb5];
// }
// bb1: {
// resume;
Expand Down Expand Up @@ -210,41 +213,41 @@ fn main() {
// unreachable;
// }
// bb9: { // binding1: Some(w) if guard()
// StorageLive(_3);
// _3 = ((_2 as Some).0: i32);
// StorageLive(_8);
// _8 = const guard() -> [return: bb10, unwind: bb1];
// StorageLive(_4);
// _4 = ((_2 as Some).0: i32);
// StorageLive(_9);
// _9 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: { //end of guard
// switchInt(move _8) -> [0u8: bb11, otherwise: bb2];
// switchInt(move _9) -> [0u8: bb11, otherwise: bb2];
// }
// bb11: { // to pre_binding2
// falseEdges -> [real: bb5, imaginary: bb5];
// }
// bb12: { // binding2 & arm2
// StorageLive(_4);
// _4 = _2;
// StorageLive(_5);
// _5 = _2;
// _1 = const 2i32;
// goto -> bb17;
// }
// bb13: { // binding3: Some(y) if guard2(y)
// StorageLive(_5);
// _5 = ((_2 as Some).0: i32);
// StorageLive(_10);
// StorageLive(_6);
// _6 = ((_2 as Some).0: i32);
// StorageLive(_11);
// _11 = _5;
// _10 = const guard2(move _11) -> [return: bb14, unwind: bb1];
// StorageLive(_12);
// _12 = _6;
// _11 = const guard2(move _12) -> [return: bb14, unwind: bb1];
// }
// bb14: { // end of guard2
// StorageDead(_11);
// switchInt(move _10) -> [0u8: bb15, otherwise: bb3];
// StorageDead(_12);
// switchInt(move _11) -> [0u8: bb15, otherwise: bb3];
// }
// bb15: { // to pre_binding4
// falseEdges -> [real: bb7, imaginary: bb7];
// }
// bb16: { // binding4 & arm4
// StorageLive(_6);
// _6 = _2;
// StorageLive(_7);
// _7 = _2;
// _1 = const 4i32;
// goto -> bb17;
// }
Expand Down
1 change: 1 addition & 0 deletions src/test/ui/borrowck/issue-41962.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub fn main(){
//~^ ERROR use of partially moved value: `maybe` (Ast) [E0382]
//~| ERROR use of moved value: `(maybe as std::prelude::v1::Some).0` (Ast) [E0382]
//~| ERROR use of moved value: `maybe` (Mir) [E0382]
//~| ERROR use of moved value: `maybe` (Mir) [E0382]
//~| ERROR use of moved value: `maybe.0` (Mir) [E0382]
}
}
Expand Down
Loading