From: Utkarsh Bahuguna <[email protected]>

PatStack::pop_head_constructor appended the sub-patterns of the head at
the back of the row, while Matrix::specialize puts their types at the
front of the column list. With a nested pattern that has fields inside a
constructor with several fields, the patterns and their types ended up in
different columns and split_constructors hit its ADT assertion. Insert
the sub-patterns in front of the remaining columns instead.

Fixes Rust-GCC/gccrs#4973

gcc/rust/ChangeLog:

        * checks/errors/rust-hir-pattern-analysis.cc
        (PatStack::pop_head_constructor): Insert the sub-patterns in front of
        the remaining columns.

gcc/testsuite/ChangeLog:

        * rust/compile/exhaustiveness5.rs: New test.
        * rust/compile/issues/issue-4973.rs: New test.

Signed-off-by: Utkarsh Bahuguna <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/fc0c9e3326124b300cb2ad918629ca469eaa7ade

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#4973: https://github.com/Rust-GCC/gccrs/issues/4973

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4974

 .../errors/rust-hir-pattern-analysis.cc       |  5 ++-
 gcc/testsuite/rust/compile/exhaustiveness5.rs | 34 ++++++++++++++++
 .../rust/compile/issues/issue-4973.rs         | 39 +++++++++++++++++++
 3 files changed, 76 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/exhaustiveness5.rs
 create mode 100644 gcc/testsuite/rust/compile/issues/issue-4973.rs

diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc 
b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
index 456b3afb9..3f4e35b3a 100644
--- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
+++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
@@ -927,8 +927,9 @@ PatStack::pop_head_constructor (const Constructor 
&other_ctor,
                other_ctor.to_string ().c_str (), s.c_str ());
   }
   pop_head ();
-  for (auto &pat : v)
-    pats.push_back (pat);
+  // The sub-patterns replace the head, in order, in front of the remaining
+  // columns, matching the order Matrix::specialize gives their types.
+  pats.insert (pats.begin (), v.begin (), v.end ());
 }
 
 std::string
diff --git a/gcc/testsuite/rust/compile/exhaustiveness5.rs 
b/gcc/testsuite/rust/compile/exhaustiveness5.rs
new file mode 100644
index 000000000..032f75744
--- /dev/null
+++ b/gcc/testsuite/rust/compile/exhaustiveness5.rs
@@ -0,0 +1,34 @@
+#![feature(no_core)]
+#![no_core]
+
+// Adapted from rustc's tests/ui/pattern/issue-6449.rs, which used to crash
+// the exhaustiveness check. The `..` rest patterns of the original are spelled
+// out with wildcards here.
+
+enum Foo {
+    Bar(isize),
+    Baz,
+}
+
+enum Other {
+    Other1(Foo),
+    Other2(Foo, Foo),
+}
+
+fn main() {
+    match Foo::Baz {
+        crate::Foo::Bar(3) => {}
+        crate::Foo::Bar(_) if false => {}
+        crate::Foo::Bar(_) if false => {}
+        crate::Foo::Bar(_n) => {}
+        crate::Foo::Baz => {}
+    }
+
+    match Other::Other1(Foo::Baz) {
+        crate::Other::Other1(crate::Foo::Baz) => {}
+        crate::Other::Other1(crate::Foo::Bar(_)) => {}
+        crate::Other::Other2(crate::Foo::Baz, crate::Foo::Bar(_)) => {}
+        crate::Other::Other2(crate::Foo::Bar(_), crate::Foo::Baz) => {}
+        crate::Other::Other2(_, _) => {}
+    }
+}
diff --git a/gcc/testsuite/rust/compile/issues/issue-4973.rs 
b/gcc/testsuite/rust/compile/issues/issue-4973.rs
new file mode 100644
index 000000000..5b9c4331b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/issue-4973.rs
@@ -0,0 +1,39 @@
+#![feature(no_core)]
+#![no_core]
+
+// Rust-GCC/gccrs#4973: a pattern with fields nested in a constructor with
+// several fields used to put the sub-patterns and their types in different
+// columns, and crashed.
+
+enum Foo {
+    Bar(isize),
+    Baz(),
+}
+
+struct Pair(Foo, Foo);
+
+// This is a valid match
+fn f(x: Pair) {
+    match x {
+        Pair(Foo::Bar(_), Foo::Bar(_)) => {}
+        Pair(_, _) => {}
+    }
+}
+
+fn f2(x: Pair) {
+    match x {
+        // { dg-error "non-exhaustive patterns: 'Pair . 0: Foo::Bar..., 1: 
Foo::Bar... .' not covered" "" { target *-*-* } .-1 }
+        Pair(Foo::Bar(_), Foo::Baz()) => {}
+        Pair(Foo::Baz(), _) => {}
+    }
+}
+
+fn f3(x: Pair) {
+    match x {
+        // { dg-error "non-exhaustive patterns: 'Pair . 0: Foo::Baz.., 1: 
Foo::Baz.. .' not covered" "" { target *-*-* } .-1 }
+        Pair(Foo::Baz(), Foo::Bar(_)) => {}
+        Pair(Foo::Bar(_), _) => {}
+    }
+}
+
+fn main() {}

base-commit: 0b70380e60d04b0f47e3657dcbe68899aafe1663
-- 
2.55.0

Reply via email to