From f5bd9646be31d865a083193c21c7448d546ce07c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 13 Feb 2020 12:19:36 +0100 Subject: [PATCH] fix extra subslice lowering --- src/librustc_ast_lowering/pat.rs | 17 +++++++----- .../issue-69103-extra-binding-subslice.rs | 18 +++++++++++++ .../issue-69103-extra-binding-subslice.stderr | 26 +++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs create mode 100644 src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs index 4c3c4ddac78ee..b42b12c4dd851 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 0000000000000..061b0d675b31f --- /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 0000000000000..9432e2f0c9d34 --- /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 +