diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 9263394508ee3..31a7dc83efc60 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -397,6 +397,11 @@ parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are inva .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access .tuple_exception_line_3 = see issue #60210 for more information + +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 + parse_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/errors.rs b/compiler/rustc_parse/src/errors.rs index 84494eab855c4..57d8bb6064142 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -156,6 +156,25 @@ pub(crate) enum InvalidComparisonOperatorSub { Spaceship(#[primary_span] Span), } +#[derive(Diagnostic)] +#[diag(parse_invalid_shift_operator)] +#[note] +pub(crate) struct InvalidShiftOperator { + #[primary_span] + pub Span: Span, + pub invalid: String, + #[subdiagnostic] + pub sub: InvalidShiftOperatorSub +} + +#[derive(SessionSubdiagnostic)] +pub enum InvalidShiftOperatorSub { + #[label(parser_left_shift_operator_invalid)] + LogicalLeftShift(#[primary_span] Span), + #[label(parser_logical_right_shift_operator)] + LogicalRightShift(#[primary_span] Span), +} + #[derive(Diagnostic)] #[diag(parse_invalid_logical_operator)] #[note] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1b28f3c97e8f6..684c182663e33 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -271,6 +271,29 @@ 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(errors::InvalidShiftOperator { + span: sp, + invalid: ">>>".into(), + sub: errors::InvalidShiftOperatorSub::LogicalRightShift(sp), + }); + self.bump(); + } + + // Look for the logical left shift operator (`<<<`) and recover + 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(errors::InvalidShiftOperator { + span: sp, + invalid: "<<<".into(), + sub: errors::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 +