diff options
| author | Sebastian Malton <sebastian@malton.name> | 2018-06-03 23:31:49 -0400 |
|---|---|---|
| committer | Jake Goulding <jake.goulding@gmail.com> | 2018-06-05 10:19:21 -0400 |
| commit | 4fe40635ef3c2cdbc2e3f62ca71f0e2235e70639 (patch) | |
| tree | 94089961baf76e9fd6ad1ce82c65de281bc74c52 | |
| parent | 4122885e0f99b3f28e65c122cde48de5bfc8231a (diff) | |
| download | rust-4fe40635ef3c2cdbc2e3f62ca71f0e2235e70639.tar.gz rust-4fe40635ef3c2cdbc2e3f62ca71f0e2235e70639.zip | |
Implementation of RFC 2086 - Allow Irrefutable Let patterns
8 files changed, 139 insertions, 22 deletions
diff --git a/src/doc/unstable-book/src/language-features/irrefutable-let-pattern.md b/src/doc/unstable-book/src/language-features/irrefutable-let-pattern.md new file mode 100644 index 00000000000..13681c96811 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/irrefutable-let-pattern.md @@ -0,0 +1,23 @@ +# `irrefutable_let_pattern` + +The tracking issue for this feature is: [#44495] + +[#44495]: https://github.com/rust-lang/rust/issues/44495 + +------------------------ + +This feature changes the way that the irrefutable pattern is handled +in the `if let` and `while let` forms. The old way was to always error +but now with a tag the error-by-default lint can be switched off. + +```rust +#![feature(irrefutable_let_pattern)] + +fn main() { + #[allow(irrefutable_let_pattern)] + if let _ = 5 {} + + #[allow(irrefutable_let_pattern)] + while let _ = 5 {} +} +``` diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index de583e81ca8..d42567c6678 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -274,6 +274,12 @@ declare_lint! { } declare_lint! { + pub IRREFUTABLE_LET_PATTERNS, + Deny, + "detects irrefutable patterns in if-let and while-let statements" +} + +declare_lint! { pub UNUSED_LABELS, Allow, "detects labels that are never used" @@ -336,6 +342,7 @@ impl LintPass for HardwiredLints { BARE_TRAIT_OBJECTS, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, UNSTABLE_NAME_COLLISIONS, + IRREFUTABLE_LET_PATTERNS, DUPLICATE_ASSOCIATED_TYPE_BINDINGS, ) } diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 0a113970098..d5d69bf7f2b 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -369,43 +369,56 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, NotUseful => { match source { hir::MatchSource::IfLetDesugar { .. } => { - if printed_if_let_err { - // we already printed an irrefutable if-let pattern error. - // We don't want two, that's just confusing. + if cx.tcx.features().irrefutable_let_pattern { + cx.tcx.lint_node( + lint::builtin::IRREFUTABLE_LET_PATTERNS, + hir_pat.id, pat.span, + "irrefutable if-let pattern"); } else { - // find the first arm pattern so we can use its span - let &(ref first_arm_pats, _) = &arms[0]; - let first_pat = &first_arm_pats[0]; - let span = first_pat.0.span; - struct_span_err!(cx.tcx.sess, span, E0162, - "irrefutable if-let pattern") - .span_label(span, "irrefutable pattern") - .emit(); - printed_if_let_err = true; + if printed_if_let_err { + // we already printed an irrefutable if-let pattern error. + // We don't want two, that's just confusing. + } else { + // find the first arm pattern so we can use its span + let &(ref first_arm_pats, _) = &arms[0]; + let first_pat = &first_arm_pats[0]; + let span = first_pat.0.span; + struct_span_err!(cx.tcx.sess, span, E0162, + "irrefutable if-let pattern") + .span_label(span, "irrefutable pattern") + .emit(); + printed_if_let_err = true; + } } }, hir::MatchSource::WhileLetDesugar => { - // find the first arm pattern so we can use its span - let &(ref first_arm_pats, _) = &arms[0]; - let first_pat = &first_arm_pats[0]; - let span = first_pat.0.span; - // check which arm we're on. match arm_index { // The arm with the user-specified pattern. 0 => { cx.tcx.lint_node( - lint::builtin::UNREACHABLE_PATTERNS, + lint::builtin::UNREACHABLE_PATTERNS, hir_pat.id, pat.span, "unreachable pattern"); }, // The arm with the wildcard pattern. 1 => { - struct_span_err!(cx.tcx.sess, span, E0165, - "irrefutable while-let pattern") - .span_label(span, "irrefutable pattern") - .emit(); + if cx.tcx.features().irrefutable_let_pattern { + cx.tcx.lint_node( + lint::builtin::IRREFUTABLE_LET_PATTERNS, + hir_pat.id, pat.span, + "irrefutable while-let pattern"); + } else { + // find the first arm pattern so we can use its span + let &(ref first_arm_pats, _) = &arms[0]; + let first_pat = &first_arm_pats[0]; + let span = first_pat.0.span; + struct_span_err!(cx.tcx.sess, span, E0165, + "irrefutable while-let pattern") + .span_label(span, "irrefutable pattern") + .emit(); + } }, _ => bug!(), } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 51788b6063a..f08a404a02a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -467,6 +467,9 @@ declare_features! ( // Scoped attributes (active, tool_attributes, "1.25.0", Some(44690), None), + // allow irrefutable patterns in if-let and while-let statements (RFC 2086) + (active, irrefutable_let_pattern, "1.27.0", Some(44495), None), + // Allows use of the :literal macro fragment specifier (RFC 1576) (active, macro_literal_matcher, "1.27.0", Some(35625), None), diff --git a/src/test/compile-fail/feature-gate-without_gate_irrefutable_pattern.rs b/src/test/compile-fail/feature-gate-without_gate_irrefutable_pattern.rs new file mode 100644 index 00000000000..1facb6b152a --- /dev/null +++ b/src/test/compile-fail/feature-gate-without_gate_irrefutable_pattern.rs @@ -0,0 +1,17 @@ +// gate-test-irrefutable_let_pattern + +// Copyright 2015 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. + +fn main() { + #[allow(irrefutable_let_pattern)] + if let _ = 5 {} + //~^ ERROR 15:12: 15:13: irrefutable if-let pattern [E0162] +} diff --git a/src/test/compile-fail/should-fail-no_gate_irrefutable_if_let_pattern.rs b/src/test/compile-fail/should-fail-no_gate_irrefutable_if_let_pattern.rs new file mode 100644 index 00000000000..71dcbf329c7 --- /dev/null +++ b/src/test/compile-fail/should-fail-no_gate_irrefutable_if_let_pattern.rs @@ -0,0 +1,15 @@ +// Copyright 2015 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. + +// should-fail-irrefutable_let_pattern +fn main() { + if let _ = 5 {} + //~^ ERROR irrefutable if-let pattern [E0162] +} diff --git a/src/test/compile-fail/should-fail-with_gate_irrefutable_pattern_deny.rs b/src/test/compile-fail/should-fail-with_gate_irrefutable_pattern_deny.rs new file mode 100644 index 00000000000..2f9b7f0628d --- /dev/null +++ b/src/test/compile-fail/should-fail-with_gate_irrefutable_pattern_deny.rs @@ -0,0 +1,17 @@ +// Copyright 2015 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(irrefutable_let_pattern)] + +// should-fail-irrefutable_let_pattern_with_gate +fn main() { + if let _ = 5 {} + //~^ ERROR irrefutable if-let pattern [irrefutable_let_pattern] +} diff --git a/src/test/run-pass/allow_irrefutable_let_patterns.rs b/src/test/run-pass/allow_irrefutable_let_patterns.rs new file mode 100644 index 00000000000..3a4f226dfe6 --- /dev/null +++ b/src/test/run-pass/allow_irrefutable_let_patterns.rs @@ -0,0 +1,22 @@ +// Copyright 2015 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(irrefutable_let_pattern)] + +// must-compile-successfully-irrefutable_let_pattern_with_gate +fn main() { + #[allow(irrefutable_let_pattern)] + if let _ = 5 {} + + #[allow(irrefutable_let_pattern)] + while let _ = 5 { + break; + } +} |
