1 use std
::panic
::{catch_unwind, AssertUnwindSafe}
;
4 use rustc_ast
::token
::{DelimToken, TokenKind}
;
5 use rustc_parse
::parser
::ForceCollect
;
6 use rustc_span
::symbol
::kw
;
8 use crate::parse
::macros
::build_stream_parser
;
9 use crate::parse
::session
::ParseSess
;
11 pub(crate) fn parse_cfg_if
<'a
>(
13 mac
: &'a ast
::MacCall
,
14 ) -> Result
<Vec
<ast
::Item
>, &'
static str> {
15 match catch_unwind(AssertUnwindSafe(|| parse_cfg_if_inner(sess
, mac
))) {
16 Ok(Ok(items
)) => Ok(items
),
17 Ok(err @
Err(_
)) => err
,
18 Err(..) => Err("failed to parse cfg_if!"),
22 fn parse_cfg_if_inner
<'a
>(
24 mac
: &'a ast
::MacCall
,
25 ) -> Result
<Vec
<ast
::Item
>, &'
static str> {
26 let ts
= mac
.args
.inner_tokens();
27 let mut parser
= build_stream_parser(sess
.inner(), ts
);
29 let mut items
= vec
![];
30 let mut process_if_cfg
= true;
32 while parser
.token
.kind
!= TokenKind
::Eof
{
34 if !parser
.eat_keyword(kw
::If
) {
35 return Err("Expected `if`");
37 // Inner attributes are not actually syntactically permitted here, but we don't
38 // care about inner vs outer attributes in this position. Our purpose with this
39 // special case parsing of cfg_if macros is to ensure we can correctly resolve
40 // imported modules that may have a custom `path` defined.
42 // As such, we just need to advance the parser past the attribute and up to
43 // to the opening brace.
44 // See also https://github.com/rust-lang/rust/pull/79433
46 .parse_attribute(rustc_parse
::parser
::attr
::InnerAttrPolicy
::Permitted
)
47 .map_err(|_
| "Failed to parse attributes")?
;
50 if !parser
.eat(&TokenKind
::OpenDelim(DelimToken
::Brace
)) {
51 return Err("Expected an opening brace");
54 while parser
.token
!= TokenKind
::CloseDelim(DelimToken
::Brace
)
55 && parser
.token
.kind
!= TokenKind
::Eof
57 let item
= match parser
.parse_item(ForceCollect
::No
) {
58 Ok(Some(item_ptr
)) => item_ptr
.into_inner(),
62 parser
.sess
.span_diagnostic
.reset_err_count();
64 "Expected item inside cfg_if block, but failed to parse it as an item",
68 if let ast
::ItemKind
::Mod(..) = item
.kind
{
73 if !parser
.eat(&TokenKind
::CloseDelim(DelimToken
::Brace
)) {
74 return Err("Expected a closing brace");
77 if parser
.eat(&TokenKind
::Eof
) {
81 if !parser
.eat_keyword(kw
::Else
) {
82 return Err("Expected `else`");
85 process_if_cfg
= parser
.token
.is_keyword(kw
::If
);