rustfmt_nightly/parse/macros/
cfg_if.rs1use std::panic::{AssertUnwindSafe, catch_unwind};
2
3use rustc_ast::ast;
4use rustc_ast::token::TokenKind;
5use rustc_parse::exp;
6use rustc_parse::parser::ForceCollect;
7use rustc_span::symbol::kw;
8
9use crate::parse::macros::build_stream_parser;
10use crate::parse::session::ParseSess;
11
12pub(crate) fn parse_cfg_if<'a>(
13 psess: &'a ParseSess,
14 mac: &'a ast::MacCall,
15) -> Result<Vec<ast::Item>, &'static str> {
16 match catch_unwind(AssertUnwindSafe(|| parse_cfg_if_inner(psess, mac))) {
17 Ok(Ok(items)) => Ok(items),
18 Ok(err @ Err(_)) => err,
19 Err(..) => Err("failed to parse cfg_if!"),
20 }
21}
22
23fn parse_cfg_if_inner<'a>(
24 psess: &'a ParseSess,
25 mac: &'a ast::MacCall,
26) -> Result<Vec<ast::Item>, &'static str> {
27 let ts = mac.args.tokens.clone();
28 let mut parser = build_stream_parser(psess.inner(), ts);
29
30 let mut items = vec![];
31 let mut process_if_cfg = true;
32
33 while parser.token.kind != TokenKind::Eof {
34 if process_if_cfg {
35 if !parser.eat_keyword(exp!(If)) {
36 return Err("Expected `if`");
37 }
38
39 if !matches!(parser.token.kind, TokenKind::Pound) {
40 return Err("Failed to parse attributes");
41 }
42
43 parser
52 .parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted)
53 .map_err(|e| {
54 e.cancel();
55 "Failed to parse attributes"
56 })?;
57 }
58
59 if !parser.eat(exp!(OpenBrace)) {
60 return Err("Expected an opening brace");
61 }
62
63 while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof {
64 let item = match parser.parse_item(ForceCollect::No) {
65 Ok(Some(item_ptr)) => item_ptr.into_inner(),
66 Ok(None) => continue,
67 Err(err) => {
68 err.cancel();
69 parser.psess.dcx().reset_err_count();
70 return Err(
71 "Expected item inside cfg_if block, but failed to parse it as an item",
72 );
73 }
74 };
75 if let ast::ItemKind::Mod(..) = item.kind {
76 items.push(item);
77 }
78 }
79
80 if !parser.eat(exp!(CloseBrace)) {
81 return Err("Expected a closing brace");
82 }
83
84 if parser.eat(exp!(Eof)) {
85 break;
86 }
87
88 if !parser.eat_keyword(exp!(Else)) {
89 return Err("Expected `else`");
90 }
91
92 process_if_cfg = parser.token.is_keyword(kw::If);
93 }
94
95 Ok(items)
96}