Skip to content

Commit 3d1e2a6

Browse files
committed
tychk: Ensure diverging else of let-else is actually diverging
Make sure the `else` expression resolves to the never type. gcc/rust/ChangeLog: * typecheck/rust-hir-type-check-stmt.cc (TypeCheckStmt::visit): Check diverging else against `!`. gcc/testsuite/ChangeLog: * rust/compile/let-else-invalid-type.rs: New test.
1 parent bee59d6 commit 3d1e2a6

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

Diff for: gcc/rust/typecheck/rust-hir-type-check-stmt.cc

+19
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717
// <http://www.gnu.org/licenses/>.
1818

1919
#include "rust-hir-type-check-stmt.h"
20+
#include "rich-location.h"
2021
#include "rust-hir-type-check-type.h"
2122
#include "rust-hir-type-check-expr.h"
2223
#include "rust-hir-type-check-implitem.h"
2324
#include "rust-hir-type-check-item.h"
2425
#include "rust-hir-type-check-pattern.h"
2526
#include "rust-type-util.h"
27+
#include "rust-tyty.h"
2628

2729
namespace Rust {
2830
namespace Resolver {
@@ -78,6 +80,7 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt)
7880
auto &stmt_pattern = stmt.get_pattern ();
7981
TyTy::BaseType *init_expr_ty = nullptr;
8082
location_t init_expr_locus = UNKNOWN_LOCATION;
83+
8184
if (stmt.has_init_expr ())
8285
{
8386
init_expr_locus = stmt.get_init_expr ().get_locus ();
@@ -97,6 +100,22 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt)
97100
specified_ty_locus = stmt.get_type ().get_locus ();
98101
}
99102

103+
if (stmt.has_else_expr ())
104+
{
105+
auto &else_expr = stmt.get_else_expr ();
106+
auto else_expr_ty = TypeCheckExpr::Resolve (else_expr);
107+
108+
if (else_expr_ty->get_kind () != TyTy::TypeKind::NEVER)
109+
{
110+
rust_error_at (else_expr.get_locus (),
111+
"%<else%> clause of let-else does not diverge");
112+
return;
113+
}
114+
115+
// FIXME: Is that enough? Do we need to do something like
116+
// `append_reference` here as well?
117+
}
118+
100119
// let x:i32 = 123;
101120
if (specified_ty != nullptr && init_expr_ty != nullptr)
102121
{

Diff for: gcc/testsuite/rust/compile/let-else-invalid-type.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
enum FakeOption {
2+
Some(i32),
3+
None,
4+
}
5+
6+
fn main() {
7+
let FakeOption::Some(a) = FakeOption::None else { FakeOption::Some(15) }; // { dg-error "does not diverge" }
8+
}

0 commit comments

Comments
 (0)