From 06a8ed10b627d04c9e91c41064c38745374acc71 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 27 Nov 2023 03:47:49 +0100 Subject: [PATCH] Disallow guards on never patterns --- compiler/rustc_ast_lowering/messages.ftl | 4 +++ compiler/rustc_ast_lowering/src/errors.rs | 8 +++++ compiler/rustc_ast_lowering/src/expr.rs | 7 ++-- tests/ui/never_patterns/check.rs | 3 +- tests/ui/never_patterns/check.stderr | 41 +++-------------------- tests/ui/never_patterns/parse.rs | 3 ++ tests/ui/never_patterns/parse.stderr | 24 +++++++++++-- 7 files changed, 47 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 2a519b418e6c7..ecbe8cc6aec71 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -108,6 +108,10 @@ ast_lowering_misplaced_impl_trait = ast_lowering_misplaced_relax_trait_bound = `?Trait` bounds are only permitted at the point where a type parameter is declared +ast_lowering_never_pattern_with_guard = + a guard on a never pattern will never be run + .suggestion = remove this guard + ast_lowering_not_supported_for_lifetime_binder_async_closure = `for<...>` binders on `async` closures are not currently supported diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 1bcf4a07eb094..c6a4166f5370e 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -349,6 +349,14 @@ pub struct MatchArmWithNoBody { pub suggestion: Span, } +#[derive(Diagnostic)] +#[diag(ast_lowering_never_pattern_with_guard)] +pub struct NeverPatternWithGuard { + #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub span: 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 4a32fa7f929cd..4913f9cd12def 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2,7 +2,7 @@ use super::errors::{ AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, - NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign, + NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign, }; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; @@ -550,7 +550,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { let pat = self.lower_pat(&arm.pat); - let guard = arm.guard.as_ref().map(|cond| { + let mut guard = arm.guard.as_ref().map(|cond| { if let ExprKind::Let(pat, scrutinee, span, is_recovered) = &cond.kind { hir::Guard::IfLet(self.arena.alloc(hir::Let { hir_id: self.next_id(), @@ -575,6 +575,9 @@ impl<'hir> LoweringContext<'_, 'hir> { self.tcx .sess .emit_err(MatchArmWithNoBody { span, suggestion: span.shrink_to_hi() }); + } else if let Some(g) = &arm.guard { + self.tcx.sess.emit_err(NeverPatternWithGuard { span: g.span }); + guard = None; } // An arm without a body, meant for never patterns. diff --git a/tests/ui/never_patterns/check.rs b/tests/ui/never_patterns/check.rs index 9b02fc7996d69..1f55ef1124229 100644 --- a/tests/ui/never_patterns/check.rs +++ b/tests/ui/never_patterns/check.rs @@ -15,12 +15,11 @@ fn no_arms_or_guards(x: Void) { None => {} } match None:: { - //~^ ERROR non-exhaustive Some(!) if true, + //~^ ERROR guard on a never pattern None => {} } match None:: { - //~^ ERROR non-exhaustive Some(!) if true => {} None => {} } diff --git a/tests/ui/never_patterns/check.stderr b/tests/ui/never_patterns/check.stderr index 945812225c418..a25ee1b0a2adf 100644 --- a/tests/ui/never_patterns/check.stderr +++ b/tests/ui/never_patterns/check.stderr @@ -1,39 +1,8 @@ -error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/check.rs:17:11 - | -LL | match None:: { - | ^^^^^^^^^^^^ pattern `Some(_)` not covered - | -note: `Option` defined here - --> $SRC_DIR/core/src/option.rs:LL:COL - ::: $SRC_DIR/core/src/option.rs:LL:COL - | - = note: not covered - = note: the matched value is of type `Option` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown - | -LL ~ None => {}, -LL + Some(_) => todo!() - | - -error[E0004]: non-exhaustive patterns: `Some(_)` not covered - --> $DIR/check.rs:22:11 - | -LL | match None:: { - | ^^^^^^^^^^^^ pattern `Some(_)` not covered - | -note: `Option` defined here - --> $SRC_DIR/core/src/option.rs:LL:COL - ::: $SRC_DIR/core/src/option.rs:LL:COL - | - = note: not covered - = note: the matched value is of type `Option` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown - | -LL ~ None => {}, -LL + Some(_) => todo!() +error: a guard on a never pattern will never be run + --> $DIR/check.rs:18:20 | +LL | Some(!) if true, + | ^^^^ help: remove this guard -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/never_patterns/parse.rs b/tests/ui/never_patterns/parse.rs index 850416d723ab8..1b23e60e0cac7 100644 --- a/tests/ui/never_patterns/parse.rs +++ b/tests/ui/never_patterns/parse.rs @@ -30,10 +30,12 @@ fn parse(x: Void) { match None:: { Some(!) if true //~^ ERROR expected `,` following `match` arm + //~| ERROR guard on a never pattern None => {} } match None:: { Some(!) if true, + //~^ ERROR guard on a never pattern None => {} } match None:: { @@ -45,6 +47,7 @@ fn parse(x: Void) { } match x { never!() if true, + //~^ ERROR guard on a never pattern } match x { never!() diff --git a/tests/ui/never_patterns/parse.stderr b/tests/ui/never_patterns/parse.stderr index 7ea33540c5efa..e81a13a3967cb 100644 --- a/tests/ui/never_patterns/parse.stderr +++ b/tests/ui/never_patterns/parse.stderr @@ -11,16 +11,34 @@ LL | Some(!) if true | ^ help: missing a comma here to end this `match` arm: `,` error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `<=` - --> $DIR/parse.rs:40:17 + --> $DIR/parse.rs:42:17 | LL | Some(!) <= | ^^ expected one of `,`, `=>`, `if`, `|`, or `}` error: top-level or-patterns are not allowed in `let` bindings - --> $DIR/parse.rs:64:9 + --> $DIR/parse.rs:67:9 | LL | let Ok(_) | Err(!) = &res; // Disallowed; see #82048. | ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Ok(_) | Err(!))` -error: aborting due to 4 previous errors +error: a guard on a never pattern will never be run + --> $DIR/parse.rs:31:20 + | +LL | Some(!) if true + | ^^^^ help: remove this guard + +error: a guard on a never pattern will never be run + --> $DIR/parse.rs:37:20 + | +LL | Some(!) if true, + | ^^^^ help: remove this guard + +error: a guard on a never pattern will never be run + --> $DIR/parse.rs:49:21 + | +LL | never!() if true, + | ^^^^ help: remove this guard + +error: aborting due to 7 previous errors