Skip to content

Commit 98c3128

Browse files
committed
Auto merge of #39127 - canndrew:unreachable-pattern-errors-into-warnings, r=arielb1
Change unreachable pattern ICEs to warnings Allow code with unreachable `?` and `for` patterns to compile. Add some tests.
2 parents 44858b8 + 0aad529 commit 98c3128

File tree

5 files changed

+135
-18
lines changed

5 files changed

+135
-18
lines changed

src/librustc/hir/lowering.rs

+35-7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use util::nodemap::{NodeMap, FxHashMap};
5151
use std::collections::BTreeMap;
5252
use std::iter;
5353

54+
use syntax::attr;
5455
use syntax::ast::*;
5556
use syntax::errors;
5657
use syntax::ptr::P;
@@ -1831,8 +1832,9 @@ impl<'a> LoweringContext<'a> {
18311832
// to:
18321833
//
18331834
// match Carrier::translate(<expr>) {
1834-
// Ok(val) => val,
1835-
// Err(err) => return Carrier::from_error(From::from(err))
1835+
// Ok(val) => #[allow(unreachable_code)] val,
1836+
// Err(err) => #[allow(unreachable_code)]
1837+
// return Carrier::from_error(From::from(err)),
18361838
// }
18371839
let unstable_span = self.allow_internal_unstable("?", e.span);
18381840

@@ -1846,17 +1848,36 @@ impl<'a> LoweringContext<'a> {
18461848
P(self.expr_call(e.span, path, hir_vec![sub_expr]))
18471849
};
18481850

1849-
// Ok(val) => val
1851+
// #[allow(unreachable_code)]
1852+
let attr = {
1853+
// allow(unreachable_code)
1854+
let allow = {
1855+
let allow_ident = self.str_to_ident("allow");
1856+
let uc_ident = self.str_to_ident("unreachable_code");
1857+
let uc_meta_item = attr::mk_spanned_word_item(e.span, uc_ident);
1858+
let uc_nested = NestedMetaItemKind::MetaItem(uc_meta_item);
1859+
let uc_spanned = respan(e.span, uc_nested);
1860+
attr::mk_spanned_list_item(e.span, allow_ident, vec![uc_spanned])
1861+
};
1862+
attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow)
1863+
};
1864+
let attrs = vec![attr];
1865+
1866+
// Ok(val) => #[allow(unreachable_code)] val,
18501867
let ok_arm = {
18511868
let val_ident = self.str_to_ident("val");
18521869
let val_pat = self.pat_ident(e.span, val_ident);
1853-
let val_expr = P(self.expr_ident(e.span, val_ident, val_pat.id));
1870+
let val_expr = P(self.expr_ident_with_attrs(e.span,
1871+
val_ident,
1872+
val_pat.id,
1873+
ThinVec::from(attrs.clone())));
18541874
let ok_pat = self.pat_ok(e.span, val_pat);
18551875

18561876
self.arm(hir_vec![ok_pat], val_expr)
18571877
};
18581878

1859-
// Err(err) => return Carrier::from_error(From::from(err))
1879+
// Err(err) => #[allow(unreachable_code)]
1880+
// return Carrier::from_error(From::from(err)),
18601881
let err_arm = {
18611882
let err_ident = self.str_to_ident("err");
18621883
let err_local = self.pat_ident(e.span, err_ident);
@@ -1876,7 +1897,7 @@ impl<'a> LoweringContext<'a> {
18761897

18771898
let ret_expr = P(self.expr(e.span,
18781899
hir::Expr_::ExprRet(Some(from_err_expr)),
1879-
ThinVec::new()));
1900+
ThinVec::from(attrs)));
18801901

18811902
let err_pat = self.pat_err(e.span, err_local);
18821903
self.arm(hir_vec![err_pat], ret_expr)
@@ -2028,6 +2049,13 @@ impl<'a> LoweringContext<'a> {
20282049
}
20292050

20302051
fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> hir::Expr {
2052+
self.expr_ident_with_attrs(span, id, binding, ThinVec::new())
2053+
}
2054+
2055+
fn expr_ident_with_attrs(&mut self, span: Span,
2056+
id: Name,
2057+
binding: NodeId,
2058+
attrs: ThinVec<Attribute>) -> hir::Expr {
20312059
let def = {
20322060
let defs = self.resolver.definitions();
20332061
Def::Local(defs.local_def_id(binding))
@@ -2039,7 +2067,7 @@ impl<'a> LoweringContext<'a> {
20392067
segments: hir_vec![hir::PathSegment::from_name(id)],
20402068
})));
20412069

2042-
self.expr(span, expr_path, ThinVec::new())
2070+
self.expr(span, expr_path, attrs)
20432071
}
20442072

20452073
fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> hir::Expr {

src/librustc_const_eval/check_match.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -308,14 +308,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
308308
.emit();
309309
},
310310

311-
hir::MatchSource::ForLoopDesugar => {
312-
// this is a bug, because on `match iter.next()` we cover
313-
// `Some(<head>)` and `None`. It's impossible to have an unreachable
314-
// pattern
315-
// (see libsyntax/ext/expand.rs for the full expansion of a for loop)
316-
span_bug!(pat.span, "unreachable for-loop pattern")
317-
},
318-
311+
hir::MatchSource::ForLoopDesugar |
319312
hir::MatchSource::Normal => {
320313
let mut diagnostic = Diagnostic::new(Level::Warning,
321314
"unreachable pattern");
@@ -329,9 +322,9 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
329322
hir_pat.id, diagnostic);
330323
},
331324

332-
hir::MatchSource::TryDesugar => {
333-
span_bug!(pat.span, "unreachable try pattern")
334-
},
325+
// Unreachable patterns in try expressions occur when one of the arms
326+
// are an uninhabited type. Which is OK.
327+
hir::MatchSource::TryDesugar => {}
335328
}
336329
}
337330
Useful => (),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
//#![feature(never_type)]
12+
13+
struct R<'a> {
14+
r: &'a R<'a>,
15+
}
16+
17+
fn foo(res: Result<u32, &R>) -> u32 {
18+
let Ok(x) = res;
19+
//~^ ERROR refutable pattern
20+
x
21+
}
22+
23+
fn main() {
24+
foo(Ok(23));
25+
}
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2013 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+
#![feature(never_type)]
12+
#![deny(unreachable_patterns)]
13+
14+
fn main() {
15+
let x: &[!] = &[];
16+
17+
for _ in x {}
18+
//~^ ERROR unreachable pattern
19+
}
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2013 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+
#![feature(never_type)]
12+
#![deny(unreachable_code)]
13+
#![deny(unreachable_patterns)]
14+
15+
enum Void {}
16+
17+
impl From<Void> for i32 {
18+
fn from(v: Void) -> i32 {
19+
match v {}
20+
}
21+
}
22+
23+
fn bar(x: Result<!, i32>) -> Result<u32, i32> {
24+
x?
25+
}
26+
27+
fn foo(x: Result<!, i32>) -> Result<u32, i32> {
28+
let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?;
29+
//~^ ERROR unreachable pattern
30+
//~| ERROR unreachable expression
31+
Ok(y)
32+
}
33+
34+
fn qux(x: Result<u32, Void>) -> Result<u32, i32> {
35+
Ok(x?)
36+
}
37+
38+
fn vom(x: Result<u32, Void>) -> Result<u32, i32> {
39+
let y = (match x { Ok(n) => Ok(n), Err(e) => Err(e) })?;
40+
//~^ ERROR unreachable pattern
41+
Ok(y)
42+
}
43+
44+
fn main() {
45+
let _ = bar(Err(123));
46+
let _ = foo(Err(123));
47+
let _ = qux(Ok(123));
48+
let _ = vom(Ok(123));
49+
}
50+

0 commit comments

Comments
 (0)