From 8b186dfdb70ebfe722975970458c6230841e6911 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 27 Feb 2023 13:22:43 +0000 Subject: [PATCH] Add recovery for use of removed `box` syntax --- compiler/rustc_parse/src/parser/expr.rs | 28 +++++++++++ tests/ui/parser/removed-syntax-box.fixed | 14 ++++++ tests/ui/parser/removed-syntax-box.rs | 12 +++-- tests/ui/parser/removed-syntax-box.stderr | 59 +++++++++++++++++++++-- tests/ui/unpretty/box.stdout | 2 +- 5 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 tests/ui/parser/removed-syntax-box.fixed diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 275167162860e..31a91e1ab6abc 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -8,6 +8,7 @@ use super::{ use crate::errors; use crate::maybe_recover_from_interpolated_ty_qpath; +use ast::{Path, PathSegment}; use core::mem; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; @@ -29,6 +30,7 @@ use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::source_map::{self, Span, Spanned}; +use rustc_span::symbol::kw::PathRoot; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Pos}; use thin_vec::{thin_vec, ThinVec}; @@ -607,6 +609,9 @@ impl<'a> Parser<'a> { let operand_expr = this.parse_expr_dot_or_call(Default::default())?; this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt) } + token::Ident(..) if this.token.is_keyword(kw::Box) => { + make_it!(this, attrs, |this, _| this.parse_expr_box(lo)) + } token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => { make_it!(this, attrs, |this, _| this.recover_not_expr(lo)) } @@ -633,6 +638,29 @@ impl<'a> Parser<'a> { self.parse_expr_unary(lo, UnOp::Not) } + /// Parse `box expr` - this syntax has been removed, but we still parse this + /// for now to provide an automated way to fix usages of it + fn parse_expr_box(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { + let (span, expr) = self.parse_expr_prefix_common(lo)?; + let code = self.sess.source_map().span_to_snippet(span.with_lo(lo.hi())).unwrap(); + self.sess.emit_err(errors::BoxSyntaxRemoved { span, code: code.trim() }); + // So typechecking works, parse `box ` as `::std::boxed::Box::new(expr)` + let path = Path { + span, + segments: [ + PathSegment::from_ident(Ident::with_dummy_span(PathRoot)), + PathSegment::from_ident(Ident::with_dummy_span(sym::std)), + PathSegment::from_ident(Ident::from_str("boxed")), + PathSegment::from_ident(Ident::from_str("Box")), + PathSegment::from_ident(Ident::with_dummy_span(sym::new)), + ] + .into(), + tokens: None, + }; + let path = self.mk_expr(span, ExprKind::Path(None, path)); + Ok((span, self.mk_call(path, ThinVec::from([expr])))) + } + fn is_mistaken_not_ident_negation(&self) -> bool { let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind { // These tokens can start an expression after `!`, but diff --git a/tests/ui/parser/removed-syntax-box.fixed b/tests/ui/parser/removed-syntax-box.fixed new file mode 100644 index 0000000000000..09d1304b77546 --- /dev/null +++ b/tests/ui/parser/removed-syntax-box.fixed @@ -0,0 +1,14 @@ +// run-rustfix + +fn main() { + #[allow(dead_code)] + struct T { + a: u8, + b: u8, + } + let _ = Box::new(()); //~ ERROR `box_syntax` has been removed + let _ = Box::new(1); //~ ERROR `box_syntax` has been removed + let _ = Box::new(T { a: 12, b: 18 }); //~ ERROR `box_syntax` has been removed + let _ = Box::new([5; 30]); //~ ERROR `box_syntax` has been removed + let _: Box<()> = Box::new(()); //~ ERROR `box_syntax` has been removed +} diff --git a/tests/ui/parser/removed-syntax-box.rs b/tests/ui/parser/removed-syntax-box.rs index b0e8eb0410ef6..1f5061b02c705 100644 --- a/tests/ui/parser/removed-syntax-box.rs +++ b/tests/ui/parser/removed-syntax-box.rs @@ -1,10 +1,14 @@ +// run-rustfix + fn main() { + #[allow(dead_code)] struct T { a: u8, b: u8, } - let _ = box () //~ ERROR expected expression, found reserved keyword `box` - let _ = box 1; - let _ = box T { a: 12, b: 18 }; - let _ = box [5; 30]; + let _ = box (); //~ ERROR `box_syntax` has been removed + let _ = box 1; //~ ERROR `box_syntax` has been removed + let _ = box T { a: 12, b: 18 }; //~ ERROR `box_syntax` has been removed + let _ = box [5; 30]; //~ ERROR `box_syntax` has been removed + let _: Box<()> = box (); //~ ERROR `box_syntax` has been removed } diff --git a/tests/ui/parser/removed-syntax-box.stderr b/tests/ui/parser/removed-syntax-box.stderr index 8c8d5b3c4cb3c..46b891587d5a6 100644 --- a/tests/ui/parser/removed-syntax-box.stderr +++ b/tests/ui/parser/removed-syntax-box.stderr @@ -1,8 +1,57 @@ -error: expected expression, found reserved keyword `box` - --> $DIR/removed-syntax-box.rs:6:13 +error: `box_syntax` has been removed + --> $DIR/removed-syntax-box.rs:9:13 | -LL | let _ = box () - | ^^^ expected expression +LL | let _ = box (); + | ^^^^^^ + | +help: use `Box::new()` instead + | +LL | let _ = Box::new(()); + | ~~~~~~~~~~~~ + +error: `box_syntax` has been removed + --> $DIR/removed-syntax-box.rs:10:13 + | +LL | let _ = box 1; + | ^^^^^ + | +help: use `Box::new()` instead + | +LL | let _ = Box::new(1); + | ~~~~~~~~~~~ + +error: `box_syntax` has been removed + --> $DIR/removed-syntax-box.rs:11:13 + | +LL | let _ = box T { a: 12, b: 18 }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `Box::new()` instead + | +LL | let _ = Box::new(T { a: 12, b: 18 }); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: `box_syntax` has been removed + --> $DIR/removed-syntax-box.rs:12:13 + | +LL | let _ = box [5; 30]; + | ^^^^^^^^^^^ + | +help: use `Box::new()` instead + | +LL | let _ = Box::new([5; 30]); + | ~~~~~~~~~~~~~~~~~ + +error: `box_syntax` has been removed + --> $DIR/removed-syntax-box.rs:13:22 + | +LL | let _: Box<()> = box (); + | ^^^^^^ + | +help: use `Box::new()` instead + | +LL | let _: Box<()> = Box::new(()); + | ~~~~~~~~~~~~ -error: aborting due to previous error +error: aborting due to 5 previous errors diff --git a/tests/ui/unpretty/box.stdout b/tests/ui/unpretty/box.stdout index 1318a56e3bee0..0c6e012e698f9 100644 --- a/tests/ui/unpretty/box.stdout +++ b/tests/ui/unpretty/box.stdout @@ -10,5 +10,5 @@ extern crate std; fn main() { let _ = #[rustc_box] - Box::new (1); + Box::new(1); }