about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSebastian Malton <sebastian@malton.name>2018-06-03 23:31:49 -0400
committerJake Goulding <jake.goulding@gmail.com>2018-06-05 10:19:21 -0400
commit4fe40635ef3c2cdbc2e3f62ca71f0e2235e70639 (patch)
tree94089961baf76e9fd6ad1ce82c65de281bc74c52
parent4122885e0f99b3f28e65c122cde48de5bfc8231a (diff)
downloadrust-4fe40635ef3c2cdbc2e3f62ca71f0e2235e70639.tar.gz
rust-4fe40635ef3c2cdbc2e3f62ca71f0e2235e70639.zip
Implementation of RFC 2086 - Allow Irrefutable Let patterns
-rw-r--r--src/doc/unstable-book/src/language-features/irrefutable-let-pattern.md23
-rw-r--r--src/librustc/lint/builtin.rs7
-rw-r--r--src/librustc_mir/hair/pattern/check_match.rs57
-rw-r--r--src/libsyntax/feature_gate.rs3
-rw-r--r--src/test/compile-fail/feature-gate-without_gate_irrefutable_pattern.rs17
-rw-r--r--src/test/compile-fail/should-fail-no_gate_irrefutable_if_let_pattern.rs15
-rw-r--r--src/test/compile-fail/should-fail-with_gate_irrefutable_pattern_deny.rs17
-rw-r--r--src/test/run-pass/allow_irrefutable_let_patterns.rs22
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;
+    }
+}