xref: /linux/rust/syn/stmt.rs (revision 784faa8eca8270671e0ed6d9d21f04bbb80fc5f7)
1*69942c0aSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT
2*69942c0aSMiguel Ojeda 
3808c999fSMiguel Ojeda use crate::attr::Attribute;
4808c999fSMiguel Ojeda use crate::expr::Expr;
5808c999fSMiguel Ojeda use crate::item::Item;
6808c999fSMiguel Ojeda use crate::mac::Macro;
7808c999fSMiguel Ojeda use crate::pat::Pat;
8808c999fSMiguel Ojeda use crate::token;
9808c999fSMiguel Ojeda 
10808c999fSMiguel Ojeda ast_struct! {
11808c999fSMiguel Ojeda     /// A braced block containing Rust statements.
12808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
13808c999fSMiguel Ojeda     pub struct Block {
14808c999fSMiguel Ojeda         pub brace_token: token::Brace,
15808c999fSMiguel Ojeda         /// Statements in a block
16808c999fSMiguel Ojeda         pub stmts: Vec<Stmt>,
17808c999fSMiguel Ojeda     }
18808c999fSMiguel Ojeda }
19808c999fSMiguel Ojeda 
20808c999fSMiguel Ojeda ast_enum! {
21808c999fSMiguel Ojeda     /// A statement, usually ending in a semicolon.
22808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
23808c999fSMiguel Ojeda     pub enum Stmt {
24808c999fSMiguel Ojeda         /// A local (let) binding.
25808c999fSMiguel Ojeda         Local(Local),
26808c999fSMiguel Ojeda 
27808c999fSMiguel Ojeda         /// An item definition.
28808c999fSMiguel Ojeda         Item(Item),
29808c999fSMiguel Ojeda 
30808c999fSMiguel Ojeda         /// Expression, with or without trailing semicolon.
31808c999fSMiguel Ojeda         Expr(Expr, Option<Token![;]>),
32808c999fSMiguel Ojeda 
33808c999fSMiguel Ojeda         /// A macro invocation in statement position.
34808c999fSMiguel Ojeda         ///
35808c999fSMiguel Ojeda         /// Syntactically it's ambiguous which other kind of statement this
36808c999fSMiguel Ojeda         /// macro would expand to. It can be any of local variable (`let`),
37808c999fSMiguel Ojeda         /// item, or expression.
38808c999fSMiguel Ojeda         Macro(StmtMacro),
39808c999fSMiguel Ojeda     }
40808c999fSMiguel Ojeda }
41808c999fSMiguel Ojeda 
42808c999fSMiguel Ojeda ast_struct! {
43808c999fSMiguel Ojeda     /// A local `let` binding: `let x: u64 = s.parse()?;`.
44808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
45808c999fSMiguel Ojeda     pub struct Local {
46808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
47808c999fSMiguel Ojeda         pub let_token: Token![let],
48808c999fSMiguel Ojeda         pub pat: Pat,
49808c999fSMiguel Ojeda         pub init: Option<LocalInit>,
50808c999fSMiguel Ojeda         pub semi_token: Token![;],
51808c999fSMiguel Ojeda     }
52808c999fSMiguel Ojeda }
53808c999fSMiguel Ojeda 
54808c999fSMiguel Ojeda ast_struct! {
55808c999fSMiguel Ojeda     /// The expression assigned in a local `let` binding, including optional
56808c999fSMiguel Ojeda     /// diverging `else` block.
57808c999fSMiguel Ojeda     ///
58808c999fSMiguel Ojeda     /// `LocalInit` represents `= s.parse()?` in `let x: u64 = s.parse()?` and
59808c999fSMiguel Ojeda     /// `= r else { return }` in `let Ok(x) = r else { return }`.
60808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
61808c999fSMiguel Ojeda     pub struct LocalInit {
62808c999fSMiguel Ojeda         pub eq_token: Token![=],
63808c999fSMiguel Ojeda         pub expr: Box<Expr>,
64808c999fSMiguel Ojeda         pub diverge: Option<(Token![else], Box<Expr>)>,
65808c999fSMiguel Ojeda     }
66808c999fSMiguel Ojeda }
67808c999fSMiguel Ojeda 
68808c999fSMiguel Ojeda ast_struct! {
69808c999fSMiguel Ojeda     /// A macro invocation in statement position.
70808c999fSMiguel Ojeda     ///
71808c999fSMiguel Ojeda     /// Syntactically it's ambiguous which other kind of statement this macro
72808c999fSMiguel Ojeda     /// would expand to. It can be any of local variable (`let`), item, or
73808c999fSMiguel Ojeda     /// expression.
74808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
75808c999fSMiguel Ojeda     pub struct StmtMacro {
76808c999fSMiguel Ojeda         pub attrs: Vec<Attribute>,
77808c999fSMiguel Ojeda         pub mac: Macro,
78808c999fSMiguel Ojeda         pub semi_token: Option<Token![;]>,
79808c999fSMiguel Ojeda     }
80808c999fSMiguel Ojeda }
81808c999fSMiguel Ojeda 
82808c999fSMiguel Ojeda #[cfg(feature = "parsing")]
83808c999fSMiguel Ojeda pub(crate) mod parsing {
84808c999fSMiguel Ojeda     use crate::attr::Attribute;
85808c999fSMiguel Ojeda     use crate::classify;
86808c999fSMiguel Ojeda     use crate::error::Result;
87808c999fSMiguel Ojeda     use crate::expr::{Expr, ExprBlock, ExprMacro};
88808c999fSMiguel Ojeda     use crate::ident::Ident;
89808c999fSMiguel Ojeda     use crate::item;
90808c999fSMiguel Ojeda     use crate::mac::{self, Macro};
91808c999fSMiguel Ojeda     use crate::parse::discouraged::Speculative as _;
92808c999fSMiguel Ojeda     use crate::parse::{Parse, ParseStream};
93808c999fSMiguel Ojeda     use crate::pat::{Pat, PatType};
94808c999fSMiguel Ojeda     use crate::path::Path;
95808c999fSMiguel Ojeda     use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro};
96808c999fSMiguel Ojeda     use crate::token;
97808c999fSMiguel Ojeda     use crate::ty::Type;
98808c999fSMiguel Ojeda     use proc_macro2::TokenStream;
99808c999fSMiguel Ojeda 
100808c999fSMiguel Ojeda     struct AllowNoSemi(bool);
101808c999fSMiguel Ojeda 
102808c999fSMiguel Ojeda     impl Block {
103808c999fSMiguel Ojeda         /// Parse the body of a block as zero or more statements, possibly
104808c999fSMiguel Ojeda         /// including one trailing expression.
105808c999fSMiguel Ojeda         ///
106808c999fSMiguel Ojeda         /// # Example
107808c999fSMiguel Ojeda         ///
108808c999fSMiguel Ojeda         /// ```
109808c999fSMiguel Ojeda         /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token};
110808c999fSMiguel Ojeda         /// use syn::parse::{Parse, ParseStream};
111808c999fSMiguel Ojeda         ///
112808c999fSMiguel Ojeda         /// // Parse a function with no generics or parameter list.
113808c999fSMiguel Ojeda         /// //
114808c999fSMiguel Ojeda         /// //     fn playground {
115808c999fSMiguel Ojeda         /// //         let mut x = 1;
116808c999fSMiguel Ojeda         /// //         x += 1;
117808c999fSMiguel Ojeda         /// //         println!("{}", x);
118808c999fSMiguel Ojeda         /// //     }
119808c999fSMiguel Ojeda         /// struct MiniFunction {
120808c999fSMiguel Ojeda         ///     attrs: Vec<Attribute>,
121808c999fSMiguel Ojeda         ///     fn_token: Token![fn],
122808c999fSMiguel Ojeda         ///     name: Ident,
123808c999fSMiguel Ojeda         ///     brace_token: token::Brace,
124808c999fSMiguel Ojeda         ///     stmts: Vec<Stmt>,
125808c999fSMiguel Ojeda         /// }
126808c999fSMiguel Ojeda         ///
127808c999fSMiguel Ojeda         /// impl Parse for MiniFunction {
128808c999fSMiguel Ojeda         ///     fn parse(input: ParseStream) -> Result<Self> {
129808c999fSMiguel Ojeda         ///         let outer_attrs = input.call(Attribute::parse_outer)?;
130808c999fSMiguel Ojeda         ///         let fn_token: Token![fn] = input.parse()?;
131808c999fSMiguel Ojeda         ///         let name: Ident = input.parse()?;
132808c999fSMiguel Ojeda         ///
133808c999fSMiguel Ojeda         ///         let content;
134808c999fSMiguel Ojeda         ///         let brace_token = braced!(content in input);
135808c999fSMiguel Ojeda         ///         let inner_attrs = content.call(Attribute::parse_inner)?;
136808c999fSMiguel Ojeda         ///         let stmts = content.call(Block::parse_within)?;
137808c999fSMiguel Ojeda         ///
138808c999fSMiguel Ojeda         ///         Ok(MiniFunction {
139808c999fSMiguel Ojeda         ///             attrs: {
140808c999fSMiguel Ojeda         ///                 let mut attrs = outer_attrs;
141808c999fSMiguel Ojeda         ///                 attrs.extend(inner_attrs);
142808c999fSMiguel Ojeda         ///                 attrs
143808c999fSMiguel Ojeda         ///             },
144808c999fSMiguel Ojeda         ///             fn_token,
145808c999fSMiguel Ojeda         ///             name,
146808c999fSMiguel Ojeda         ///             brace_token,
147808c999fSMiguel Ojeda         ///             stmts,
148808c999fSMiguel Ojeda         ///         })
149808c999fSMiguel Ojeda         ///     }
150808c999fSMiguel Ojeda         /// }
151808c999fSMiguel Ojeda         /// ```
152808c999fSMiguel Ojeda         #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
parse_within(input: ParseStream) -> Result<Vec<Stmt>>153808c999fSMiguel Ojeda         pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> {
154808c999fSMiguel Ojeda             let mut stmts = Vec::new();
155808c999fSMiguel Ojeda             loop {
156808c999fSMiguel Ojeda                 while let semi @ Some(_) = input.parse()? {
157808c999fSMiguel Ojeda                     stmts.push(Stmt::Expr(Expr::Verbatim(TokenStream::new()), semi));
158808c999fSMiguel Ojeda                 }
159808c999fSMiguel Ojeda                 if input.is_empty() {
160808c999fSMiguel Ojeda                     break;
161808c999fSMiguel Ojeda                 }
162808c999fSMiguel Ojeda                 let stmt = parse_stmt(input, AllowNoSemi(true))?;
163808c999fSMiguel Ojeda                 let requires_semicolon = match &stmt {
164808c999fSMiguel Ojeda                     Stmt::Expr(stmt, None) => classify::requires_semi_to_be_stmt(stmt),
165808c999fSMiguel Ojeda                     Stmt::Macro(stmt) => {
166808c999fSMiguel Ojeda                         stmt.semi_token.is_none() && !stmt.mac.delimiter.is_brace()
167808c999fSMiguel Ojeda                     }
168808c999fSMiguel Ojeda                     Stmt::Local(_) | Stmt::Item(_) | Stmt::Expr(_, Some(_)) => false,
169808c999fSMiguel Ojeda                 };
170808c999fSMiguel Ojeda                 stmts.push(stmt);
171808c999fSMiguel Ojeda                 if input.is_empty() {
172808c999fSMiguel Ojeda                     break;
173808c999fSMiguel Ojeda                 } else if requires_semicolon {
174808c999fSMiguel Ojeda                     return Err(input.error("unexpected token, expected `;`"));
175808c999fSMiguel Ojeda                 }
176808c999fSMiguel Ojeda             }
177808c999fSMiguel Ojeda             Ok(stmts)
178808c999fSMiguel Ojeda         }
179808c999fSMiguel Ojeda     }
180808c999fSMiguel Ojeda 
181808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
182808c999fSMiguel Ojeda     impl Parse for Block {
parse(input: ParseStream) -> Result<Self>183808c999fSMiguel Ojeda         fn parse(input: ParseStream) -> Result<Self> {
184808c999fSMiguel Ojeda             let content;
185808c999fSMiguel Ojeda             Ok(Block {
186808c999fSMiguel Ojeda                 brace_token: braced!(content in input),
187808c999fSMiguel Ojeda                 stmts: content.call(Block::parse_within)?,
188808c999fSMiguel Ojeda             })
189808c999fSMiguel Ojeda         }
190808c999fSMiguel Ojeda     }
191808c999fSMiguel Ojeda 
192808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
193808c999fSMiguel Ojeda     impl Parse for Stmt {
parse(input: ParseStream) -> Result<Self>194808c999fSMiguel Ojeda         fn parse(input: ParseStream) -> Result<Self> {
195808c999fSMiguel Ojeda             let allow_nosemi = AllowNoSemi(false);
196808c999fSMiguel Ojeda             parse_stmt(input, allow_nosemi)
197808c999fSMiguel Ojeda         }
198808c999fSMiguel Ojeda     }
199808c999fSMiguel Ojeda 
parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result<Stmt>200808c999fSMiguel Ojeda     fn parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result<Stmt> {
201808c999fSMiguel Ojeda         let begin = input.fork();
202808c999fSMiguel Ojeda         let attrs = input.call(Attribute::parse_outer)?;
203808c999fSMiguel Ojeda 
204808c999fSMiguel Ojeda         // brace-style macros; paren and bracket macros get parsed as
205808c999fSMiguel Ojeda         // expression statements.
206808c999fSMiguel Ojeda         let ahead = input.fork();
207808c999fSMiguel Ojeda         let mut is_item_macro = false;
208808c999fSMiguel Ojeda         if let Ok(path) = ahead.call(Path::parse_mod_style) {
209808c999fSMiguel Ojeda             if ahead.peek(Token![!]) {
210808c999fSMiguel Ojeda                 if ahead.peek2(Ident) || ahead.peek2(Token![try]) {
211808c999fSMiguel Ojeda                     is_item_macro = true;
212808c999fSMiguel Ojeda                 } else if ahead.peek2(token::Brace)
213808c999fSMiguel Ojeda                     && !(ahead.peek3(Token![.]) && !ahead.peek3(Token![..])
214808c999fSMiguel Ojeda                         || ahead.peek3(Token![?]))
215808c999fSMiguel Ojeda                 {
216808c999fSMiguel Ojeda                     input.advance_to(&ahead);
217808c999fSMiguel Ojeda                     return stmt_mac(input, attrs, path).map(Stmt::Macro);
218808c999fSMiguel Ojeda                 }
219808c999fSMiguel Ojeda             }
220808c999fSMiguel Ojeda         }
221808c999fSMiguel Ojeda 
222808c999fSMiguel Ojeda         if input.peek(Token![let]) && !input.peek(token::Group) {
223808c999fSMiguel Ojeda             stmt_local(input, attrs).map(Stmt::Local)
224808c999fSMiguel Ojeda         } else if input.peek(Token![pub])
225808c999fSMiguel Ojeda             || input.peek(Token![crate]) && !input.peek2(Token![::])
226808c999fSMiguel Ojeda             || input.peek(Token![extern])
227808c999fSMiguel Ojeda             || input.peek(Token![use])
228808c999fSMiguel Ojeda             || input.peek(Token![static])
229808c999fSMiguel Ojeda                 && (input.peek2(Token![mut])
230808c999fSMiguel Ojeda                     || input.peek2(Ident)
231808c999fSMiguel Ojeda                         && !(input.peek2(Token![async])
232808c999fSMiguel Ojeda                             && (input.peek3(Token![move]) || input.peek3(Token![|]))))
233808c999fSMiguel Ojeda             || input.peek(Token![const])
234808c999fSMiguel Ojeda                 && !(input.peek2(token::Brace)
235808c999fSMiguel Ojeda                     || input.peek2(Token![static])
236808c999fSMiguel Ojeda                     || input.peek2(Token![async])
237808c999fSMiguel Ojeda                         && !(input.peek3(Token![unsafe])
238808c999fSMiguel Ojeda                             || input.peek3(Token![extern])
239808c999fSMiguel Ojeda                             || input.peek3(Token![fn]))
240808c999fSMiguel Ojeda                     || input.peek2(Token![move])
241808c999fSMiguel Ojeda                     || input.peek2(Token![|]))
242808c999fSMiguel Ojeda             || input.peek(Token![unsafe]) && !input.peek2(token::Brace)
243808c999fSMiguel Ojeda             || input.peek(Token![async])
244808c999fSMiguel Ojeda                 && (input.peek2(Token![unsafe])
245808c999fSMiguel Ojeda                     || input.peek2(Token![extern])
246808c999fSMiguel Ojeda                     || input.peek2(Token![fn]))
247808c999fSMiguel Ojeda             || input.peek(Token![fn])
248808c999fSMiguel Ojeda             || input.peek(Token![mod])
249808c999fSMiguel Ojeda             || input.peek(Token![type])
250808c999fSMiguel Ojeda             || input.peek(Token![struct])
251808c999fSMiguel Ojeda             || input.peek(Token![enum])
252808c999fSMiguel Ojeda             || input.peek(Token![union]) && input.peek2(Ident)
253808c999fSMiguel Ojeda             || input.peek(Token![auto]) && input.peek2(Token![trait])
254808c999fSMiguel Ojeda             || input.peek(Token![trait])
255808c999fSMiguel Ojeda             || input.peek(Token![default])
256808c999fSMiguel Ojeda                 && (input.peek2(Token![unsafe]) || input.peek2(Token![impl]))
257808c999fSMiguel Ojeda             || input.peek(Token![impl])
258808c999fSMiguel Ojeda             || input.peek(Token![macro])
259808c999fSMiguel Ojeda             || is_item_macro
260808c999fSMiguel Ojeda         {
261808c999fSMiguel Ojeda             let item = item::parsing::parse_rest_of_item(begin, attrs, input)?;
262808c999fSMiguel Ojeda             Ok(Stmt::Item(item))
263808c999fSMiguel Ojeda         } else {
264808c999fSMiguel Ojeda             stmt_expr(input, allow_nosemi, attrs)
265808c999fSMiguel Ojeda         }
266808c999fSMiguel Ojeda     }
267808c999fSMiguel Ojeda 
stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<StmtMacro>268808c999fSMiguel Ojeda     fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<StmtMacro> {
269808c999fSMiguel Ojeda         let bang_token: Token![!] = input.parse()?;
270808c999fSMiguel Ojeda         let (delimiter, tokens) = mac::parse_delimiter(input)?;
271808c999fSMiguel Ojeda         let semi_token: Option<Token![;]> = input.parse()?;
272808c999fSMiguel Ojeda 
273808c999fSMiguel Ojeda         Ok(StmtMacro {
274808c999fSMiguel Ojeda             attrs,
275808c999fSMiguel Ojeda             mac: Macro {
276808c999fSMiguel Ojeda                 path,
277808c999fSMiguel Ojeda                 bang_token,
278808c999fSMiguel Ojeda                 delimiter,
279808c999fSMiguel Ojeda                 tokens,
280808c999fSMiguel Ojeda             },
281808c999fSMiguel Ojeda             semi_token,
282808c999fSMiguel Ojeda         })
283808c999fSMiguel Ojeda     }
284808c999fSMiguel Ojeda 
stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local>285808c999fSMiguel Ojeda     fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> {
286808c999fSMiguel Ojeda         let let_token: Token![let] = input.parse()?;
287808c999fSMiguel Ojeda 
288808c999fSMiguel Ojeda         let mut pat = Pat::parse_single(input)?;
289808c999fSMiguel Ojeda         if input.peek(Token![:]) {
290808c999fSMiguel Ojeda             let colon_token: Token![:] = input.parse()?;
291808c999fSMiguel Ojeda             let ty: Type = input.parse()?;
292808c999fSMiguel Ojeda             pat = Pat::Type(PatType {
293808c999fSMiguel Ojeda                 attrs: Vec::new(),
294808c999fSMiguel Ojeda                 pat: Box::new(pat),
295808c999fSMiguel Ojeda                 colon_token,
296808c999fSMiguel Ojeda                 ty: Box::new(ty),
297808c999fSMiguel Ojeda             });
298808c999fSMiguel Ojeda         }
299808c999fSMiguel Ojeda 
300808c999fSMiguel Ojeda         let init = if let Some(eq_token) = input.parse()? {
301808c999fSMiguel Ojeda             let eq_token: Token![=] = eq_token;
302808c999fSMiguel Ojeda             let expr: Expr = input.parse()?;
303808c999fSMiguel Ojeda 
304808c999fSMiguel Ojeda             let diverge = if !classify::expr_trailing_brace(&expr) && input.peek(Token![else]) {
305808c999fSMiguel Ojeda                 let else_token: Token![else] = input.parse()?;
306808c999fSMiguel Ojeda                 let diverge = ExprBlock {
307808c999fSMiguel Ojeda                     attrs: Vec::new(),
308808c999fSMiguel Ojeda                     label: None,
309808c999fSMiguel Ojeda                     block: input.parse()?,
310808c999fSMiguel Ojeda                 };
311808c999fSMiguel Ojeda                 Some((else_token, Box::new(Expr::Block(diverge))))
312808c999fSMiguel Ojeda             } else {
313808c999fSMiguel Ojeda                 None
314808c999fSMiguel Ojeda             };
315808c999fSMiguel Ojeda 
316808c999fSMiguel Ojeda             Some(LocalInit {
317808c999fSMiguel Ojeda                 eq_token,
318808c999fSMiguel Ojeda                 expr: Box::new(expr),
319808c999fSMiguel Ojeda                 diverge,
320808c999fSMiguel Ojeda             })
321808c999fSMiguel Ojeda         } else {
322808c999fSMiguel Ojeda             None
323808c999fSMiguel Ojeda         };
324808c999fSMiguel Ojeda 
325808c999fSMiguel Ojeda         let semi_token: Token![;] = input.parse()?;
326808c999fSMiguel Ojeda 
327808c999fSMiguel Ojeda         Ok(Local {
328808c999fSMiguel Ojeda             attrs,
329808c999fSMiguel Ojeda             let_token,
330808c999fSMiguel Ojeda             pat,
331808c999fSMiguel Ojeda             init,
332808c999fSMiguel Ojeda             semi_token,
333808c999fSMiguel Ojeda         })
334808c999fSMiguel Ojeda     }
335808c999fSMiguel Ojeda 
stmt_expr( input: ParseStream, allow_nosemi: AllowNoSemi, mut attrs: Vec<Attribute>, ) -> Result<Stmt>336808c999fSMiguel Ojeda     fn stmt_expr(
337808c999fSMiguel Ojeda         input: ParseStream,
338808c999fSMiguel Ojeda         allow_nosemi: AllowNoSemi,
339808c999fSMiguel Ojeda         mut attrs: Vec<Attribute>,
340808c999fSMiguel Ojeda     ) -> Result<Stmt> {
341808c999fSMiguel Ojeda         let mut e = Expr::parse_with_earlier_boundary_rule(input)?;
342808c999fSMiguel Ojeda 
343808c999fSMiguel Ojeda         let mut attr_target = &mut e;
344808c999fSMiguel Ojeda         loop {
345808c999fSMiguel Ojeda             attr_target = match attr_target {
346808c999fSMiguel Ojeda                 Expr::Assign(e) => &mut e.left,
347808c999fSMiguel Ojeda                 Expr::Binary(e) => &mut e.left,
348808c999fSMiguel Ojeda                 Expr::Cast(e) => &mut e.expr,
349808c999fSMiguel Ojeda                 Expr::Array(_)
350808c999fSMiguel Ojeda                 | Expr::Async(_)
351808c999fSMiguel Ojeda                 | Expr::Await(_)
352808c999fSMiguel Ojeda                 | Expr::Block(_)
353808c999fSMiguel Ojeda                 | Expr::Break(_)
354808c999fSMiguel Ojeda                 | Expr::Call(_)
355808c999fSMiguel Ojeda                 | Expr::Closure(_)
356808c999fSMiguel Ojeda                 | Expr::Const(_)
357808c999fSMiguel Ojeda                 | Expr::Continue(_)
358808c999fSMiguel Ojeda                 | Expr::Field(_)
359808c999fSMiguel Ojeda                 | Expr::ForLoop(_)
360808c999fSMiguel Ojeda                 | Expr::Group(_)
361808c999fSMiguel Ojeda                 | Expr::If(_)
362808c999fSMiguel Ojeda                 | Expr::Index(_)
363808c999fSMiguel Ojeda                 | Expr::Infer(_)
364808c999fSMiguel Ojeda                 | Expr::Let(_)
365808c999fSMiguel Ojeda                 | Expr::Lit(_)
366808c999fSMiguel Ojeda                 | Expr::Loop(_)
367808c999fSMiguel Ojeda                 | Expr::Macro(_)
368808c999fSMiguel Ojeda                 | Expr::Match(_)
369808c999fSMiguel Ojeda                 | Expr::MethodCall(_)
370808c999fSMiguel Ojeda                 | Expr::Paren(_)
371808c999fSMiguel Ojeda                 | Expr::Path(_)
372808c999fSMiguel Ojeda                 | Expr::Range(_)
373808c999fSMiguel Ojeda                 | Expr::RawAddr(_)
374808c999fSMiguel Ojeda                 | Expr::Reference(_)
375808c999fSMiguel Ojeda                 | Expr::Repeat(_)
376808c999fSMiguel Ojeda                 | Expr::Return(_)
377808c999fSMiguel Ojeda                 | Expr::Struct(_)
378808c999fSMiguel Ojeda                 | Expr::Try(_)
379808c999fSMiguel Ojeda                 | Expr::TryBlock(_)
380808c999fSMiguel Ojeda                 | Expr::Tuple(_)
381808c999fSMiguel Ojeda                 | Expr::Unary(_)
382808c999fSMiguel Ojeda                 | Expr::Unsafe(_)
383808c999fSMiguel Ojeda                 | Expr::While(_)
384808c999fSMiguel Ojeda                 | Expr::Yield(_)
385808c999fSMiguel Ojeda                 | Expr::Verbatim(_) => break,
386808c999fSMiguel Ojeda             };
387808c999fSMiguel Ojeda         }
388808c999fSMiguel Ojeda         attrs.extend(attr_target.replace_attrs(Vec::new()));
389808c999fSMiguel Ojeda         attr_target.replace_attrs(attrs);
390808c999fSMiguel Ojeda 
391808c999fSMiguel Ojeda         let semi_token: Option<Token![;]> = input.parse()?;
392808c999fSMiguel Ojeda 
393808c999fSMiguel Ojeda         match e {
394808c999fSMiguel Ojeda             Expr::Macro(ExprMacro { attrs, mac })
395808c999fSMiguel Ojeda                 if semi_token.is_some() || mac.delimiter.is_brace() =>
396808c999fSMiguel Ojeda             {
397808c999fSMiguel Ojeda                 return Ok(Stmt::Macro(StmtMacro {
398808c999fSMiguel Ojeda                     attrs,
399808c999fSMiguel Ojeda                     mac,
400808c999fSMiguel Ojeda                     semi_token,
401808c999fSMiguel Ojeda                 }));
402808c999fSMiguel Ojeda             }
403808c999fSMiguel Ojeda             _ => {}
404808c999fSMiguel Ojeda         }
405808c999fSMiguel Ojeda 
406808c999fSMiguel Ojeda         if semi_token.is_some() {
407808c999fSMiguel Ojeda             Ok(Stmt::Expr(e, semi_token))
408808c999fSMiguel Ojeda         } else if allow_nosemi.0 || !classify::requires_semi_to_be_stmt(&e) {
409808c999fSMiguel Ojeda             Ok(Stmt::Expr(e, None))
410808c999fSMiguel Ojeda         } else {
411808c999fSMiguel Ojeda             Err(input.error("expected semicolon"))
412808c999fSMiguel Ojeda         }
413808c999fSMiguel Ojeda     }
414808c999fSMiguel Ojeda }
415808c999fSMiguel Ojeda 
416808c999fSMiguel Ojeda #[cfg(feature = "printing")]
417808c999fSMiguel Ojeda pub(crate) mod printing {
418808c999fSMiguel Ojeda     use crate::classify;
419808c999fSMiguel Ojeda     use crate::expr::{self, Expr};
420808c999fSMiguel Ojeda     use crate::fixup::FixupContext;
421808c999fSMiguel Ojeda     use crate::stmt::{Block, Local, Stmt, StmtMacro};
422808c999fSMiguel Ojeda     use crate::token;
423808c999fSMiguel Ojeda     use proc_macro2::TokenStream;
424808c999fSMiguel Ojeda     use quote::{ToTokens, TokenStreamExt};
425808c999fSMiguel Ojeda 
426808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
427808c999fSMiguel Ojeda     impl ToTokens for Block {
to_tokens(&self, tokens: &mut TokenStream)428808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
429808c999fSMiguel Ojeda             self.brace_token.surround(tokens, |tokens| {
430808c999fSMiguel Ojeda                 tokens.append_all(&self.stmts);
431808c999fSMiguel Ojeda             });
432808c999fSMiguel Ojeda         }
433808c999fSMiguel Ojeda     }
434808c999fSMiguel Ojeda 
435808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
436808c999fSMiguel Ojeda     impl ToTokens for Stmt {
to_tokens(&self, tokens: &mut TokenStream)437808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
438808c999fSMiguel Ojeda             match self {
439808c999fSMiguel Ojeda                 Stmt::Local(local) => local.to_tokens(tokens),
440808c999fSMiguel Ojeda                 Stmt::Item(item) => item.to_tokens(tokens),
441808c999fSMiguel Ojeda                 Stmt::Expr(expr, semi) => {
442808c999fSMiguel Ojeda                     expr::printing::print_expr(expr, tokens, FixupContext::new_stmt());
443808c999fSMiguel Ojeda                     semi.to_tokens(tokens);
444808c999fSMiguel Ojeda                 }
445808c999fSMiguel Ojeda                 Stmt::Macro(mac) => mac.to_tokens(tokens),
446808c999fSMiguel Ojeda             }
447808c999fSMiguel Ojeda         }
448808c999fSMiguel Ojeda     }
449808c999fSMiguel Ojeda 
450808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
451808c999fSMiguel Ojeda     impl ToTokens for Local {
to_tokens(&self, tokens: &mut TokenStream)452808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
453808c999fSMiguel Ojeda             expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
454808c999fSMiguel Ojeda             self.let_token.to_tokens(tokens);
455808c999fSMiguel Ojeda             self.pat.to_tokens(tokens);
456808c999fSMiguel Ojeda             if let Some(init) = &self.init {
457808c999fSMiguel Ojeda                 init.eq_token.to_tokens(tokens);
458808c999fSMiguel Ojeda                 expr::printing::print_subexpression(
459808c999fSMiguel Ojeda                     &init.expr,
460808c999fSMiguel Ojeda                     init.diverge.is_some() && classify::expr_trailing_brace(&init.expr),
461808c999fSMiguel Ojeda                     tokens,
462808c999fSMiguel Ojeda                     FixupContext::NONE,
463808c999fSMiguel Ojeda                 );
464808c999fSMiguel Ojeda                 if let Some((else_token, diverge)) = &init.diverge {
465808c999fSMiguel Ojeda                     else_token.to_tokens(tokens);
466808c999fSMiguel Ojeda                     match &**diverge {
467808c999fSMiguel Ojeda                         Expr::Block(diverge) => diverge.to_tokens(tokens),
468808c999fSMiguel Ojeda                         _ => token::Brace::default().surround(tokens, |tokens| {
469808c999fSMiguel Ojeda                             expr::printing::print_expr(diverge, tokens, FixupContext::new_stmt());
470808c999fSMiguel Ojeda                         }),
471808c999fSMiguel Ojeda                     }
472808c999fSMiguel Ojeda                 }
473808c999fSMiguel Ojeda             }
474808c999fSMiguel Ojeda             self.semi_token.to_tokens(tokens);
475808c999fSMiguel Ojeda         }
476808c999fSMiguel Ojeda     }
477808c999fSMiguel Ojeda 
478808c999fSMiguel Ojeda     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
479808c999fSMiguel Ojeda     impl ToTokens for StmtMacro {
to_tokens(&self, tokens: &mut TokenStream)480808c999fSMiguel Ojeda         fn to_tokens(&self, tokens: &mut TokenStream) {
481808c999fSMiguel Ojeda             expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
482808c999fSMiguel Ojeda             self.mac.to_tokens(tokens);
483808c999fSMiguel Ojeda             self.semi_token.to_tokens(tokens);
484808c999fSMiguel Ojeda         }
485808c999fSMiguel Ojeda     }
486808c999fSMiguel Ojeda }
487