From 56226a59259466078ffadeff1bd10b543df819be Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 24 Jun 2023 21:59:14 -0700 Subject: [PATCH] Preserve attributes on verbatim Item in statement position --- src/item.rs | 262 +++++++++++++++++++++++++++------------------------- src/stmt.rs | 7 +- 2 files changed, 138 insertions(+), 131 deletions(-) diff --git a/src/item.rs b/src/item.rs index 8538868c33..66ab35b5df 100644 --- a/src/item.rs +++ b/src/item.rs @@ -898,96 +898,76 @@ pub(crate) mod parsing { impl Parse for Item { fn parse(input: ParseStream) -> Result { let begin = input.fork(); - let mut attrs = input.call(Attribute::parse_outer)?; - let ahead = input.fork(); - let vis: Visibility = ahead.parse()?; + let attrs = input.call(Attribute::parse_outer)?; + parse_rest_of_item(begin, attrs, input) + } + } + + pub(crate) fn parse_rest_of_item( + begin: ParseBuffer, + mut attrs: Vec, + input: ParseStream, + ) -> Result { + let ahead = input.fork(); + let vis: Visibility = ahead.parse()?; + let lookahead = ahead.lookahead1(); + let mut item = if lookahead.peek(Token![fn]) || peek_signature(&ahead) { + let vis: Visibility = input.parse()?; + let sig: Signature = input.parse()?; + if input.peek(Token![;]) { + input.parse::()?; + Ok(Item::Verbatim(verbatim::between(begin, input))) + } else { + parse_rest_of_fn(input, Vec::new(), vis, sig).map(Item::Fn) + } + } else if lookahead.peek(Token![extern]) { + ahead.parse::()?; let lookahead = ahead.lookahead1(); - let mut item = if lookahead.peek(Token![fn]) || peek_signature(&ahead) { - let vis: Visibility = input.parse()?; - let sig: Signature = input.parse()?; - if input.peek(Token![;]) { - input.parse::()?; - Ok(Item::Verbatim(verbatim::between(begin, input))) - } else { - parse_rest_of_fn(input, Vec::new(), vis, sig).map(Item::Fn) - } - } else if lookahead.peek(Token![extern]) { - ahead.parse::()?; + if lookahead.peek(Token![crate]) { + input.parse().map(Item::ExternCrate) + } else if lookahead.peek(token::Brace) { + input.parse().map(Item::ForeignMod) + } else if lookahead.peek(LitStr) { + ahead.parse::()?; let lookahead = ahead.lookahead1(); - if lookahead.peek(Token![crate]) { - input.parse().map(Item::ExternCrate) - } else if lookahead.peek(token::Brace) { + if lookahead.peek(token::Brace) { input.parse().map(Item::ForeignMod) - } else if lookahead.peek(LitStr) { - ahead.parse::()?; - let lookahead = ahead.lookahead1(); - if lookahead.peek(token::Brace) { - input.parse().map(Item::ForeignMod) - } else { - Err(lookahead.error()) - } } else { Err(lookahead.error()) } - } else if lookahead.peek(Token![use]) { - let allow_crate_root_in_path = true; - match parse_item_use(input, allow_crate_root_in_path)? { - Some(item_use) => Ok(Item::Use(item_use)), - None => Ok(Item::Verbatim(verbatim::between(begin, input))), - } - } else if lookahead.peek(Token![static]) { - let vis = input.parse()?; - let static_token = input.parse()?; - let mutability = input.parse()?; - let ident = input.parse()?; - if input.peek(Token![=]) { - input.parse::()?; - input.parse::()?; - input.parse::()?; - Ok(Item::Verbatim(verbatim::between(begin, input))) - } else { - let colon_token = input.parse()?; - let ty = input.parse()?; - if input.peek(Token![;]) { - input.parse::()?; - Ok(Item::Verbatim(verbatim::between(begin, input))) - } else { - Ok(Item::Static(ItemStatic { - attrs: Vec::new(), - vis, - static_token, - mutability, - ident, - colon_token, - ty, - eq_token: input.parse()?, - expr: input.parse()?, - semi_token: input.parse()?, - })) - } - } - } else if lookahead.peek(Token![const]) { - let vis = input.parse()?; - let const_token: Token![const] = input.parse()?; - let lookahead = input.lookahead1(); - let ident = if lookahead.peek(Ident) || lookahead.peek(Token![_]) { - input.call(Ident::parse_any)? - } else { - return Err(lookahead.error()); - }; + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![use]) { + let allow_crate_root_in_path = true; + match parse_item_use(input, allow_crate_root_in_path)? { + Some(item_use) => Ok(Item::Use(item_use)), + None => Ok(Item::Verbatim(verbatim::between(begin, input))), + } + } else if lookahead.peek(Token![static]) { + let vis = input.parse()?; + let static_token = input.parse()?; + let mutability = input.parse()?; + let ident = input.parse()?; + if input.peek(Token![=]) { + input.parse::()?; + input.parse::()?; + input.parse::()?; + Ok(Item::Verbatim(verbatim::between(begin, input))) + } else { let colon_token = input.parse()?; let ty = input.parse()?; if input.peek(Token![;]) { input.parse::()?; Ok(Item::Verbatim(verbatim::between(begin, input))) } else { - Ok(Item::Const(ItemConst { + Ok(Item::Static(ItemStatic { attrs: Vec::new(), vis, - const_token, + static_token, + mutability, ident, - generics: Generics::default(), colon_token, ty, eq_token: input.parse()?, @@ -995,69 +975,97 @@ pub(crate) mod parsing { semi_token: input.parse()?, })) } - } else if lookahead.peek(Token![unsafe]) { - ahead.parse::()?; - let lookahead = ahead.lookahead1(); - if lookahead.peek(Token![trait]) - || lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) - { - input.parse().map(Item::Trait) - } else if lookahead.peek(Token![impl]) { - let allow_verbatim_impl = true; - if let Some(item) = parse_impl(input, allow_verbatim_impl)? { - Ok(Item::Impl(item)) - } else { - Ok(Item::Verbatim(verbatim::between(begin, input))) - } - } else if lookahead.peek(Token![extern]) { - input.parse().map(Item::ForeignMod) - } else if lookahead.peek(Token![mod]) { - input.parse().map(Item::Mod) - } else { - Err(lookahead.error()) - } - } else if lookahead.peek(Token![mod]) { - input.parse().map(Item::Mod) - } else if lookahead.peek(Token![type]) { - parse_item_type(begin, input) - } else if lookahead.peek(Token![struct]) { - input.parse().map(Item::Struct) - } else if lookahead.peek(Token![enum]) { - input.parse().map(Item::Enum) - } else if lookahead.peek(Token![union]) && ahead.peek2(Ident) { - input.parse().map(Item::Union) - } else if lookahead.peek(Token![trait]) { - input.call(parse_trait_or_trait_alias) - } else if lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) { - input.parse().map(Item::Trait) - } else if lookahead.peek(Token![impl]) - || lookahead.peek(Token![default]) && !ahead.peek2(Token![!]) + } + } else if lookahead.peek(Token![const]) { + let vis = input.parse()?; + let const_token: Token![const] = input.parse()?; + let lookahead = input.lookahead1(); + let ident = if lookahead.peek(Ident) || lookahead.peek(Token![_]) { + input.call(Ident::parse_any)? + } else { + return Err(lookahead.error()); + }; + let colon_token = input.parse()?; + let ty = input.parse()?; + if input.peek(Token![;]) { + input.parse::()?; + Ok(Item::Verbatim(verbatim::between(begin, input))) + } else { + Ok(Item::Const(ItemConst { + attrs: Vec::new(), + vis, + const_token, + ident, + generics: Generics::default(), + colon_token, + ty, + eq_token: input.parse()?, + expr: input.parse()?, + semi_token: input.parse()?, + })) + } + } else if lookahead.peek(Token![unsafe]) { + ahead.parse::()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Token![trait]) + || lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) { + input.parse().map(Item::Trait) + } else if lookahead.peek(Token![impl]) { let allow_verbatim_impl = true; if let Some(item) = parse_impl(input, allow_verbatim_impl)? { Ok(Item::Impl(item)) } else { Ok(Item::Verbatim(verbatim::between(begin, input))) } - } else if lookahead.peek(Token![macro]) { - input.advance_to(&ahead); - parse_macro2(begin, vis, input) - } else if vis.is_inherited() - && (lookahead.peek(Ident) - || lookahead.peek(Token![self]) - || lookahead.peek(Token![super]) - || lookahead.peek(Token![crate]) - || lookahead.peek(Token![::])) - { - input.parse().map(Item::Macro) + } else if lookahead.peek(Token![extern]) { + input.parse().map(Item::ForeignMod) + } else if lookahead.peek(Token![mod]) { + input.parse().map(Item::Mod) } else { Err(lookahead.error()) - }?; + } + } else if lookahead.peek(Token![mod]) { + input.parse().map(Item::Mod) + } else if lookahead.peek(Token![type]) { + parse_item_type(begin, input) + } else if lookahead.peek(Token![struct]) { + input.parse().map(Item::Struct) + } else if lookahead.peek(Token![enum]) { + input.parse().map(Item::Enum) + } else if lookahead.peek(Token![union]) && ahead.peek2(Ident) { + input.parse().map(Item::Union) + } else if lookahead.peek(Token![trait]) { + input.call(parse_trait_or_trait_alias) + } else if lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) { + input.parse().map(Item::Trait) + } else if lookahead.peek(Token![impl]) + || lookahead.peek(Token![default]) && !ahead.peek2(Token![!]) + { + let allow_verbatim_impl = true; + if let Some(item) = parse_impl(input, allow_verbatim_impl)? { + Ok(Item::Impl(item)) + } else { + Ok(Item::Verbatim(verbatim::between(begin, input))) + } + } else if lookahead.peek(Token![macro]) { + input.advance_to(&ahead); + parse_macro2(begin, vis, input) + } else if vis.is_inherited() + && (lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![::])) + { + input.parse().map(Item::Macro) + } else { + Err(lookahead.error()) + }?; - attrs.extend(item.replace_attrs(Vec::new())); - item.replace_attrs(attrs); - Ok(item) - } + attrs.extend(item.replace_attrs(Vec::new())); + item.replace_attrs(attrs); + Ok(item) } struct FlexibleItemType { diff --git a/src/stmt.rs b/src/stmt.rs index b5434f7ce9..fb67feccb2 100644 --- a/src/stmt.rs +++ b/src/stmt.rs @@ -180,7 +180,8 @@ pub(crate) mod parsing { } fn parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result { - let mut attrs = input.call(Attribute::parse_outer)?; + let begin = input.fork(); + let attrs = input.call(Attribute::parse_outer)?; // brace-style macros; paren and bracket macros get parsed as // expression statements. @@ -238,9 +239,7 @@ pub(crate) mod parsing { || input.peek(Token![macro]) || is_item_macro { - let mut item: Item = input.parse()?; - attrs.extend(item.replace_attrs(Vec::new())); - item.replace_attrs(attrs); + let item = item::parsing::parse_rest_of_item(begin, attrs, input)?; Ok(Stmt::Item(item)) } else { stmt_expr(input, allow_nosemi, attrs)