diff options
| author | Nadrieril <nadrieril+git@gmail.com> | 2023-11-27 01:53:05 +0100 |
|---|---|---|
| committer | Nadrieril <nadrieril+git@gmail.com> | 2023-12-03 12:25:46 +0100 |
| commit | a2dcb3a6d9aead3964b3b1cdf814dc7eb9c5d8ed (patch) | |
| tree | 6dface89197039eb8fddb71508a4522ac0892eca /compiler | |
| parent | 0bfebc6105ea882d7048057718b2e34d09a5d17e (diff) | |
| download | rust-a2dcb3a6d9aead3964b3b1cdf814dc7eb9c5d8ed.tar.gz rust-a2dcb3a6d9aead3964b3b1cdf814dc7eb9c5d8ed.zip | |
Disallow an arm without a body (except for never patterns)
Parsing now accepts a match arm without a body, so we must make sure to only accept that if the pattern is a never pattern.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast/src/ast.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/messages.ftl | 4 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/errors.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/expr.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 17 |
5 files changed, 42 insertions, 5 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 62bacf97f49..815f5fa8368 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -659,8 +659,8 @@ impl Pat { matches!(self.kind, PatKind::Rest) } - /// Could this be a never pattern? I.e. is it a never pattern modulo macro invocations that - /// might return never patterns? + /// Whether this could be a never pattern, taking into account that a macro invocation can + /// return a never pattern. Used to inform errors during parsing. pub fn could_be_never_pattern(&self) -> bool { let mut could_be_never_pattern = false; self.walk(&mut |pat| match &pat.kind { diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 91591a71611..2a519b418e6 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -91,6 +91,10 @@ ast_lowering_invalid_register = ast_lowering_invalid_register_class = invalid register class `{$reg_class}`: {$error} +ast_lowering_match_arm_with_no_body = + `match` arm with no body + .suggestion = add a body after the pattern + ast_lowering_misplaced_assoc_ty_binding = associated type bounds are only allowed in where clauses and function signatures, not in {$position} diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 6e1a9eff500..1bcf4a07eb0 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -340,6 +340,15 @@ pub struct NotSupportedForLifetimeBinderAsyncClosure { pub span: Span, } +#[derive(Diagnostic)] +#[diag(ast_lowering_match_arm_with_no_body)] +pub struct MatchArmWithNoBody { + #[primary_span] + pub span: Span, + #[suggestion(code = " => todo!(),", applicability = "has-placeholders")] + pub suggestion: Span, +} + #[derive(Diagnostic, Clone, Copy)] #[diag(ast_lowering_arbitrary_expression_in_pattern)] pub struct ArbitraryExpressionInPattern { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b688950f5a3..4a32fa7f929 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,7 +1,7 @@ use super::errors::{ AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters, - FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, + FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign, }; use super::ResolverAstLoweringExt; @@ -565,14 +565,21 @@ impl<'hir> LoweringContext<'_, 'hir> { } }); let hir_id = self.next_id(); + let span = self.lower_span(arm.span); self.lower_attrs(hir_id, &arm.attrs); let body = if let Some(body) = &arm.body { + // FIXME(never_patterns): Disallow never pattern with a body or guard self.lower_expr(body) } else { + if !pat.is_never_pattern() { + self.tcx + .sess + .emit_err(MatchArmWithNoBody { span, suggestion: span.shrink_to_hi() }); + } + // An arm without a body, meant for never patterns. // We add a fake `loop {}` arm body so that it typecks to `!`. // FIXME(never_patterns): Desugar into a call to `unreachable_unchecked`. - let span = pat.span; let block = self.arena.alloc(hir::Block { stmts: &[], expr: None, @@ -587,7 +594,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span, }) }; - hir::Arm { hir_id, pat, guard, body, span: self.lower_span(arm.span) } + hir::Arm { hir_id, pat, guard, body, span } } /// Lower an `async` construct to a coroutine that implements `Future`. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 81733d8f64e..479a0db75b0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1055,6 +1055,23 @@ impl<'hir> Pat<'hir> { true }) } + + /// Whether this a never pattern. + pub fn is_never_pattern(&self) -> bool { + let mut is_never_pattern = false; + self.walk(|pat| match &pat.kind { + PatKind::Never => { + is_never_pattern = true; + false + } + PatKind::Or(s) => { + is_never_pattern = s.iter().all(|p| p.is_never_pattern()); + false + } + _ => true, + }); + is_never_pattern + } } /// A single field in a struct pattern. |
