Skip to content

Commit

Permalink
Merge pull request #1531 from dtolnay/breaklabel
Browse files Browse the repository at this point in the history
Improve parsing of labeled loop as value expression for break
  • Loading branch information
dtolnay authored Nov 6, 2023
2 parents 6f658f8 + b88f86f commit 95aeeb5
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 12 deletions.
38 changes: 28 additions & 10 deletions src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2463,18 +2463,36 @@ pub(crate) mod parsing {

#[cfg(feature = "full")]
fn expr_break(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprBreak> {
let break_token: Token![break] = input.parse()?;

let ahead = input.fork();
let label: Option<Lifetime> = ahead.parse()?;
if label.is_some() && ahead.peek(Token![:]) {
// Not allowed: `break 'label: loop {...}`
// Parentheses are required. `break ('label: loop {...})`
let _ = ambiguous_expr(input, allow_struct)?;
let start_span = label.unwrap().apostrophe;
let end_span = input.cursor().prev_span();
return Err(crate::error::new2(
start_span,
end_span,
"parentheses required",
));
}

input.advance_to(&ahead);
let expr = if can_begin_expr(input) && (allow_struct.0 || !input.peek(token::Brace)) {
let expr = ambiguous_expr(input, allow_struct)?;
Some(Box::new(expr))
} else {
None
};

Ok(ExprBreak {
attrs: Vec::new(),
break_token: input.parse()?,
label: input.parse()?,
expr: {
if can_begin_expr(input) && (allow_struct.0 || !input.peek(token::Brace)) {
let expr = ambiguous_expr(input, allow_struct)?;
Some(Box::new(expr))
} else {
None
}
},
break_token,
label,
expr,
})
}

Expand Down
33 changes: 31 additions & 2 deletions tests/test_expr.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#![allow(clippy::uninlined_format_args)]
#![allow(clippy::single_element_loop, clippy::uninlined_format_args)]

#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use quote::quote;
use syn::{Expr, ExprRange};
use syn::{Expr, ExprRange, Stmt};

#[test]
fn test_expr_parse() {
Expand Down Expand Up @@ -310,3 +310,32 @@ fn test_ranges() {
syn::parse_str::<Expr>("lo...").unwrap_err();
syn::parse_str::<Expr>("lo...hi").unwrap_err();
}

#[test]
fn test_ambiguous_label() {
for stmt in [
quote! {
return 'label: loop { break 'label 42; };
},
quote! {
break ('label: loop { break 'label 42; });
},
quote! {
break 1 + 'label: loop { break 'label 42; };
},
quote! {
break 'outer 'inner: loop { break 'inner 42; };
},
] {
syn::parse2::<Stmt>(stmt).unwrap();
}

for stmt in [
// Parentheses required. See https:/rust-lang/rust/pull/87026.
quote! {
break 'label: loop { break 'label 42; };
},
] {
syn::parse2::<Stmt>(stmt).unwrap_err();
}
}

0 comments on commit 95aeeb5

Please sign in to comment.