Skip to content

Commit 1c51f60

Browse files
committed
Change unreachable patterns ICEs to warnings
Allow code with unreachable `?` and `for` patterns to compile. Add some tests.
1 parent 31dee37 commit 1c51f60

File tree

5 files changed

+125
-20
lines changed

5 files changed

+125
-20
lines changed

src/librustc/hir/lowering.rs

Lines changed: 55 additions & 9 deletions
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;
@@ -1814,7 +1815,8 @@ impl<'a> LoweringContext<'a> {
18141815
let match_expr = P(self.expr_match(e.span,
18151816
into_iter_expr,
18161817
hir_vec![iter_arm],
1817-
hir::MatchSource::ForLoopDesugar));
1818+
hir::MatchSource::ForLoopDesugar,
1819+
ThinVec::new()));
18181820

18191821
// `{ let _result = ...; _result }`
18201822
// underscore prevents an unused_variables lint if the head diverges
@@ -1833,8 +1835,12 @@ impl<'a> LoweringContext<'a> {
18331835
ExprKind::Try(ref sub_expr) => {
18341836
// to:
18351837
//
1838+
// #[allow(unreachable_patterns)]
18361839
// match Carrier::translate(<expr>) {
1837-
// Ok(val) => val,
1840+
// Ok(val) => {
1841+
// #[allow(unreachable_code)]
1842+
// val
1843+
// }
18381844
// Err(err) => return Carrier::from_error(From::from(err))
18391845
// }
18401846
let unstable_span = self.allow_internal_unstable("?", e.span);
@@ -1849,14 +1855,31 @@ impl<'a> LoweringContext<'a> {
18491855
P(self.expr_call(e.span, path, hir_vec![sub_expr]))
18501856
};
18511857

1852-
// Ok(val) => val
1858+
// Ok(val) => { #[allow(unreachable_code)] val }
18531859
let ok_arm = {
18541860
let val_ident = self.str_to_ident("val");
18551861
let val_pat = self.pat_ident(e.span, val_ident);
1856-
let val_expr = P(self.expr_ident(e.span, val_ident, val_pat.id));
1862+
// #[allow(unreachable_code)]
1863+
let val_attr = {
1864+
// allow(unreachable_code)
1865+
let allow = {
1866+
let allow_ident = self.str_to_ident("allow");
1867+
let uc_ident = self.str_to_ident("unreachable_code");
1868+
let uc_meta_item = attr::mk_spanned_word_item(e.span, uc_ident);
1869+
let uc_nested_meta_item = NestedMetaItemKind::MetaItem(uc_meta_item);
1870+
let uc_spanned = respan(e.span, uc_nested_meta_item);
1871+
attr::mk_spanned_list_item(e.span, allow_ident, vec![uc_spanned])
1872+
};
1873+
attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow)
1874+
};
1875+
let attrs = From::from(vec![val_attr]);
1876+
let val_expr = P(self.expr_ident_with_attrs(e.span, val_ident, val_pat.id, attrs));
1877+
let val_block = P(self.block_expr(val_expr));
1878+
let ok_expr = P(self.expr_block(val_block, ThinVec::new()));
1879+
18571880
let ok_pat = self.pat_ok(e.span, val_pat);
18581881

1859-
self.arm(hir_vec![ok_pat], val_expr)
1882+
self.arm(hir_vec![ok_pat], ok_expr)
18601883
};
18611884

18621885
// Err(err) => return Carrier::from_error(From::from(err))
@@ -1885,8 +1908,23 @@ impl<'a> LoweringContext<'a> {
18851908
self.arm(hir_vec![err_pat], ret_expr)
18861909
};
18871910

1911+
// #[allow(unreachable_patterns)]
1912+
let match_attr = {
1913+
// allow(unreachable_patterns)
1914+
let allow = {
1915+
let allow_ident = self.str_to_ident("allow");
1916+
let up_ident = self.str_to_ident("unreachable_patterns");
1917+
let up_meta_item = attr::mk_spanned_word_item(e.span, up_ident);
1918+
let up_nested_meta_item = NestedMetaItemKind::MetaItem(up_meta_item);
1919+
let up_spanned = respan(e.span, up_nested_meta_item);
1920+
attr::mk_spanned_list_item(e.span, allow_ident, vec![up_spanned])
1921+
};
1922+
attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow)
1923+
};
1924+
1925+
let attrs = From::from(vec![match_attr]);
18881926
return self.expr_match(e.span, discr, hir_vec![err_arm, ok_arm],
1889-
hir::MatchSource::TryDesugar);
1927+
hir::MatchSource::TryDesugar, attrs);
18901928
}
18911929

18921930
ExprKind::Mac(_) => panic!("Shouldn't exist here"),
@@ -2031,6 +2069,13 @@ impl<'a> LoweringContext<'a> {
20312069
}
20322070

20332071
fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> hir::Expr {
2072+
self.expr_ident_with_attrs(span, id, binding, ThinVec::new())
2073+
}
2074+
2075+
fn expr_ident_with_attrs(&mut self, span: Span,
2076+
id: Name,
2077+
binding: NodeId,
2078+
attrs: ThinVec<Attribute>) -> hir::Expr {
20342079
let def = {
20352080
let defs = self.resolver.definitions();
20362081
Def::Local(defs.local_def_id(binding))
@@ -2042,7 +2087,7 @@ impl<'a> LoweringContext<'a> {
20422087
segments: hir_vec![hir::PathSegment::from_name(id)],
20432088
})));
20442089

2045-
self.expr(span, expr_path, ThinVec::new())
2090+
self.expr(span, expr_path, attrs)
20462091
}
20472092

20482093
fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> hir::Expr {
@@ -2062,9 +2107,10 @@ impl<'a> LoweringContext<'a> {
20622107
span: Span,
20632108
arg: P<hir::Expr>,
20642109
arms: hir::HirVec<hir::Arm>,
2065-
source: hir::MatchSource)
2110+
source: hir::MatchSource,
2111+
attrs: ThinVec<Attribute>)
20662112
-> hir::Expr {
2067-
self.expr(span, hir::ExprMatch(arg, arms, source), ThinVec::new())
2113+
self.expr(span, hir::ExprMatch(arg, arms, source), attrs)
20682114
}
20692115

20702116
fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Expr {

src/librustc_const_eval/check_match.rs

Lines changed: 2 additions & 11 deletions
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,7 @@ 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+
hir::MatchSource::TryDesugar => {}
335326
}
336327
}
337328
Useful => (),
Lines changed: 26 additions & 0 deletions
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+
Lines changed: 20 additions & 0 deletions
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+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
fn bar(x: Result<!, i32>) -> Result<u32, i32> {
16+
x?
17+
}
18+
19+
fn main() {
20+
let _ = bar(Err(123));
21+
}
22+

0 commit comments

Comments
 (0)