Skip to content

Commit 1824973

Browse files
committed
auto merge of #16567 : jakub-/rust/issue-16149, r=pcwalton
Fixes #16149.
2 parents 3b65124 + d283574 commit 1824973

File tree

5 files changed

+90
-47
lines changed

5 files changed

+90
-47
lines changed

src/librustc/diagnostics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ register_diagnostics!(
139139
E0120,
140140
E0121,
141141
E0122,
142-
E0123,
143142
E0124,
144143
E0125,
145144
E0126,
@@ -173,5 +172,6 @@ register_diagnostics!(
173172
E0154,
174173
E0155,
175174
E0156,
176-
E0157
175+
E0157,
176+
E0158
177177
)

src/librustc/middle/check_match.rs

+65-29
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use std::gc::{Gc, GC};
2323
use std::iter::AdditiveIterator;
2424
use std::iter::range_inclusive;
2525
use syntax::ast::*;
26-
use syntax::ast_util::{is_unguarded, walk_pat};
26+
use syntax::ast_util::walk_pat;
2727
use syntax::codemap::{Span, Spanned, DUMMY_SP};
2828
use syntax::fold::{Folder, noop_fold_pat};
2929
use syntax::print::pprust::pat_to_string;
@@ -159,13 +159,31 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
159159
}
160160
}
161161

162-
// Third, check for unreachable arms.
163-
check_arms(cx, arms.as_slice());
162+
let mut static_inliner = StaticInliner::new(cx.tcx);
163+
let inlined_arms = arms
164+
.iter()
165+
.map(|arm| Arm {
166+
pats: arm.pats.iter().map(|pat| {
167+
static_inliner.fold_pat(*pat)
168+
}).collect(),
169+
..arm.clone()
170+
})
171+
.collect::<Vec<Arm>>();
172+
173+
if static_inliner.failed {
174+
return;
175+
}
176+
177+
// Third, check if there are any references to NaN that we should warn about.
178+
check_for_static_nan(cx, inlined_arms.as_slice());
179+
180+
// Fourth, check for unreachable arms.
181+
check_arms(cx, inlined_arms.as_slice());
164182

165183
// Finally, check if the whole match expression is exhaustive.
166184
// Check for empty enum, because is_useful only works on inhabited types.
167185
let pat_ty = node_id_to_type(cx.tcx, scrut.id);
168-
if arms.is_empty() {
186+
if inlined_arms.is_empty() {
169187
if !type_is_empty(cx.tcx, pat_ty) {
170188
// We know the type is inhabited, so this must be wrong
171189
span_err!(cx.tcx.sess, ex.span, E0002,
@@ -177,19 +195,16 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
177195
return;
178196
}
179197

180-
let mut static_inliner = StaticInliner { tcx: cx.tcx };
181-
let matrix: Matrix = arms
182-
.iter()
183-
.filter(|&arm| is_unguarded(arm))
184-
.flat_map(|arm| arm.pats.iter())
185-
.map(|pat| vec![static_inliner.fold_pat(*pat)])
198+
let matrix: Matrix = inlined_arms
199+
.move_iter()
200+
.filter(|arm| arm.guard.is_none())
201+
.flat_map(|arm| arm.pats.move_iter())
202+
.map(|pat| vec![pat])
186203
.collect();
187204
check_exhaustive(cx, ex.span, &matrix);
188205
},
189206
ExprForLoop(ref pat, _, _, _) => {
190-
let mut static_inliner = StaticInliner {
191-
tcx: cx.tcx
192-
};
207+
let mut static_inliner = StaticInliner::new(cx.tcx);
193208
match is_refutable(cx, static_inliner.fold_pat(*pat)) {
194209
Some(uncovered_pat) => {
195210
cx.tcx.sess.span_err(
@@ -216,28 +231,31 @@ fn is_expr_const_nan(tcx: &ty::ctxt, expr: &Expr) -> bool {
216231
}
217232
}
218233

219-
// Check for unreachable patterns
220-
fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
221-
let mut seen = Matrix(vec!());
222-
let mut static_inliner = StaticInliner { tcx: cx.tcx };
234+
// Check that we do not match against a static NaN (#6804)
235+
fn check_for_static_nan(cx: &MatchCheckCtxt, arms: &[Arm]) {
223236
for arm in arms.iter() {
224-
for pat in arm.pats.iter() {
225-
let inlined = static_inliner.fold_pat(*pat);
226-
227-
// Check that we do not match against a static NaN (#6804)
228-
walk_pat(&*inlined, |p| {
237+
for &pat in arm.pats.iter() {
238+
walk_pat(&*pat, |p| {
229239
match p.node {
230240
PatLit(expr) if is_expr_const_nan(cx.tcx, &*expr) => {
231-
span_warn!(cx.tcx.sess, pat.span, E0003,
241+
span_warn!(cx.tcx.sess, p.span, E0003,
232242
"unmatchable NaN in pattern, \
233243
use the is_nan method in a guard instead");
234244
}
235245
_ => ()
236246
}
237247
true
238248
});
249+
}
250+
}
251+
}
239252

240-
let v = vec![inlined];
253+
// Check for unreachable patterns
254+
fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
255+
let mut seen = Matrix(vec!());
256+
for arm in arms.iter() {
257+
for &pat in arm.pats.iter() {
258+
let v = vec![pat];
241259
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
242260
NotUseful => span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"),
243261
Useful => (),
@@ -293,7 +311,17 @@ fn const_val_to_expr(value: &const_val) -> Gc<Expr> {
293311
}
294312

295313
pub struct StaticInliner<'a> {
296-
pub tcx: &'a ty::ctxt
314+
pub tcx: &'a ty::ctxt,
315+
pub failed: bool
316+
}
317+
318+
impl<'a> StaticInliner<'a> {
319+
pub fn new<'a>(tcx: &'a ty::ctxt) -> StaticInliner<'a> {
320+
StaticInliner {
321+
tcx: tcx,
322+
failed: false
323+
}
324+
}
297325
}
298326

299327
impl<'a> Folder for StaticInliner<'a> {
@@ -302,9 +330,17 @@ impl<'a> Folder for StaticInliner<'a> {
302330
PatIdent(..) | PatEnum(..) => {
303331
let def = self.tcx.def_map.borrow().find_copy(&pat.id);
304332
match def {
305-
Some(DefStatic(did, _)) => {
306-
let const_expr = lookup_const_by_id(self.tcx, did).unwrap();
307-
const_expr_to_pat(self.tcx, const_expr)
333+
Some(DefStatic(did, _)) => match lookup_const_by_id(self.tcx, did) {
334+
Some(const_expr) => box (GC) Pat {
335+
span: pat.span,
336+
..(*const_expr_to_pat(self.tcx, const_expr)).clone()
337+
},
338+
None => {
339+
self.failed = true;
340+
span_err!(self.tcx.sess, pat.span, E0158,
341+
"extern statics cannot be referenced in patterns");
342+
pat
343+
}
308344
},
309345
_ => noop_fold_pat(pat, self)
310346
}
@@ -813,7 +849,7 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
813849
LocalFor => "`for` loop"
814850
};
815851

816-
let mut static_inliner = StaticInliner { tcx: cx.tcx };
852+
let mut static_inliner = StaticInliner::new(cx.tcx);
817853
match is_refutable(cx, static_inliner.fold_pat(loc.pat)) {
818854
Some(pat) => {
819855
span_err!(cx.tcx.sess, loc.pat.span, E0005,

src/librustc/middle/trans/_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1422,7 +1422,7 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>,
14221422
bindings_map: create_bindings_map(bcx, *arm.pats.get(0), discr_expr, &*arm.body)
14231423
}).collect();
14241424

1425-
let mut static_inliner = StaticInliner { tcx: scope_cx.tcx() };
1425+
let mut static_inliner = StaticInliner::new(scope_cx.tcx());
14261426
let mut matches = Vec::new();
14271427
for arm_data in arm_datas.iter() {
14281428
matches.extend(arm_data.arm.pats.iter().map(|&p| Match {

src/libsyntax/ast_util.rs

-15
Original file line numberDiff line numberDiff line change
@@ -209,21 +209,6 @@ pub fn name_to_dummy_lifetime(name: Name) -> Lifetime {
209209
name: name }
210210
}
211211

212-
pub fn is_unguarded(a: &Arm) -> bool {
213-
match a.guard {
214-
None => true,
215-
_ => false
216-
}
217-
}
218-
219-
pub fn unguarded_pat(a: &Arm) -> Option<Vec<Gc<Pat>>> {
220-
if is_unguarded(a) {
221-
Some(/* FIXME (#2543) */ a.pats.clone())
222-
} else {
223-
None
224-
}
225-
}
226-
227212
/// Generate a "pretty" name for an `impl` from its type and trait.
228213
/// This is designed so that symbols of `impl`'d methods give some
229214
/// hint of where they came from, (previously they would all just be

src/test/compile-fail/issue-16149.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2014 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+
extern {
12+
static externalValue: int;
13+
}
14+
15+
fn main() {
16+
let boolValue = match 42 {
17+
externalValue => true,
18+
//~^ ERROR extern statics cannot be referenced in patterns
19+
_ => false
20+
};
21+
}
22+

0 commit comments

Comments
 (0)