Skip to content

Commit 7f2baba

Browse files
committed
Auto merge of #48092 - eddyb:discriminate-the-void, r=nikomatsakis
rustc_mir: insert a dummy access to places being matched on, when building MIR. Fixes #47412 by adding a `_dummy = Discriminant(place)` before each `match place {...}`. r? @nikomatsakis
2 parents d0f1f42 + 8af134e commit 7f2baba

File tree

10 files changed

+154
-74
lines changed

10 files changed

+154
-74
lines changed

Diff for: src/librustc/mir/tcx.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,8 @@ impl<'tcx> Rvalue<'tcx> {
182182
if let ty::TyAdt(adt_def, _) = ty.sty {
183183
adt_def.repr.discr_type().to_ty(tcx)
184184
} else {
185-
// Undefined behaviour, bug for now; may want to return something for
186-
// the `discriminant` intrinsic later.
187-
bug!("Rvalue::Discriminant on Place of type {:?}", ty);
185+
// This can only be `0`, for now, so `u8` will suffice.
186+
tcx.types.u8
188187
}
189188
}
190189
Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),

Diff for: src/librustc_mir/build/matches/mod.rs

+16
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
3838
-> BlockAnd<()> {
3939
let discriminant_place = unpack!(block = self.as_place(block, discriminant));
4040

41+
// Matching on a `discriminant_place` with an uninhabited type doesn't
42+
// generate any memory reads by itself, and so if the place "expression"
43+
// contains unsafe operations like raw pointer dereferences or union
44+
// field projections, we wouldn't know to require an `unsafe` block
45+
// around a `match` equivalent to `std::intrinsics::unreachable()`.
46+
// See issue #47412 for this hole being discovered in the wild.
47+
//
48+
// HACK(eddyb) Work around the above issue by adding a dummy inspection
49+
// of `discriminant_place`, specifically by applying `Rvalue::Discriminant`
50+
// (which will work regardless of type) and storing the result in a temp.
51+
let dummy_source_info = self.source_info(span);
52+
let dummy_access = Rvalue::Discriminant(discriminant_place.clone());
53+
let dummy_ty = dummy_access.ty(&self.local_decls, self.hir.tcx());
54+
let dummy_temp = self.temp(dummy_ty, dummy_source_info.span);
55+
self.cfg.push_assign(block, dummy_source_info, &dummy_temp, dummy_access);
56+
4157
let mut arm_blocks = ArmBlocks {
4258
blocks: arms.iter()
4359
.map(|_| self.cfg.start_new_block())

Diff for: src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ fn main() {
7272
{
7373
let mut e = Baz::X(2);
7474
let _e0 = e.x();
75-
match e {
75+
match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
7676
Baz::X(value) => value
7777
//[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed
7878
//[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed
@@ -110,7 +110,7 @@ fn main() {
110110
{
111111
let mut e = Box::new(Baz::X(3));
112112
let _e0 = e.x();
113-
match *e {
113+
match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed
114114
Baz::X(value) => value
115115
//[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed
116116
//[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed
@@ -127,25 +127,25 @@ fn main() {
127127
{
128128
let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
129129
let _v = &mut v;
130-
match v {
130+
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
131131
&[x, _, .., _, _] => println!("{}", x),
132132
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
133133
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
134134
_ => panic!("other case"),
135135
}
136-
match v {
136+
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
137137
&[_, x, .., _, _] => println!("{}", x),
138138
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
139139
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
140140
_ => panic!("other case"),
141141
}
142-
match v {
142+
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
143143
&[_, _, .., x, _] => println!("{}", x),
144144
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
145145
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
146146
_ => panic!("other case"),
147147
}
148-
match v {
148+
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
149149
&[_, _, .., _, x] => println!("{}", x),
150150
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
151151
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
@@ -156,25 +156,25 @@ fn main() {
156156
{
157157
let mut v = &[1, 2, 3, 4, 5];
158158
let _v = &mut v;
159-
match v {
159+
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
160160
&[x..] => println!("{:?}", x),
161161
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
162162
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
163163
_ => panic!("other case"),
164164
}
165-
match v {
165+
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
166166
&[_, x..] => println!("{:?}", x),
167167
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
168168
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
169169
_ => panic!("other case"),
170170
}
171-
match v {
171+
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
172172
&[x.., _] => println!("{:?}", x),
173173
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
174174
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
175175
_ => panic!("other case"),
176176
}
177-
match v {
177+
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
178178
&[_, x.., _] => println!("{:?}", x),
179179
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
180180
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
@@ -187,7 +187,7 @@ fn main() {
187187

188188
let mut e = E::A(3);
189189
let _e = &mut e;
190-
match e {
190+
match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
191191
E::A(ref ax) =>
192192
//[ast]~^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable
193193
//[mir]~^^ ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable
@@ -205,14 +205,14 @@ fn main() {
205205
struct S { x: F, y: (u32, u32), };
206206
let mut s = S { x: F { x: 1, y: 2}, y: (999, 998) };
207207
let _s = &mut s;
208-
match s {
208+
match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
209209
S { y: (ref y0, _), .. } =>
210210
//[ast]~^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable
211211
//[mir]~^^ ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable
212212
println!("y0: {:?}", y0),
213213
_ => panic!("other case"),
214214
}
215-
match s {
215+
match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
216216
S { x: F { y: ref x0, .. }, .. } =>
217217
//[ast]~^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable
218218
//[mir]~^^ ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable
@@ -263,7 +263,7 @@ fn main() {
263263
struct F {x: u32, y: u32};
264264
let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}];
265265
let _v = &mut v;
266-
match v {
266+
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
267267
&[_, F {x: ref xf, ..}] => println!("{}", xf),
268268
//[mir]~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable
269269
// No errors in AST

Diff for: src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ enum Foo {
1919
fn match_enum() {
2020
let mut foo = Foo::B;
2121
let p = &mut foo;
22-
let _ = match foo {
22+
let _ = match foo { //[mir]~ ERROR [E0503]
2323
Foo::B => 1, //[mir]~ ERROR [E0503]
2424
_ => 2,
2525
Foo::A(x) => x //[ast]~ ERROR [E0503]
@@ -31,7 +31,7 @@ fn match_enum() {
3131
fn main() {
3232
let mut x = 1;
3333
let _x = &mut x;
34-
let _ = match x {
34+
let _ = match x { //[mir]~ ERROR [E0503]
3535
x => x + 1, //[ast]~ ERROR [E0503]
3636
//[mir]~^ ERROR [E0503]
3737
y => y + 2, //[ast]~ ERROR [E0503]

Diff for: src/test/compile-fail/issue-47412.rs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[derive(Copy, Clone)]
12+
enum Void {}
13+
14+
// Tests that we detect unsafe places (specifically, union fields and
15+
// raw pointer dereferences), even when they're matched on while having
16+
// an uninhabited type (equivalent to `std::intrinsics::unreachable()`).
17+
18+
fn union_field() {
19+
union Union { unit: (), void: Void }
20+
let u = Union { unit: () };
21+
match u.void {}
22+
//~^ ERROR access to union field requires unsafe function or block
23+
}
24+
25+
fn raw_ptr_deref() {
26+
let ptr = std::ptr::null::<Void>();
27+
match *ptr {}
28+
//~^ ERROR dereference of raw pointer requires unsafe function or block
29+
}
30+
31+
fn main() {}

Diff for: src/test/mir-opt/match_false_edges.rs

+55-52
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,18 @@ fn main() {
5353
// bb0: {
5454
// ...
5555
// _2 = std::option::Option<i32>::Some(const 42i32,);
56-
// _5 = discriminant(_2);
57-
// switchInt(move _5) -> [0isize: bb6, 1isize: bb4, otherwise: bb8];
56+
// _3 = discriminant(_2);
57+
// _6 = discriminant(_2);
58+
// switchInt(move _6) -> [0isize: bb6, 1isize: bb4, otherwise: bb8];
5859
// }
5960
// bb1: {
6061
// resume;
6162
// }
6263
// bb2: { // arm1
63-
// StorageLive(_7);
64-
// _7 = _3;
65-
// _1 = (const 1i32, move _7);
66-
// StorageDead(_7);
64+
// StorageLive(_8);
65+
// _8 = _4;
66+
// _1 = (const 1i32, move _8);
67+
// StorageDead(_8);
6768
// goto -> bb13;
6869
// }
6970
// bb3: { // binding3(empty) and arm3
@@ -86,24 +87,24 @@ fn main() {
8687
// unreachable;
8788
// }
8889
// bb9: { // binding1 and guard
89-
// StorageLive(_3);
90-
// _3 = ((_2 as Some).0: i32);
91-
// StorageLive(_6);
92-
// _6 = const guard() -> [return: bb10, unwind: bb1];
90+
// StorageLive(_4);
91+
// _4 = ((_2 as Some).0: i32);
92+
// StorageLive(_7);
93+
// _7 = const guard() -> [return: bb10, unwind: bb1];
9394
// }
9495
// bb10: { // end of guard
95-
// switchInt(move _6) -> [0u8: bb11, otherwise: bb2];
96+
// switchInt(move _7) -> [0u8: bb11, otherwise: bb2];
9697
// }
9798
// bb11: { // to pre_binding2
9899
// falseEdges -> [real: bb5, imaginary: bb5];
99100
// }
100101
// bb12: { // bindingNoLandingPads.before.mir2 and arm2
101-
// StorageLive(_4);
102-
// _4 = ((_2 as Some).0: i32);
103-
// StorageLive(_8);
104-
// _8 = _4;
105-
// _1 = (const 2i32, move _8);
106-
// StorageDead(_8);
102+
// StorageLive(_5);
103+
// _5 = ((_2 as Some).0: i32);
104+
// StorageLive(_9);
105+
// _9 = _5;
106+
// _1 = (const 2i32, move _9);
107+
// StorageDead(_9);
107108
// goto -> bb13;
108109
// }
109110
// bb13: {
@@ -116,17 +117,18 @@ fn main() {
116117
// bb0: {
117118
// ...
118119
// _2 = std::option::Option<i32>::Some(const 42i32,);
119-
// _5 = discriminant(_2);
120-
// switchInt(move _5) -> [0isize: bb5, 1isize: bb4, otherwise: bb8];
120+
// _3 = discriminant(_2);
121+
// _6 = discriminant(_2);
122+
// switchInt(move _6) -> [0isize: bb5, 1isize: bb4, otherwise: bb8];
121123
// }
122124
// bb1: {
123125
// resume;
124126
// }
125127
// bb2: { // arm1
126-
// StorageLive(_7);
127-
// _7 = _3;
128-
// _1 = (const 1i32, move _7);
129-
// StorageDead(_7);
128+
// StorageLive(_8);
129+
// _8 = _4;
130+
// _1 = (const 1i32, move _8);
131+
// StorageDead(_8);
130132
// goto -> bb13;
131133
// }
132134
// bb3: { // binding3(empty) and arm3
@@ -149,24 +151,24 @@ fn main() {
149151
// unreachable;
150152
// }
151153
// bb9: { // binding1 and guard
152-
// StorageLive(_3);
153-
// _3 = ((_2 as Some).0: i32);
154-
// StorageLive(_6);
155-
// _6 = const guard() -> [return: bb10, unwind: bb1];
154+
// StorageLive(_4);
155+
// _4 = ((_2 as Some).0: i32);
156+
// StorageLive(_7);
157+
// _7 = const guard() -> [return: bb10, unwind: bb1];
156158
// }
157159
// bb10: { // end of guard
158-
// switchInt(move _6) -> [0u8: bb11, otherwise: bb2];
160+
// switchInt(move _7) -> [0u8: bb11, otherwise: bb2];
159161
// }
160162
// bb11: { // to pre_binding2
161163
// falseEdges -> [real: bb6, imaginary: bb5];
162164
// }
163165
// bb12: { // binding2 and arm2
164-
// StorageLive(_4);
165-
// _4 = ((_2 as Some).0: i32);
166-
// StorageLive(_8);
167-
// _8 = _4;
168-
// _1 = (const 2i32, move _8);
169-
// StorageDead(_8);
166+
// StorageLive(_5);
167+
// _5 = ((_2 as Some).0: i32);
168+
// StorageLive(_9);
169+
// _9 = _5;
170+
// _1 = (const 2i32, move _9);
171+
// StorageDead(_9);
170172
// goto -> bb13;
171173
// }
172174
// bb13: {
@@ -179,8 +181,9 @@ fn main() {
179181
// bb0: {
180182
// ...
181183
// _2 = std::option::Option<i32>::Some(const 1i32,);
182-
// _7 = discriminant(_2);
183-
// switchInt(move _7) -> [1isize: bb4, otherwise: bb5];
184+
// _3 = discriminant(_2);
185+
// _8 = discriminant(_2);
186+
// switchInt(move _8) -> [1isize: bb4, otherwise: bb5];
184187
// }
185188
// bb1: {
186189
// resume;
@@ -210,41 +213,41 @@ fn main() {
210213
// unreachable;
211214
// }
212215
// bb9: { // binding1: Some(w) if guard()
213-
// StorageLive(_3);
214-
// _3 = ((_2 as Some).0: i32);
215-
// StorageLive(_8);
216-
// _8 = const guard() -> [return: bb10, unwind: bb1];
216+
// StorageLive(_4);
217+
// _4 = ((_2 as Some).0: i32);
218+
// StorageLive(_9);
219+
// _9 = const guard() -> [return: bb10, unwind: bb1];
217220
// }
218221
// bb10: { //end of guard
219-
// switchInt(move _8) -> [0u8: bb11, otherwise: bb2];
222+
// switchInt(move _9) -> [0u8: bb11, otherwise: bb2];
220223
// }
221224
// bb11: { // to pre_binding2
222225
// falseEdges -> [real: bb5, imaginary: bb5];
223226
// }
224227
// bb12: { // binding2 & arm2
225-
// StorageLive(_4);
226-
// _4 = _2;
228+
// StorageLive(_5);
229+
// _5 = _2;
227230
// _1 = const 2i32;
228231
// goto -> bb17;
229232
// }
230233
// bb13: { // binding3: Some(y) if guard2(y)
231-
// StorageLive(_5);
232-
// _5 = ((_2 as Some).0: i32);
233-
// StorageLive(_10);
234+
// StorageLive(_6);
235+
// _6 = ((_2 as Some).0: i32);
234236
// StorageLive(_11);
235-
// _11 = _5;
236-
// _10 = const guard2(move _11) -> [return: bb14, unwind: bb1];
237+
// StorageLive(_12);
238+
// _12 = _6;
239+
// _11 = const guard2(move _12) -> [return: bb14, unwind: bb1];
237240
// }
238241
// bb14: { // end of guard2
239-
// StorageDead(_11);
240-
// switchInt(move _10) -> [0u8: bb15, otherwise: bb3];
242+
// StorageDead(_12);
243+
// switchInt(move _11) -> [0u8: bb15, otherwise: bb3];
241244
// }
242245
// bb15: { // to pre_binding4
243246
// falseEdges -> [real: bb7, imaginary: bb7];
244247
// }
245248
// bb16: { // binding4 & arm4
246-
// StorageLive(_6);
247-
// _6 = _2;
249+
// StorageLive(_7);
250+
// _7 = _2;
248251
// _1 = const 4i32;
249252
// goto -> bb17;
250253
// }

Diff for: src/test/ui/borrowck/issue-41962.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub fn main(){
1818
//~^ ERROR use of partially moved value: `maybe` (Ast) [E0382]
1919
//~| ERROR use of moved value: `(maybe as std::prelude::v1::Some).0` (Ast) [E0382]
2020
//~| ERROR use of moved value: `maybe` (Mir) [E0382]
21+
//~| ERROR use of moved value: `maybe` (Mir) [E0382]
2122
//~| ERROR use of moved value: `maybe.0` (Mir) [E0382]
2223
}
2324
}

0 commit comments

Comments
 (0)