From 80604dc8efae5e58ee13f7d85816b980db7a0878 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 10 Dec 2023 17:14:04 -0800 Subject: [PATCH] Fix parsing of labeled loop followed by paren in stmt or match arm position --- src/expr.rs | 47 ++++++++++++++++++++++++++-------------------- tests/test_stmt.rs | 21 +++++++++++---------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 22400be329..ca6471c17b 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1663,31 +1663,36 @@ pub(crate) mod parsing { } else if input.peek(Token![_]) { input.parse().map(Expr::Infer) } else if input.peek(Lifetime) { - let the_label: Label = input.parse()?; - let mut expr = if input.peek(Token![while]) { - Expr::While(input.parse()?) - } else if input.peek(Token![for]) { - Expr::ForLoop(input.parse()?) - } else if input.peek(Token![loop]) { - Expr::Loop(input.parse()?) - } else if input.peek(token::Brace) { - Expr::Block(input.parse()?) - } else { - return Err(input.error("expected loop or block expression")); - }; - match &mut expr { - Expr::While(ExprWhile { label, .. }) - | Expr::ForLoop(ExprForLoop { label, .. }) - | Expr::Loop(ExprLoop { label, .. }) - | Expr::Block(ExprBlock { label, .. }) => *label = Some(the_label), - _ => unreachable!(), - } - Ok(expr) + atom_labeled(input) } else { Err(input.error("expected an expression")) } } + #[cfg(feature = "full")] + fn atom_labeled(input: ParseStream) -> Result { + let the_label: Label = input.parse()?; + let mut expr = if input.peek(Token![while]) { + Expr::While(input.parse()?) + } else if input.peek(Token![for]) { + Expr::ForLoop(input.parse()?) + } else if input.peek(Token![loop]) { + Expr::Loop(input.parse()?) + } else if input.peek(token::Brace) { + Expr::Block(input.parse()?) + } else { + return Err(input.error("expected loop or block expression")); + }; + match &mut expr { + Expr::While(ExprWhile { label, .. }) + | Expr::ForLoop(ExprForLoop { label, .. }) + | Expr::Loop(ExprLoop { label, .. }) + | Expr::Block(ExprBlock { label, .. }) => *label = Some(the_label), + _ => unreachable!(), + } + Ok(expr) + } + #[cfg(not(feature = "full"))] fn atom_expr(input: ParseStream) -> Result { if input.peek(token::Group) @@ -1935,6 +1940,8 @@ pub(crate) mod parsing { Expr::Const(input.parse()?) } else if input.peek(token::Brace) { Expr::Block(input.parse()?) + } else if input.peek(Lifetime) { + atom_labeled(input)? } else { let allow_struct = AllowStruct(true); let mut expr = unary_expr(input, allow_struct)?; diff --git a/tests/test_stmt.rs b/tests/test_stmt.rs index b3a25aa340..b27ee581ed 100644 --- a/tests/test_stmt.rs +++ b/tests/test_stmt.rs @@ -269,22 +269,23 @@ fn test_early_parse_loop() { let stmts = Block::parse_within.parse2(tokens).unwrap(); - // FIXME snapshot!(stmts, @r###" [ Stmt::Expr( - Expr::Call { - func: Expr::Loop { - label: Some(Label { - name: Lifetime { - ident: "a", - }, - }), - body: Block, - }, + Expr::Loop { + label: Some(Label { + name: Lifetime { + ident: "a", + }, + }), + body: Block, }, None, ), + Stmt::Expr( + Expr::Tuple, + None, + ), ] "###); }