From 05c516446a0f6105ce695da00d5cf5a0eb54e808 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 2 Oct 2024 16:35:37 -0300 Subject: Implement .use keyword as an alias of clone --- compiler/rustc_parse/messages.ftl | 3 +++ compiler/rustc_parse/src/errors.rs | 13 +++++++++++++ compiler/rustc_parse/src/parser/diagnostics.rs | 21 ++++++++++++++++++--- compiler/rustc_parse/src/parser/expr.rs | 15 +++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) (limited to 'compiler/rustc_parse') diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 1d5b5942170..0289fa5f493 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -348,6 +348,9 @@ parse_incorrect_use_of_await = incorrect use of `await` parse_incorrect_use_of_await_postfix_suggestion = `await` is a postfix operation +parse_incorrect_use_of_use = incorrect use of `use` + .parentheses_suggestion = `use` is not a method call, try removing the parentheses + parse_incorrect_visibility_restriction = incorrect visibility restriction .help = some possible visibility restrictions are: `pub(crate)`: visible only on the current crate diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 8d2fd595942..d89bb1451b6 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -106,6 +106,19 @@ pub(crate) struct IncorrectUseOfAwait { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_incorrect_use_of_use)] +pub(crate) struct IncorrectUseOfUse { + #[primary_span] + #[suggestion( + parse_parentheses_suggestion, + style = "verbose", + code = "", + applicability = "machine-applicable" + )] + pub span: Span, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( parse_incorrect_use_of_await_postfix_suggestion, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 94db43bb59f..dd511fcd8c0 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -38,8 +38,8 @@ use crate::errors::{ DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, - IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType, - QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, + IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, + QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, @@ -1991,7 +1991,7 @@ impl<'a> Parser<'a> { self.parse_expr() } .map_err(|mut err| { - err.span_label(await_sp, "while parsing this incorrect await expression"); + err.span_label(await_sp, format!("while parsing this incorrect await expression")); err })?; Ok((expr.span, expr, is_question)) @@ -2030,6 +2030,21 @@ impl<'a> Parser<'a> { self.dcx().emit_err(IncorrectUseOfAwait { span }); } } + /// + /// If encountering `x.use()`, consumes and emits an error. + pub(super) fn recover_from_use(&mut self) { + if self.token == token::OpenDelim(Delimiter::Parenthesis) + && self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) + { + // var.use() + let lo = self.token.span; + self.bump(); // ( + let span = lo.to(self.token.span); + self.bump(); // ) + + self.dcx().emit_err(IncorrectUseOfUse { span }); + } + } pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P> { let is_try = self.token.is_keyword(kw::Try); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0a08c6faeb4..c00f7f2d8de 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -778,6 +778,7 @@ impl<'a> Parser<'a> { ExprKind::MethodCall(_) => "a method call", ExprKind::Call(_, _) => "a function call", ExprKind::Await(_, _) => "`.await`", + ExprKind::Use(_, _) => "`.use`", ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match", ExprKind::Err(_) => return Ok(with_postfix), _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), @@ -1296,6 +1297,12 @@ impl<'a> Parser<'a> { return Ok(self.mk_await_expr(self_arg, lo)); } + if self.eat_keyword(exp!(Use)) { + let use_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::ergonomic_clones, use_span); + return Ok(self.mk_use_expr(self_arg, lo)); + } + // Post-fix match if self.eat_keyword(exp!(Match)) { let match_span = self.prev_token.span; @@ -3818,6 +3825,13 @@ impl<'a> Parser<'a> { await_expr } + fn mk_use_expr(&mut self, self_arg: P, lo: Span) -> P { + let span = lo.to(self.prev_token.span); + let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span)); + self.recover_from_use(); + use_expr + } + pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P { P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None }) } @@ -3966,6 +3980,7 @@ impl MutVisitor for CondChecker<'_> { } ExprKind::Unary(_, _) | ExprKind::Await(_, _) + | ExprKind::Use(_, _) | ExprKind::AssignOp(_, _, _) | ExprKind::Range(_, _, _) | ExprKind::Try(_) -- cgit 1.4.1-3-g733a5 From 81a926cc2ae22bed26c57a7ef481099916fc1cc8 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 1 Nov 2024 18:37:32 -0300 Subject: Use closure parse code --- compiler/rustc_ast/src/ast.rs | 5 ++ compiler/rustc_ast/src/mut_visit.rs | 3 + compiler/rustc_ast_pretty/src/pprust/state/expr.rs | 1 + compiler/rustc_borrowck/src/borrowck_errors.rs | 1 + compiler/rustc_hir_pretty/src/lib.rs | 1 + compiler/rustc_hir_typeck/src/upvar.rs | 14 ++-- compiler/rustc_parse/messages.ftl | 3 + compiler/rustc_parse/src/errors.rs | 8 +++ compiler/rustc_parse/src/parser/expr.rs | 15 ++++- compiler/rustc_parse/src/parser/item.rs | 2 +- .../edition-keywords-2018-2015-parsing.stderr | 8 +-- .../edition-keywords-2018-2018-parsing.stderr | 16 ++--- tests/ui/ergonomic-clones/closure.rs | 23 +++++++ .../feature-gates/feature-gate-ergonomic-clones.rs | 5 +- .../feature-gate-ergonomic-clones.stderr | 76 ++++++++++++---------- tests/ui/parser/block-no-opening-brace.rs | 2 +- tests/ui/parser/block-no-opening-brace.stderr | 4 +- .../parser/misspelled-keywords/async-move.stderr | 4 +- .../parser/recover/recover-quantified-closure.rs | 2 +- .../recover/recover-quantified-closure.stderr | 4 +- 20 files changed, 133 insertions(+), 64 deletions(-) create mode 100644 tests/ui/ergonomic-clones/closure.rs (limited to 'compiler/rustc_parse') diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3987aea6066..66a8d1ce86a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1762,6 +1762,11 @@ pub enum CaptureBy { }, /// `move` keyword was not specified. Ref, + /// `use |x| y + x`. + Use { + /// The span of the `use` keyword. + use_kw: Span, + }, } /// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 5841805abd7..ee894db7b96 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1899,6 +1899,9 @@ fn walk_capture_by(vis: &mut T, capture_by: &mut CaptureBy) { CaptureBy::Value { move_kw } => { vis.visit_span(move_kw); } + CaptureBy::Use { use_kw } => { + vis.visit_span(use_kw); + } } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 9d11115ecbf..e3c41f117ab 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -893,6 +893,7 @@ impl<'a> State<'a> { fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) { match capture_clause { ast::CaptureBy::Value { .. } => self.word_space("move"), + ast::CaptureBy::Use { .. } => self.word_space("use"), ast::CaptureBy::Ref => {} } } diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 30e94b0bec7..c9be5575da5 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -403,6 +403,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> { .expect_closure(); let span = match capture_clause { rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(), + rustc_hir::CaptureBy::Use { use_kw } => use_kw.shrink_to_lo(), rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(), }; diag.span_suggestion_verbose( diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5f632bdc517..b04d3256f7b 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2305,6 +2305,7 @@ impl<'a> State<'a> { fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) { match capture_clause { hir::CaptureBy::Value { .. } => self.word_space("move"), + hir::CaptureBy::Use { .. } => self.word_space("use"), hir::CaptureBy::Ref => {} } } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 9a0b2247058..4c2a0e1a26b 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -670,7 +670,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { origin = updated.1; let (place, capture_kind) = match capture_clause { - hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind), + hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } => { + adjust_for_move_closure(place, capture_kind) + } hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind), }; @@ -1165,7 +1167,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match closure_clause { hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value - hir::CaptureBy::Ref => { + hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => { // For non move closure the capture kind is the max capture kind of all captures // according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue let mut max_capture_info = root_var_min_capture_list.first().unwrap().info; @@ -1292,7 +1294,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span }); return Some(diagnostics_info); } - hir::CaptureBy::Ref => {} + hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {} } return None; @@ -1689,10 +1691,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // If the data will be moved out of this place, then the place will be truncated // at the first Deref in `adjust_for_move_closure` and then moved into the closure. - hir::CaptureBy::Value { .. } if !place.deref_tys().any(Ty::is_ref) => { + hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } + if !place.deref_tys().any(Ty::is_ref) => + { ty::UpvarCapture::ByValue } - hir::CaptureBy::Value { .. } | hir::CaptureBy::Ref => { + hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } | hir::CaptureBy::Ref => { ty::UpvarCapture::ByRef(BorrowKind::Immutable) } } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 0289fa5f493..a1d7d321d8a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -26,6 +26,9 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect .suggestion = try switching the order +parse_async_use_order_incorrect = the order of `use` and `async` is incorrect + .suggestion = try switching the order + parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index d89bb1451b6..f75fc8f9830 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1512,6 +1512,14 @@ pub(crate) struct AsyncMoveOrderIncorrect { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_async_use_order_incorrect)] +pub(crate) struct AsyncUseOrderIncorrect { + #[primary_span] + #[suggestion(style = "verbose", code = "async use", applicability = "maybe-incorrect")] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_double_colon_in_bound)] pub(crate) struct DoubleColonInBound { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index c00f7f2d8de..b37dd64fbed 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1404,6 +1404,7 @@ impl<'a> Parser<'a> { } else if this.check_path() { this.parse_expr_path_start() } else if this.check_keyword(exp!(Move)) + || this.check_keyword(exp!(Use)) || this.check_keyword(exp!(Static)) || this.check_const_closure() { @@ -2395,7 +2396,7 @@ impl<'a> Parser<'a> { Ok(closure) } - /// Parses an optional `move` prefix to a closure-like construct. + /// Parses an optional `move` or `use` prefix to a closure-like construct. fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { if self.eat_keyword(exp!(Move)) { let move_kw_span = self.prev_token.span; @@ -2408,6 +2409,16 @@ impl<'a> Parser<'a> { } else { Ok(CaptureBy::Value { move_kw: move_kw_span }) } + } else if self.eat_keyword(exp!(Use)) { + let use_kw_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span); + // Check for `use async` and recover + if self.check_keyword(exp!(Async)) { + let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span })) + } else { + Ok(CaptureBy::Use { use_kw: use_kw_span }) + } } else { Ok(CaptureBy::Ref) } @@ -3422,7 +3433,7 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(lookahead, &[kw]) && (( // `async move {` - self.is_keyword_ahead(lookahead + 1, &[kw::Move]) + self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use]) && self.look_ahead(lookahead + 2, |t| { *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() }) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3f642a7ac1f..7b511f503dd 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1290,7 +1290,7 @@ impl<'a> Parser<'a> { if self.check_keyword(exp!(Static)) { // Check if this could be a closure. !self.look_ahead(1, |token| { - if token.is_keyword(kw::Move) { + if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) { return true; } matches!(token.kind, token::Or | token::OrOr) diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr index 905e1249d97..152a6f3a41e 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -44,22 +44,22 @@ note: while trying to match `r#async` LL | (r#async) => (1) | ^^^^^^^ -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2015-parsing.rs:22:8 | LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved | -------------------- in this macro invocation -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2015-parsing.rs:24:24 | LL | if passes_tt!(async) == 1 {} - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` error[E0308]: mismatched types --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33 diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr index af5cc515bb2..53f1b827f9c 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -44,34 +44,34 @@ note: while trying to match `r#async` LL | (r#async) => (1) | ^^^^^^^ -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2018-parsing.rs:29:8 | LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved | -------------------- in this macro invocation -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:31:24 | LL | if passes_tt!(async) == 1 {} - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:14:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` -error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:35:30 | LL | if local_passes_tt!(async) == 1 {} - | ^ expected one of `move`, `|`, or `||` + | ^ expected one of `move`, `use`, `|`, or `||` error[E0308]: mismatched types --> $DIR/edition-keywords-2018-2018-parsing.rs:40:33 diff --git a/tests/ui/ergonomic-clones/closure.rs b/tests/ui/ergonomic-clones/closure.rs new file mode 100644 index 00000000000..ea5c06457f5 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure.rs @@ -0,0 +1,23 @@ +//@ check-pass +//@ edition:2018 + +#![feature(ergonomic_clones)] + +fn ergonomic_clone_closure() -> i32 { + let cl = use || { + 1 + }; + cl() +} + +fn ergonomic_clone_async_closures() -> String { + let s = String::from("hi"); + + async use { + 22 + }; + + s +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs index be65afd85d9..f00f15174b2 100644 --- a/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs +++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs @@ -7,12 +7,13 @@ fn ergonomic_closure_clone() { let s1 = String::from("hi!"); let s2 = use || { - //~^ ERROR incorrect use of `use` + //~^ ERROR `.use` calls are experimental [E0658] s1 }; let s3 = use || { - //~^ ERROR incorrect use of `use` + //~^ ERROR `.use` calls are experimental [E0658] + //~| ERROR use of moved value: `s1` [E0382] s1 }; } diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr index 61583239815..c83b4400d3c 100644 --- a/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr +++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr @@ -1,49 +1,57 @@ -error: incorrect use of `use` - --> $DIR/feature-gate-ergonomic-clones.rs:9:14 +error[E0658]: `.use` calls are experimental + --> $DIR/feature-gate-ergonomic-clones.rs:2:7 | -LL | let s2 = use || { - | ______________^ -LL | | -LL | | s1 -LL | | }; - | |_____^ +LL | x.use + | ^^^ | -help: `use` is a postfix operation + = note: see issue #132290 for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `.use` calls are experimental + --> $DIR/feature-gate-ergonomic-clones.rs:9:14 | -LL ~ let s2 = || { -LL | -LL | s1 -LL ~ }.use; +LL | let s2 = use || { + | ^^^ | + = note: see issue #132290 for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: incorrect use of `use` +error[E0658]: `.use` calls are experimental --> $DIR/feature-gate-ergonomic-clones.rs:14:14 | -LL | let s3 = use || { - | ______________^ -LL | | -LL | | s1 -LL | | }; - | |_____^ +LL | let s3 = use || { + | ^^^ | -help: `use` is a postfix operation + = note: see issue #132290 for more information + = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0382]: use of moved value: `s1` + --> $DIR/feature-gate-ergonomic-clones.rs:14:14 | -LL ~ let s3 = || { +LL | let s1 = String::from("hi!"); + | -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait +LL | +LL | let s2 = use || { + | ------ value moved into closure here LL | LL | s1 -LL ~ }.use; - | - -error[E0658]: `.use` calls are experimental - --> $DIR/feature-gate-ergonomic-clones.rs:2:7 + | -- variable moved due to use in closure +... +LL | let s3 = use || { + | ^^^^^^ value used here after move +... +LL | s1 + | -- use occurs due to use in closure | -LL | x.use - | ^^^ +help: consider cloning the value if the performance cost is acceptable | - = note: see issue #132290 for more information - = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +LL | s1.clone() + | ++++++++ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0382, E0658. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/parser/block-no-opening-brace.rs b/tests/ui/parser/block-no-opening-brace.rs index 2fde37ce6ac..b08c830bfc7 100644 --- a/tests/ui/parser/block-no-opening-brace.rs +++ b/tests/ui/parser/block-no-opening-brace.rs @@ -30,7 +30,7 @@ fn in_try() { // FIXME(#80931) fn in_async() { async - let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let` + let x = 0; //~ ERROR expected one of `move`, `use`, `|`, or `||`, found keyword `let` } // FIXME(#78168) diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr index b65de4eac3f..f51ee92626f 100644 --- a/tests/ui/parser/block-no-opening-brace.stderr +++ b/tests/ui/parser/block-no-opening-brace.stderr @@ -43,11 +43,11 @@ error: expected expression, found reserved keyword `try` LL | try | ^^^ expected expression -error: expected one of `move`, `|`, or `||`, found keyword `let` +error: expected one of `move`, `use`, `|`, or `||`, found keyword `let` --> $DIR/block-no-opening-brace.rs:33:9 | LL | async - | - expected one of `move`, `|`, or `||` + | - expected one of `move`, `use`, `|`, or `||` LL | let x = 0; | ^^^ unexpected token diff --git a/tests/ui/parser/misspelled-keywords/async-move.stderr b/tests/ui/parser/misspelled-keywords/async-move.stderr index a002d54dc91..2507326fb28 100644 --- a/tests/ui/parser/misspelled-keywords/async-move.stderr +++ b/tests/ui/parser/misspelled-keywords/async-move.stderr @@ -1,8 +1,8 @@ -error: expected one of `move`, `|`, or `||`, found `Move` +error: expected one of `move`, `use`, `|`, or `||`, found `Move` --> $DIR/async-move.rs:4:11 | LL | async Move {} - | ^^^^ expected one of `move`, `|`, or `||` + | ^^^^ expected one of `move`, `use`, `|`, or `||` | help: write keyword `move` in lowercase | diff --git a/tests/ui/parser/recover/recover-quantified-closure.rs b/tests/ui/parser/recover/recover-quantified-closure.rs index 10af39b7007..1f5004ad099 100644 --- a/tests/ui/parser/recover/recover-quantified-closure.rs +++ b/tests/ui/parser/recover/recover-quantified-closure.rs @@ -7,6 +7,6 @@ fn main() { enum Foo { Bar } fn foo(x: impl Iterator) { for ::Bar in x {} - //~^ ERROR expected one of `move`, `static`, `|` + //~^ ERROR expected one of `move`, `static`, `use`, `|` //~^^ ERROR `for<...>` binders for closures are experimental } diff --git a/tests/ui/parser/recover/recover-quantified-closure.stderr b/tests/ui/parser/recover/recover-quantified-closure.stderr index 6e03bbb5869..48dea071ae6 100644 --- a/tests/ui/parser/recover/recover-quantified-closure.stderr +++ b/tests/ui/parser/recover/recover-quantified-closure.stderr @@ -1,8 +1,8 @@ -error: expected one of `move`, `static`, `|`, or `||`, found `::` +error: expected one of `move`, `static`, `use`, `|`, or `||`, found `::` --> $DIR/recover-quantified-closure.rs:9:14 | LL | for ::Bar in x {} - | ^^ expected one of `move`, `static`, `|`, or `||` + | ^^ expected one of `move`, `static`, `use`, `|`, or `||` error[E0658]: `for<...>` binders for closures are experimental --> $DIR/recover-quantified-closure.rs:2:5 -- cgit 1.4.1-3-g733a5 From 38b4746d824294d05d87a6e461113a99ac052c34 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 10 Feb 2025 18:09:31 -0300 Subject: Support nested use closures --- compiler/rustc_parse/src/parser/item.rs | 4 +++- tests/ui/ergonomic-clones/closure/nested.rs | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/ui/ergonomic-clones/closure/nested.rs (limited to 'compiler/rustc_parse') diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 7b511f503dd..961e81989d6 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -209,7 +209,9 @@ impl<'a> Parser<'a> { let check_pub = def == &Defaultness::Final; let mut def_ = || mem::replace(def, Defaultness::Final); - let info = if self.eat_keyword_case(exp!(Use), case) { + let info = if !self.look_ahead(1, |t| [token::OrOr, token::Or].contains(&t.kind)) + && self.eat_keyword_case(exp!(Use), case) + { self.parse_use_item()? } else if self.check_fn_front_matter(check_pub, case) { // FUNCTION ITEM diff --git a/tests/ui/ergonomic-clones/closure/nested.rs b/tests/ui/ergonomic-clones/closure/nested.rs new file mode 100644 index 00000000000..5876396f087 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/nested.rs @@ -0,0 +1,20 @@ +//@ run-pass + +#![feature(ergonomic_clones)] + +use std::clone::UseCloned; + +#[derive(Clone)] +struct Foo; + +impl UseCloned for Foo {} + +fn work(_: Box) {} +fn foo(_: F) {} + +pub fn main() { + let a = Box::new(Foo); + foo(use || { foo(use || { work(a) }) }); + let x = use || { use || { Foo } }; + let _y = x(); +} -- cgit 1.4.1-3-g733a5 From 292aa8704957f0c0a94cc0cb01c74267d2bdfe27 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 11 Feb 2025 11:13:33 -0300 Subject: Fix use closure parsing error message --- compiler/rustc_parse/src/parser/item.rs | 19 ++++++++++++++++--- tests/ui/ergonomic-clones/closure/parse.rs | 4 +--- tests/ui/ergonomic-clones/closure/parse.stderr | 12 +++--------- 3 files changed, 20 insertions(+), 15 deletions(-) (limited to 'compiler/rustc_parse') diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 961e81989d6..678376aee4f 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -209,9 +209,7 @@ impl<'a> Parser<'a> { let check_pub = def == &Defaultness::Final; let mut def_ = || mem::replace(def, Defaultness::Final); - let info = if !self.look_ahead(1, |t| [token::OrOr, token::Or].contains(&t.kind)) - && self.eat_keyword_case(exp!(Use), case) - { + let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) { self.parse_use_item()? } else if self.check_fn_front_matter(check_pub, case) { // FUNCTION ITEM @@ -1279,6 +1277,21 @@ impl<'a> Parser<'a> { None } + fn is_use_closure(&self) -> bool { + if self.token.is_keyword(kw::Use) { + // Check if this could be a closure. + self.look_ahead(1, |token| { + // Move or Async here would be an error but still we're parsing a closure + let dist = + if token.is_keyword(kw::Move) || token.is_keyword(kw::Async) { 2 } else { 1 }; + + self.look_ahead(dist, |token| matches!(token.kind, token::Or | token::OrOr)) + }) + } else { + false + } + } + fn is_unsafe_foreign_mod(&self) -> bool { self.token.is_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Extern]) diff --git a/tests/ui/ergonomic-clones/closure/parse.rs b/tests/ui/ergonomic-clones/closure/parse.rs index d4523de57ff..23fce20e370 100644 --- a/tests/ui/ergonomic-clones/closure/parse.rs +++ b/tests/ui/ergonomic-clones/closure/parse.rs @@ -14,9 +14,7 @@ fn parse2() { fn parse3() { use move || { - //~^ ERROR expected identifier, found keyword `move` - //~| ERROR expected one of `::`, `;`, or `as`, found `||` - // FIXME ideally we should error like in the previous example + //~^ ERROR expected one of `async`, `|`, or `||`, found keyword `move` }; } diff --git a/tests/ui/ergonomic-clones/closure/parse.stderr b/tests/ui/ergonomic-clones/closure/parse.stderr index ac86a041929..c45c46eefa5 100644 --- a/tests/ui/ergonomic-clones/closure/parse.stderr +++ b/tests/ui/ergonomic-clones/closure/parse.stderr @@ -18,17 +18,11 @@ error: expected one of `async`, `|`, or `||`, found keyword `use` LL | move use || { | ^^^ expected one of `async`, `|`, or `||` -error: expected identifier, found keyword `move` +error: expected one of `async`, `|`, or `||`, found keyword `move` --> $DIR/parse.rs:16:9 | LL | use move || { - | ^^^^ expected identifier, found keyword + | ^^^^ expected one of `async`, `|`, or `||` -error: expected one of `::`, `;`, or `as`, found `||` - --> $DIR/parse.rs:16:14 - | -LL | use move || { - | ^^ expected one of `::`, `;`, or `as` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From 4e6407ab947314480f3b978a20f9b0685ad59f78 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 21 Feb 2025 17:24:46 -0300 Subject: Give a better error message on async use in edition 2015 --- compiler/rustc_parse/messages.ftl | 2 ++ compiler/rustc_parse/src/errors.rs | 7 +++++++ compiler/rustc_parse/src/parser/diagnostics.rs | 23 ++++++++++++++-------- tests/ui/ergonomic-clones/async/edition-2015.rs | 6 ++++++ .../ui/ergonomic-clones/async/edition-2015.stderr | 8 ++++++++ 5 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 tests/ui/ergonomic-clones/async/edition-2015.rs create mode 100644 tests/ui/ergonomic-clones/async/edition-2015.stderr (limited to 'compiler/rustc_parse') diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index a1d7d321d8a..6d4308cda1a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -26,6 +26,8 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect .suggestion = try switching the order +parse_async_use_block_in_2015 = `async use` blocks are only allowed in Rust 2018 or later + parse_async_use_order_incorrect = the order of `use` and `async` is incorrect .suggestion = try switching the order diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index f75fc8f9830..e090d9cf760 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1688,6 +1688,13 @@ pub(crate) struct AsyncMoveBlockIn2015 { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_async_use_block_in_2015)] +pub(crate) struct AsyncUseBlockIn2015 { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_async_bound_modifier_in_2015)] pub(crate) struct AsyncBoundModifierIn2015 { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index dd511fcd8c0..bb227a58cf1 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -31,11 +31,11 @@ use super::{ SeqSep, TokenType, }; use crate::errors::{ - AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion, - BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, - ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces, - ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType, - DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, + AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType, + AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, + ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, + ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, + DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, @@ -572,10 +572,17 @@ impl<'a> Parser<'a> { return Err(self.dcx().create_err(UseEqInstead { span: self.token.span })); } - if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) { - // The 2015 edition is in use because parsing of `async move` has failed. + if (self.token.is_keyword(kw::Move) || self.token.is_keyword(kw::Use)) + && self.prev_token.is_keyword(kw::Async) + { + // The 2015 edition is in use because parsing of `async move` or `async use` has failed. let span = self.prev_token.span.to(self.token.span); - return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span })); + if self.token.is_keyword(kw::Move) { + return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span })); + } else { + // kw::Use + return Err(self.dcx().create_err(AsyncUseBlockIn2015 { span })); + } } let expect = tokens_to_string(&expected); diff --git a/tests/ui/ergonomic-clones/async/edition-2015.rs b/tests/ui/ergonomic-clones/async/edition-2015.rs new file mode 100644 index 00000000000..64f62ea099e --- /dev/null +++ b/tests/ui/ergonomic-clones/async/edition-2015.rs @@ -0,0 +1,6 @@ +#![feature(ergonomic_clones)] + +fn main() { + async use {}; + //~^ ERROR `async use` blocks are only allowed in Rust 2018 or later +} diff --git a/tests/ui/ergonomic-clones/async/edition-2015.stderr b/tests/ui/ergonomic-clones/async/edition-2015.stderr new file mode 100644 index 00000000000..e65e8d77910 --- /dev/null +++ b/tests/ui/ergonomic-clones/async/edition-2015.stderr @@ -0,0 +1,8 @@ +error: `async use` blocks are only allowed in Rust 2018 or later + --> $DIR/edition-2015.rs:4:5 + | +LL | async use {}; + | ^^^^^^^^^ + +error: aborting due to 1 previous error + -- cgit 1.4.1-3-g733a5 From 65d65e5e7eac02bfbb9f4053b7ec0db8f4c0f183 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 21 Feb 2025 17:38:30 -0300 Subject: Parse and allow const use closures --- compiler/rustc_parse/src/parser/mod.rs | 6 +++--- tests/ui/ergonomic-clones/closure/const-closure.rs | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 tests/ui/ergonomic-clones/closure/const-closure.rs (limited to 'compiler/rustc_parse') diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 7dabc28c645..4ec8d9e5e49 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -813,9 +813,9 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(0, &[kw::Const]) && self.look_ahead(1, |t| match &t.kind { // async closures do not work with const closures, so we do not parse that here. - token::Ident(kw::Move | kw::Static, IdentIsRaw::No) | token::OrOr | token::Or => { - true - } + token::Ident(kw::Move | kw::Use | kw::Static, IdentIsRaw::No) + | token::OrOr + | token::Or => true, _ => false, }) } diff --git a/tests/ui/ergonomic-clones/closure/const-closure.rs b/tests/ui/ergonomic-clones/closure/const-closure.rs new file mode 100644 index 00000000000..6b4de824df9 --- /dev/null +++ b/tests/ui/ergonomic-clones/closure/const-closure.rs @@ -0,0 +1,11 @@ +//@ check-pass + +#![feature(const_closures)] +#![feature(ergonomic_clones)] +#![allow(incomplete_features)] + +const fn foo() { + let cl = const use || {}; +} + +fn main() {} -- cgit 1.4.1-3-g733a5