Skip to content

Commit e8bc0e1

Browse files
committed
gccrs: empty match expressions should resolve to !
This is a special case in Rust and the ! type can unify with pretty much anything its almost a inference variable and a unit-type for special cases. Fixes #3231 Fixes #2567 gcc/rust/ChangeLog: * backend/rust-compile-expr.cc (check_match_scrutinee): check for empty match (CompileExpr::visit): fix assertion * checks/errors/rust-hir-pattern-analysis.cc (check_match_usefulness): check for empty * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): resolve to ! gcc/testsuite/ChangeLog: * rust/compile/exhaustiveness1.rs: remove bad check * rust/compile/issue-2567-1.rs: New test. * rust/compile/issue-2567-2.rs: New test. * rust/compile/issue-2567-3.rs: New test. * rust/compile/issue-3231.rs: New test. Signed-off-by: Philip Herron <herron.philip@googlemail.com>
1 parent 01f30ec commit e8bc0e1

8 files changed

Lines changed: 58 additions & 14 deletions

File tree

‎gcc/rust/backend/rust-compile-expr.cc‎

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,17 +1014,7 @@ check_match_scrutinee (HIR::MatchExpr &expr, Context *ctx)
10141014
|| scrutinee_kind == TyTy::TypeKind::TUPLE
10151015
|| scrutinee_kind == TyTy::TypeKind::REF);
10161016

1017-
if (scrutinee_kind == TyTy::TypeKind::ADT)
1018-
{
1019-
// this will need to change but for now the first pass implementation,
1020-
// lets assert this is the case
1021-
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_expr_tyty);
1022-
if (adt->is_enum ())
1023-
rust_assert (adt->number_of_variants () > 0);
1024-
else
1025-
rust_assert (adt->number_of_variants () == 1);
1026-
}
1027-
else if (scrutinee_kind == TyTy::TypeKind::FLOAT)
1017+
if (scrutinee_kind == TyTy::TypeKind::FLOAT)
10281018
{
10291019
// FIXME: CASE_LABEL_EXPR does not support floating point types.
10301020
// Find another way to compile these.
@@ -1065,6 +1055,15 @@ CompileExpr::visit (HIR::MatchExpr &expr)
10651055
return;
10661056
}
10671057

1058+
// if the result of this expression is meant to be never type then we can
1059+
// optimise this away but there is the case where match arms resolve to !
1060+
// because of return statements we need to special case this
1061+
if (!expr.has_match_arms () && expr_tyty->is<TyTy::NeverType> ())
1062+
{
1063+
translated = unit_expression (expr.get_locus ());
1064+
return;
1065+
}
1066+
10681067
fncontext fnctx = ctx->peek_fn ();
10691068
Bvariable *tmp = NULL;
10701069
tree enclosing_scope = ctx->peek_enclosing_scope ();

‎gcc/rust/checks/errors/rust-hir-pattern-analysis.cc‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,6 +1530,9 @@ void
15301530
check_match_usefulness (Resolver::TypeCheckContext *ctx,
15311531
TyTy::BaseType *scrutinee_ty, HIR::MatchExpr &expr)
15321532
{
1533+
if (!expr.has_match_arms ())
1534+
return;
1535+
15331536
// Lower the arms to a more convenient representation.
15341537
std::vector<MatrixRow> rows;
15351538
for (auto &arm : expr.get_match_cases ())

‎gcc/rust/typecheck/rust-hir-type-check-expr.cc‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,18 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr)
14561456
TyTy::BaseType *scrutinee_tyty
14571457
= TypeCheckExpr::Resolve (expr.get_scrutinee_expr ());
14581458

1459+
// https://github.com/Rust-GCC/gccrs/issues/3231#issuecomment-2462660048
1460+
// https://github.com/rust-lang/rust/blob/3d1dba830a564d1118361345d7ada47a05241f45/compiler/rustc_hir_typeck/src/_match.rs#L32-L36
1461+
if (!expr.has_match_arms ())
1462+
{
1463+
// this is a special case where rustc returns !
1464+
TyTy::BaseType *lookup = nullptr;
1465+
bool ok = context->lookup_builtin ("!", &lookup);
1466+
rust_assert (ok);
1467+
infered = lookup->clone ();
1468+
return;
1469+
}
1470+
14591471
bool saw_error = false;
14601472
std::vector<TyTy::BaseType *> kase_block_tys;
14611473
for (auto &kase : expr.get_match_cases ())

‎gcc/testsuite/rust/compile/exhaustiveness1.rs‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ fn s2(s: S) {
1515
}
1616

1717
fn s3(s: S) {
18-
match s {
19-
// { dg-error "non-exhaustive patterns: '_' not covered" "" { target *-*-* } .-1 }
20-
}
18+
match s {}
2119
}
2220

2321
enum E {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// { dg-options "-w" }
2+
enum Empty {}
3+
4+
fn foo(x: Empty) {
5+
let x: Empty = match x {
6+
// empty
7+
};
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// { dg-options "-w" }
2+
enum Empty {}
3+
4+
fn foo(x: Empty) {
5+
let x: i32 = match x {
6+
// empty
7+
};
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// { dg-options "-w" }
2+
enum Empty {}
3+
4+
fn foo(x: Empty) {
5+
match x {
6+
// empty
7+
}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// { dg-options "-w" }
2+
pub enum X {}
3+
4+
pub fn foo(x: X) {
5+
let _a: i32 = match x {};
6+
}
7+
8+
pub fn main() {}

0 commit comments

Comments
 (0)