From: Utkarsh Bahuguna <[email protected]>
Unit variants in patterns were treated as wildcards, so a match naming
only some of them still looked exhaustive. Lower a path pattern that
names a variant of the scrutinee's enum to that variant. issues/3726.rs
only matched one of its two variants, so restore the or-pattern from the
issue there.
Fixes Rust-GCC/gccrs#2311
Assisted-by: Claude Opus 5.5 (Anthropic)
gcc/rust/ChangeLog:
* checks/errors/rust-hir-pattern-analysis.cc (lower_pattern): Lower
path patterns that name an enum variant.
gcc/testsuite/ChangeLog:
* rust/compile/exhaustiveness9.rs: New test.
* rust/compile/exhaustiveness10.rs: New test.
* rust/compile/issues/3726.rs: Match both variants.
* rust/compile/issues/issue-2311.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/691624530ad1b3c3c915193851cf04af246e15ea
The commit has been mentioned in the following issue(s):
- Rust-GCC/gccrs#2311: https://github.com/Rust-GCC/gccrs/issues/2311
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4976
.../errors/rust-hir-pattern-analysis.cc | 26 +++++--
.../rust/compile/exhaustiveness10.rs | 24 +++++++
gcc/testsuite/rust/compile/exhaustiveness9.rs | 70 +++++++++++++++++++
gcc/testsuite/rust/compile/issues/3726.rs | 4 +-
.../rust/compile/issues/issue-2311.rs | 19 +++++
5 files changed, 138 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/exhaustiveness10.rs
create mode 100644 gcc/testsuite/rust/compile/exhaustiveness9.rs
create mode 100644 gcc/testsuite/rust/compile/issues/issue-2311.rs
diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
index 3c6270bf2..8043ec220 100644
--- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
+++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
@@ -1384,11 +1384,29 @@ lower_pattern (Resolver::TypeCheckContext *ctx,
HIR::Pattern &pattern,
break;
case HIR::Pattern::PatternType::PATH:
{
- // TODO: support constants, associated constants, enum variants and
- // structs
+ // A unit variant of the scrutinee's enum is a variant constructor
+ // without fields. Anything else is still treated as a wildcard.
+ // TODO: support constants, associated constants and unit structs
// https://doc.rust-lang.org/reference/patterns.html#path-patterns
- // unimplemented. Treat this pattern as wildcard for now.
- return DeconstructedPat::make_wildcard (pattern.get_locus ());
+ // The type is not destructured on purpose: split_constructors sees the
+ // column's type as it is, and asserts that it is an ADT.
+ if (scrutinee_ty->get_kind () != TyTy::TypeKind::ADT)
+ return DeconstructedPat::make_wildcard (pattern.get_locus ());
+
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_ty);
+ HirId variant_id = UNKNOWN_HIRID;
+ if (!adt->is_enum ()
+ || !ctx->lookup_variant_definition (
+ pattern.get_mappings ().get_hirid (), &variant_id))
+ return DeconstructedPat::make_wildcard (pattern.get_locus ());
+
+ TyTy::VariantDef *variant;
+ int variant_idx;
+ if (!adt->lookup_variant_by_id (variant_id, &variant, &variant_idx))
+ return DeconstructedPat::make_wildcard (pattern.get_locus ());
+
+ return DeconstructedPat (Constructor::make_variant (variant_idx), 0, {},
+ pattern.get_locus ());
}
break;
case HIR::Pattern::PatternType::REFERENCE:
diff --git a/gcc/testsuite/rust/compile/exhaustiveness10.rs
b/gcc/testsuite/rust/compile/exhaustiveness10.rs
new file mode 100644
index 000000000..a0b3a6366
--- /dev/null
+++ b/gcc/testsuite/rust/compile/exhaustiveness10.rs
@@ -0,0 +1,24 @@
+#![feature(no_core)]
+#![no_core]
+
+// A unit variant inside a macro-expanded tuple struct pattern is checked like
+// any other, see Rust-GCC/gccrs#3726.
+
+pub enum TypeCtor {
+ Slice,
+ Array,
+}
+pub struct ApplicationTy(TypeCtor);
+
+macro_rules! ty_app {
+ ($ctor:pat) => {
+ ApplicationTy($ctor)
+ };
+}
+
+pub fn foo(ty: ApplicationTy) {
+ match ty {
+ // { dg-error "non-exhaustive patterns: 'ApplicationTy . 0:
TypeCtor::Slice .' not covered" "" { target *-*-* } .-1 }
+ ty_app!(TypeCtor::Array) => {}
+ }
+}
diff --git a/gcc/testsuite/rust/compile/exhaustiveness9.rs
b/gcc/testsuite/rust/compile/exhaustiveness9.rs
new file mode 100644
index 000000000..d3aa3024b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/exhaustiveness9.rs
@@ -0,0 +1,70 @@
+#![feature(no_core)]
+#![no_core]
+
+// Unit variants used to be treated as wildcards, so any match on them looked
+// exhaustive.
+
+enum E {
+ A,
+ B,
+}
+
+enum Three {
+ A,
+ B,
+ C,
+}
+
+enum Mixed {
+ A,
+ B(i32),
+ C,
+}
+
+const C: E = E::A;
+
+fn missing_arm(e: E) {
+ match e {
+ // { dg-error "non-exhaustive patterns: 'E::B' not covered" "" {
target *-*-* } .-1 }
+ E::A => {}
+ }
+}
+
+fn mixed(m: Mixed) {
+ match m {
+ // { dg-error "non-exhaustive patterns: 'Mixed::C' not covered" "" {
target *-*-* } .-1 }
+ Mixed::A => {}
+ Mixed::B(_) => {}
+ }
+}
+
+// These are valid matches
+fn all_covered(e: E) {
+ match e {
+ E::A => {}
+ E::B => {}
+ }
+}
+
+fn with_wildcard(t: Three) {
+ match t {
+ Three::A => {}
+ _ => {}
+ }
+}
+
+fn through_reference(e: &E) {
+ match e {
+ &E::A => {}
+ &E::B => {}
+ }
+}
+
+fn const_arm(e: E) {
+ match e {
+ C => {}
+ E::B => {}
+ }
+}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/issues/3726.rs
b/gcc/testsuite/rust/compile/issues/3726.rs
index 3c773099a..a0bf19c7f 100644
--- a/gcc/testsuite/rust/compile/issues/3726.rs
+++ b/gcc/testsuite/rust/compile/issues/3726.rs
@@ -14,7 +14,9 @@ macro_rules! ty_app {
}
pub fn foo(ty: ApplicationTy) {
+ // Both variants, as in the reproducer of Rust-GCC/gccrs#3726: a match
+ // with only `TypeCtor::Array` is not exhaustive.
match ty {
- ty_app!(TypeCtor::Array) => {}
+ ty_app!(TypeCtor::Array) | ty_app!(TypeCtor::Slice) => {}
}
}
diff --git a/gcc/testsuite/rust/compile/issues/issue-2311.rs
b/gcc/testsuite/rust/compile/issues/issue-2311.rs
new file mode 100644
index 000000000..277025e16
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/issue-2311.rs
@@ -0,0 +1,19 @@
+#![feature(no_core)]
+#![no_core]
+
+// Rust-GCC/gccrs#2311: unit variants in patterns used to be treated as
+// wildcards, so this match was accepted.
+
+enum Terminator {
+ HastaLaVistaBaby,
+ TalkToMyHand,
+}
+
+fn main() {
+ let x = Terminator::HastaLaVistaBaby;
+
+ match x {
+ // { dg-error "non-exhaustive patterns: 'Terminator::HastaLaVistaBaby'
not covered" "" { target *-*-* } .-1 }
+ Terminator::TalkToMyHand => {}
+ }
+}
base-commit: e7f01140e0aba4476d6c78ec5ba103913584940e
--
2.56.0