From 1a77631a8cea2b641cf5844ff8fd99db20214699 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 10 Dec 2023 17:06:59 -0800 Subject: [PATCH 1/2] Add test of parsing loop followed by unit expr --- tests/test_stmt.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/tests/test_stmt.rs b/tests/test_stmt.rs index bc57685df7..b3a25aa340 100644 --- a/tests/test_stmt.rs +++ b/tests/test_stmt.rs @@ -9,7 +9,8 @@ mod macros; use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; use quote::quote; -use syn::Stmt; +use syn::parse::Parser as _; +use syn::{Block, Stmt}; #[test] fn test_raw_operator() { @@ -234,3 +235,56 @@ fn test_macros() { }) "###); } + +#[test] +fn test_early_parse_loop() { + // The following is an Expr::Loop followed by Expr::Tuple. It is not an + // Expr::Call. + let tokens = quote! { + loop {} + () + }; + + let stmts = Block::parse_within.parse2(tokens).unwrap(); + + snapshot!(stmts, @r###" + [ + Stmt::Expr( + Expr::Loop { + body: Block, + }, + None, + ), + Stmt::Expr( + Expr::Tuple, + None, + ), + ] + "###); + + let tokens = quote! { + 'a: 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, + }, + }, + None, + ), + ] + "###); +} From 80604dc8efae5e58ee13f7d85816b980db7a0878 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 10 Dec 2023 17:14:04 -0800 Subject: [PATCH 2/2] 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, + ), ] "###); }