about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-02-13 12:19:36 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-02-13 12:24:53 +0100
commitf5bd9646be31d865a083193c21c7448d546ce07c (patch)
tree54e155d2a858f8394ed014fb81639b58fd2a348d
parent2e6eaceedeeda764056eb0e2134735793533770d (diff)
downloadrust-f5bd9646be31d865a083193c21c7448d546ce07c.tar.gz
rust-f5bd9646be31d865a083193c21c7448d546ce07c.zip
fix extra subslice lowering
-rw-r--r--src/librustc_ast_lowering/pat.rs17
-rw-r--r--src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs18
-rw-r--r--src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr26
3 files changed, 55 insertions, 6 deletions
diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs
index 4c3c4ddac78..b42b12c4dd8 100644
--- a/src/librustc_ast_lowering/pat.rs
+++ b/src/librustc_ast_lowering/pat.rs
@@ -128,6 +128,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let mut slice = None;
         let mut prev_rest_span = None;
 
+        // Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
+        let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| {
+            let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
+            let node = this.lower_pat_ident(pat, bm, ident, lower_sub);
+            this.pat_with_node_id_of(pat, node)
+        };
+
         let mut iter = pats.iter();
         // Lower all the patterns until the first occurrence of a sub-slice pattern.
         for pat in iter.by_ref() {
@@ -142,9 +149,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 // Record, lower it to `$binding_mode $ident @ _`, and stop here.
                 PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
                     prev_rest_span = Some(sub.span);
-                    let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
-                    let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
-                    slice = Some(self.pat_with_node_id_of(pat, node));
+                    slice = Some(lower_rest_sub(self, pat, bm, ident, sub));
                     break;
                 }
                 // It was not a subslice pattern so lower it normally.
@@ -157,9 +162,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // There was a previous subslice pattern; make sure we don't allow more.
             let rest_span = match pat.kind {
                 PatKind::Rest => Some(pat.span),
-                PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
-                    // The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
-                    after.push(self.pat_wild_with_node_id_of(pat));
+                PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
+                    // #69103: Lower into `binding @ _` as above to avoid ICEs.
+                    after.push(lower_rest_sub(self, pat, bm, ident, sub));
                     Some(sub.span)
                 }
                 _ => None,
diff --git a/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs b/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs
new file mode 100644
index 00000000000..061b0d675b3
--- /dev/null
+++ b/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs
@@ -0,0 +1,18 @@
+// We used to not lower the extra `b @ ..` into `b @ _` which meant that no type
+// was registered for the binding `b` although it passed through resolve.
+// This resulted in an ICE (#69103).
+
+fn main() {
+    let [a @ .., b @ ..] = &mut [1, 2];
+    //~^ ERROR `..` can only be used once per slice pattern
+    b;
+
+    let [.., c @ ..] = [1, 2];
+    //~^ ERROR `..` can only be used once per slice pattern
+    c;
+
+    // This never ICEd, but let's make sure it won't regress either.
+    let (.., d @ ..) = (1, 2);
+    //~^ ERROR `..` patterns are not allowed here
+    d;
+}
diff --git a/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr b/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr
new file mode 100644
index 00000000000..9432e2f0c9d
--- /dev/null
+++ b/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr
@@ -0,0 +1,26 @@
+error: `..` can only be used once per slice pattern
+  --> $DIR/issue-69103-extra-binding-subslice.rs:6:22
+   |
+LL |     let [a @ .., b @ ..] = &mut [1, 2];
+   |              --      ^^ can only be used once per slice pattern
+   |              |
+   |              previously used here
+
+error: `..` can only be used once per slice pattern
+  --> $DIR/issue-69103-extra-binding-subslice.rs:10:18
+   |
+LL |     let [.., c @ ..] = [1, 2];
+   |          --      ^^ can only be used once per slice pattern
+   |          |
+   |          previously used here
+
+error: `..` patterns are not allowed here
+  --> $DIR/issue-69103-extra-binding-subslice.rs:15:18
+   |
+LL |     let (.., d @ ..) = (1, 2);
+   |                  ^^
+   |
+   = note: only allowed in tuple, tuple struct, and slice patterns
+
+error: aborting due to 3 previous errors
+