diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index f74df3d9746ae..5a1a8ad556808 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -46,6 +46,10 @@ parser_invalid_comparison_operator = invalid comparison operator `{$invalid}` .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}` .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering` +parser_invalid_shift_operator = invalid shift operator `{$invalid}` + .logical_left_shift_operator_invalid = `<<<` is not a valid left shift operator, consider shifting normally and fixing the sign as needed + .logical_right_shift_operator_invalid = `>>>` is not a valid right shift operator, consider casting to an unsigned integer and right shifting normally + parser_invalid_logical_operator = `{$incorrect}` is not a logical operator .note = unlike in e.g., python and PHP, `&&` and `||` are used for logical operators .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index be524db785bc0..75863ccdb893a 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -389,6 +389,24 @@ pub(crate) enum InvalidComparisonOperatorSub { Spaceship(#[primary_span] Span), } +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_shift_operator)] +pub(crate) struct InvalidShiftOperator { + #[primary_span] + pub span: Span, + pub invalid: String, + #[subdiagnostic] + pub sub: InvalidShiftOperatorSub, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum InvalidShiftOperatorSub { + #[label(parser::logical_left_shift_operator_invalid)] + LogicalLeftShift(#[primary_span] Span), + #[label(parser::logical_right_shift_operator_invalid)] + LogicalRightShift(#[primary_span] Span), +} + #[derive(SessionDiagnostic)] #[diag(parser::invalid_logical_operator)] #[note] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index ed37ede65d514..d47de2311e151 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4,10 +4,11 @@ use super::diagnostics::{ FloatLiteralRequiresIntegerPart, IfExpressionMissingCondition, IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub, InvalidLogicalOperator, InvalidLogicalOperatorSub, - LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, - MalformedLoopLabel, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, - NotAsNegationOperator, OuterAttributeNotAllowedOnIfElse, RequireColonAfterLabeledExpression, - SnapshotParser, TildeAsUnaryOperator, UnexpectedTokenAfterLabel, + InvalidShiftOperator, InvalidShiftOperatorSub, LeftArrowOperator, LifetimeInBorrowExpression, + MacroInvocationWithQualifiedPath, MalformedLoopLabel, MissingInInForLoop, + MissingInInForLoopSub, MissingSemicolonBeforeArray, NotAsNegationOperator, + OuterAttributeNotAllowedOnIfElse, RequireColonAfterLabeledExpression, SnapshotParser, + TildeAsUnaryOperator, UnexpectedTokenAfterLabel, }; use super::pat::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; @@ -279,6 +280,35 @@ impl<'a> Parser<'a> { self.bump(); } + // Look for the logical right shift operator (`>>>`) and recover. + if op.node == AssocOp::ShiftRight + && self.token.kind == token::Gt + && self.prev_token.span.hi() == self.token.span.lo() + { + let sp = op.span.to(self.token.span); + self.sess.emit_err(InvalidShiftOperator { + span: sp, + invalid: ">>>".into(), + sub: InvalidShiftOperatorSub::LogicalRightShift(sp), + }); + self.bump(); + } + + // Look for the logical left shift operator (`<<<`) and recover. + // Yea nobody uses this but it's worth being thorough. + if op.node == AssocOp::ShiftLeft + && self.token.kind == token::Lt + && self.prev_token.span.hi() == self.token.span.lo() + { + let sp = op.span.to(self.token.span); + self.sess.emit_err(InvalidShiftOperator { + span: sp, + invalid: "<<<".into(), + sub: InvalidShiftOperatorSub::LogicalLeftShift(sp), + }); + self.bump(); + } + if self.prev_token == token::BinOp(token::Plus) && self.token == token::BinOp(token::Plus) && self.prev_token.span.between(self.token.span).is_empty() diff --git a/src/test/ui/operator-recovery/logical-left-shift.rs b/src/test/ui/operator-recovery/logical-left-shift.rs new file mode 100644 index 0000000000000..3045105690931 --- /dev/null +++ b/src/test/ui/operator-recovery/logical-left-shift.rs @@ -0,0 +1,4 @@ +fn main() { + println!("{}", 1 <<< 2); + //~^ERROR invalid shift operator `<<<` +} diff --git a/src/test/ui/operator-recovery/logical-left-shift.stderr b/src/test/ui/operator-recovery/logical-left-shift.stderr new file mode 100644 index 0000000000000..124981d4b266a --- /dev/null +++ b/src/test/ui/operator-recovery/logical-left-shift.stderr @@ -0,0 +1,8 @@ +error: invalid shift operator `<<<` + --> $DIR/logical-left-shift.rs:2:22 + | +LL | println!("{}", 1 <<< 2); + | ^^^ `<<<` is not a valid left shift operator, consider shifting normally and fixing the sign as needed. + +error: aborting due to previous error + diff --git a/src/test/ui/operator-recovery/logical-right-shift.rs b/src/test/ui/operator-recovery/logical-right-shift.rs new file mode 100644 index 0000000000000..18353d9428ae1 --- /dev/null +++ b/src/test/ui/operator-recovery/logical-right-shift.rs @@ -0,0 +1,4 @@ +fn main() { + println!("{}", 1 >>> 2); + //~^ERROR invalid shift operator `>>>` +} diff --git a/src/test/ui/operator-recovery/logical-right-shift.stderr b/src/test/ui/operator-recovery/logical-right-shift.stderr new file mode 100644 index 0000000000000..d8b4c7de84019 --- /dev/null +++ b/src/test/ui/operator-recovery/logical-right-shift.stderr @@ -0,0 +1,8 @@ +error: invalid shift operator `>>>` + --> $DIR/logical-right-shift.rs:2:22 + | +LL | println!("{}", 1 >>> 2); + | ^^^ `>>>` is not a valid right shift operator, consider casting to an unsigned integer and right shifting normally. + +error: aborting due to previous error +