1
Fork 0

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.
This commit is contained in:
bors 2017-01-22 08:56:27 +00:00
commit 98c3128c39
5 changed files with 135 additions and 18 deletions

View file

@ -51,6 +51,7 @@ use util::nodemap::{NodeMap, FxHashMap};
use std::collections::BTreeMap;
use std::iter;
use syntax::attr;
use syntax::ast::*;
use syntax::errors;
use syntax::ptr::P;
@ -1831,8 +1832,9 @@ impl<'a> LoweringContext<'a> {
// to:
//
// match Carrier::translate(<expr>) {
// Ok(val) => val,
// Err(err) => return Carrier::from_error(From::from(err))
// Ok(val) => #[allow(unreachable_code)] val,
// Err(err) => #[allow(unreachable_code)]
// return Carrier::from_error(From::from(err)),
// }
let unstable_span = self.allow_internal_unstable("?", e.span);
@ -1846,17 +1848,36 @@ impl<'a> LoweringContext<'a> {
P(self.expr_call(e.span, path, hir_vec![sub_expr]))
};
// Ok(val) => val
// #[allow(unreachable_code)]
let attr = {
// allow(unreachable_code)
let allow = {
let allow_ident = self.str_to_ident("allow");
let uc_ident = self.str_to_ident("unreachable_code");
let uc_meta_item = attr::mk_spanned_word_item(e.span, uc_ident);
let uc_nested = NestedMetaItemKind::MetaItem(uc_meta_item);
let uc_spanned = respan(e.span, uc_nested);
attr::mk_spanned_list_item(e.span, allow_ident, vec![uc_spanned])
};
attr::mk_spanned_attr_outer(e.span, attr::mk_attr_id(), allow)
};
let attrs = vec![attr];
// Ok(val) => #[allow(unreachable_code)] val,
let ok_arm = {
let val_ident = self.str_to_ident("val");
let val_pat = self.pat_ident(e.span, val_ident);
let val_expr = P(self.expr_ident(e.span, val_ident, val_pat.id));
let val_expr = P(self.expr_ident_with_attrs(e.span,
val_ident,
val_pat.id,
ThinVec::from(attrs.clone())));
let ok_pat = self.pat_ok(e.span, val_pat);
self.arm(hir_vec![ok_pat], val_expr)
};
// Err(err) => return Carrier::from_error(From::from(err))
// Err(err) => #[allow(unreachable_code)]
// return Carrier::from_error(From::from(err)),
let err_arm = {
let err_ident = self.str_to_ident("err");
let err_local = self.pat_ident(e.span, err_ident);
@ -1876,7 +1897,7 @@ impl<'a> LoweringContext<'a> {
let ret_expr = P(self.expr(e.span,
hir::Expr_::ExprRet(Some(from_err_expr)),
ThinVec::new()));
ThinVec::from(attrs)));
let err_pat = self.pat_err(e.span, err_local);
self.arm(hir_vec![err_pat], ret_expr)
@ -2028,6 +2049,13 @@ impl<'a> LoweringContext<'a> {
}
fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> hir::Expr {
self.expr_ident_with_attrs(span, id, binding, ThinVec::new())
}
fn expr_ident_with_attrs(&mut self, span: Span,
id: Name,
binding: NodeId,
attrs: ThinVec<Attribute>) -> hir::Expr {
let def = {
let defs = self.resolver.definitions();
Def::Local(defs.local_def_id(binding))
@ -2039,7 +2067,7 @@ impl<'a> LoweringContext<'a> {
segments: hir_vec![hir::PathSegment::from_name(id)],
})));
self.expr(span, expr_path, ThinVec::new())
self.expr(span, expr_path, attrs)
}
fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> hir::Expr {

View file

@ -308,14 +308,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
.emit();
},
hir::MatchSource::ForLoopDesugar => {
// this is a bug, because on `match iter.next()` we cover
// `Some(<head>)` and `None`. It's impossible to have an unreachable
// pattern
// (see libsyntax/ext/expand.rs for the full expansion of a for loop)
span_bug!(pat.span, "unreachable for-loop pattern")
},
hir::MatchSource::ForLoopDesugar |
hir::MatchSource::Normal => {
let mut diagnostic = Diagnostic::new(Level::Warning,
"unreachable pattern");
@ -329,9 +322,9 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
hir_pat.id, diagnostic);
},
hir::MatchSource::TryDesugar => {
span_bug!(pat.span, "unreachable try pattern")
},
// Unreachable patterns in try expressions occur when one of the arms
// are an uninhabited type. Which is OK.
hir::MatchSource::TryDesugar => {}
}
}
Useful => (),

View file

@ -0,0 +1,26 @@
// Copyright 2014 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.
//#![feature(never_type)]
struct R<'a> {
r: &'a R<'a>,
}
fn foo(res: Result<u32, &R>) -> u32 {
let Ok(x) = res;
//~^ ERROR refutable pattern
x
}
fn main() {
foo(Ok(23));
}

View file

@ -0,0 +1,20 @@
// Copyright 2013 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.
#![feature(never_type)]
#![deny(unreachable_patterns)]
fn main() {
let x: &[!] = &[];
for _ in x {}
//~^ ERROR unreachable pattern
}

View file

@ -0,0 +1,50 @@
// Copyright 2013 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.
#![feature(never_type)]
#![deny(unreachable_code)]
#![deny(unreachable_patterns)]
enum Void {}
impl From<Void> for i32 {
fn from(v: Void) -> i32 {
match v {}
}
}
fn bar(x: Result<!, i32>) -> Result<u32, i32> {
x?
}
fn foo(x: Result<!, i32>) -> Result<u32, i32> {
let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?;
//~^ ERROR unreachable pattern
//~| ERROR unreachable expression
Ok(y)
}
fn qux(x: Result<u32, Void>) -> Result<u32, i32> {
Ok(x?)
}
fn vom(x: Result<u32, Void>) -> Result<u32, i32> {
let y = (match x { Ok(n) => Ok(n), Err(e) => Err(e) })?;
//~^ ERROR unreachable pattern
Ok(y)
}
fn main() {
let _ = bar(Err(123));
let _ = foo(Err(123));
let _ = qux(Ok(123));
let _ = vom(Ok(123));
}