Skip to main content

rustc_parse/parser/
cfg_select.rs

1use rustc_ast::tokenstream::{TokenStream, TokenTree};
2use rustc_ast::util::classify;
3use rustc_ast::{AttrKind, token};
4use rustc_errors::PResult;
5use rustc_span::Span;
6
7use crate::exp;
8use crate::parser::{AttrWrapper, ForceCollect, Parser, Restrictions, Trailing, UsePreAttrPos};
9
10#[derive(#[automatically_derived]
impl ::core::default::Default for CfgSelectBranchAttrSpans {
    #[inline]
    fn default() -> CfgSelectBranchAttrSpans {
        CfgSelectBranchAttrSpans {
            attrs: ::core::default::Default::default(),
            doc_comments: ::core::default::Default::default(),
        }
    }
}Default)]
11pub struct CfgSelectBranchAttrSpans {
12    pub attrs: Vec<Span>,
13    pub doc_comments: Vec<Span>,
14}
15
16impl<'a> Parser<'a> {
17    /// Parses a `TokenTree` consisting either of `{ /* ... */ }` optionally followed by a comma
18    /// (and strip the braces and the optional comma) or an expression followed by a comma
19    /// (and strip the comma).
20    pub fn parse_delimited_token_tree(&mut self) -> PResult<'a, TokenStream> {
21        if self.token == token::OpenBrace {
22            // Strip the outer '{' and '}'.
23            match self.parse_token_tree() {
24                TokenTree::Token(..) => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("because the current token is a \'{{\'")));
}unreachable!("because the current token is a '{{'"),
25                TokenTree::Delimited(.., tts) => {
26                    // Optionally end with a comma.
27                    let _ = self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
28                    return Ok(tts);
29                }
30            }
31        }
32        let expr = self.collect_tokens(None, AttrWrapper::empty(), ForceCollect::Yes, |p, _| {
33            p.parse_expr_res(Restrictions::STMT_EXPR, AttrWrapper::empty())
34                .map(|(expr, _)| (expr, Trailing::No, UsePreAttrPos::No))
35        })?;
36        if !classify::expr_is_complete(&expr)
37            && self.token != token::CloseBrace
38            && self.token != token::Eof
39        {
40            self.expect(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
41        } else {
42            let _ = self.eat(crate::parser::token_type::ExpTokenPair {
    tok: rustc_ast::token::Comma,
    token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
43        }
44        Ok(TokenStream::from_ast(&expr))
45    }
46
47    /// Parses outer attributes before a `cfg_select!` branch for recovery.
48    pub fn parse_cfg_select_branch_outer_attrs(
49        &mut self,
50    ) -> PResult<'a, Option<CfgSelectBranchAttrSpans>> {
51        let attrs = self.parse_outer_attributes()?;
52        if attrs.is_empty() {
53            return Ok(None);
54        }
55
56        let mut spans = CfgSelectBranchAttrSpans::default();
57        for attr in attrs.take_for_recovery(self.psess) {
58            match attr.kind {
59                AttrKind::Normal(..) => spans.attrs.push(attr.span),
60                // `parse_outer_attributes` already emitted E0753 for inner doc comments before
61                // recovering them as outer doc-comment attributes.
62                AttrKind::DocComment(comment_kind, _)
63                    if self.span_to_snippet(attr.span).ok().is_some_and(
64                        |snippet| match comment_kind {
65                            token::CommentKind::Line => snippet.starts_with("//!"),
66                            token::CommentKind::Block => snippet.starts_with("/*!"),
67                        },
68                    ) => {}
69                AttrKind::DocComment(..) => spans.doc_comments.push(attr.span),
70            }
71        }
72
73        Ok(Some(spans))
74    }
75}