diff options
| author | Jon Gjengset <jon@thesquareplanet.com> | 2019-11-02 11:12:42 -0400 |
|---|---|---|
| committer | Jon Gjengset <jon@thesquareplanet.com> | 2019-11-02 11:12:42 -0400 |
| commit | 31fc42b7f778accb21db8daaf0f0e725948c9d6d (patch) | |
| tree | 85ddf145a04d381abae1b01906206e83b3813fd9 /src/libsyntax/parse/parser.rs | |
| parent | 8990f7d627525db934831cc29d5805172d80e156 (diff) | |
| parent | f39205b5d9825fcf35989b5a04d115d411175d18 (diff) | |
| download | rust-31fc42b7f778accb21db8daaf0f0e725948c9d6d.tar.gz rust-31fc42b7f778accb21db8daaf0f0e725948c9d6d.zip | |
Merge branch 'master' into format-temporaries
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 684 |
1 files changed, 187 insertions, 497 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cc582819b6b..6ead1ce811d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1,28 +1,28 @@ +pub mod attr; mod expr; mod pat; mod item; -pub use item::AliasKind; mod module; -pub use module::{ModulePath, ModulePathSuccess}; mod ty; mod path; pub use path::PathStyle; mod stmt; mod generics; +mod diagnostics; +use diagnostics::Error; use crate::ast::{ - self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, FnDecl, Ident, - IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility, - VisibilityKind, Unsafety, + self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, + IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, }; -use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep, literal, token}; -use crate::parse::diagnostics::{Error, dummy_arg}; +use crate::parse::{PResult, Directory, DirectoryOwnership}; use crate::parse::lexer::UnmatchedBrace; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; -use crate::parse::token::{Token, TokenKind, DelimToken}; +use crate::parse::token::{self, Token, TokenKind, DelimToken}; use crate::print::pprust; use crate::ptr::P; -use crate::source_map::{self, respan}; +use crate::sess::ParseSess; +use crate::source_map::respan; use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; use crate::ThinVec; @@ -44,14 +44,14 @@ bitflags::bitflags! { } #[derive(Clone, Copy, PartialEq, Debug)] -crate enum SemiColonMode { +enum SemiColonMode { Break, Ignore, Comma, } #[derive(Clone, Copy, PartialEq, Debug)] -crate enum BlockMode { +enum BlockMode { Break, Ignore, } @@ -86,13 +86,6 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath { } } -fn maybe_append(mut lhs: Vec<Attribute>, mut rhs: Option<Vec<Attribute>>) -> Vec<Attribute> { - if let Some(ref mut rhs) = rhs { - lhs.append(rhs); - } - lhs -} - #[derive(Debug, Clone, Copy, PartialEq)] enum PrevTokenKind { DocComment, @@ -124,33 +117,33 @@ pub struct Parser<'a> { prev_token_kind: PrevTokenKind, restrictions: Restrictions, /// Used to determine the path to externally loaded source files. - crate directory: Directory<'a>, + pub(super) directory: Directory<'a>, /// `true` to parse sub-modules in other files. - pub recurse_into_file_modules: bool, + pub(super) recurse_into_file_modules: bool, /// Name of the root module this parser originated from. If `None`, then the /// name is not known. This does not change while the parser is descending /// into modules, and sub-parsers have new values for this name. pub root_module_name: Option<String>, - crate expected_tokens: Vec<TokenType>, + expected_tokens: Vec<TokenType>, token_cursor: TokenCursor, desugar_doc_comments: bool, /// `true` we should configure out of line modules as we parse. - pub cfg_mods: bool, + cfg_mods: bool, /// This field is used to keep track of how many left angle brackets we have seen. This is /// required in order to detect extra leading left angle brackets (`<` characters) and error /// appropriately. /// /// See the comments in the `parse_path_segment` function for more details. - crate unmatched_angle_bracket_count: u32, - crate max_angle_bracket_count: u32, + unmatched_angle_bracket_count: u32, + max_angle_bracket_count: u32, /// A list of all unclosed delimiters found by the lexer. If an entry is used for error recovery /// it gets removed from here. Every entry left at the end gets emitted as an independent /// error. - crate unclosed_delims: Vec<UnmatchedBrace>, - crate last_unexpected_token_span: Option<Span>, - crate last_type_ascription: Option<(Span, bool /* likely path typo */)>, + pub(super) unclosed_delims: Vec<UnmatchedBrace>, + last_unexpected_token_span: Option<Span>, + pub last_type_ascription: Option<(Span, bool /* likely path typo */)>, /// If present, this `Parser` is not parsing Rust code but rather a macro call. - crate subparser_name: Option<&'static str>, + subparser_name: Option<&'static str>, } impl<'a> Drop for Parser<'a> { @@ -194,7 +187,7 @@ struct TokenCursorFrame { /// You can find some more example usage of this in the `collect_tokens` method /// on the parser. #[derive(Clone)] -crate enum LastToken { +enum LastToken { Collecting(Vec<TreeAndJoint>), Was(Option<TreeAndJoint>), } @@ -285,10 +278,10 @@ impl TokenCursor { token::NoDelim, &if doc_comment_style(&name.as_str()) == AttrStyle::Inner { [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body] - .iter().cloned().collect::<TokenStream>().into() + .iter().cloned().collect::<TokenStream>() } else { [TokenTree::token(token::Pound, sp), body] - .iter().cloned().collect::<TokenStream>().into() + .iter().cloned().collect::<TokenStream>() }, ))); @@ -297,7 +290,7 @@ impl TokenCursor { } #[derive(Clone, PartialEq)] -crate enum TokenType { +enum TokenType { Token(TokenKind), Keyword(Symbol), Operator, @@ -309,7 +302,7 @@ crate enum TokenType { } impl TokenType { - crate fn to_string(&self) -> String { + fn to_string(&self) -> String { match *self { TokenType::Token(ref t) => format!("`{}`", pprust::token_kind_to_string(t)), TokenType::Keyword(kw) => format!("`{}`", kw), @@ -324,11 +317,35 @@ impl TokenType { } #[derive(Copy, Clone, Debug)] -crate enum TokenExpectType { +enum TokenExpectType { Expect, NoExpect, } +/// A sequence separator. +struct SeqSep { + /// The separator token. + sep: Option<TokenKind>, + /// `true` if a trailing separator is allowed. + trailing_sep_allowed: bool, +} + +impl SeqSep { + fn trailing_allowed(t: TokenKind) -> SeqSep { + SeqSep { + sep: Some(t), + trailing_sep_allowed: true, + } + } + + fn none() -> SeqSep { + SeqSep { + sep: None, + trailing_sep_allowed: false, + } + } +} + impl<'a> Parser<'a> { pub fn new( sess: &'a ParseSess, @@ -405,7 +422,7 @@ impl<'a> Parser<'a> { pprust::token_to_string(&self.token) } - crate fn token_descr(&self) -> Option<&'static str> { + fn token_descr(&self) -> Option<&'static str> { Some(match &self.token.kind { _ if self.token.is_special_ident() => "reserved identifier", _ if self.token.is_used_keyword() => "keyword", @@ -415,7 +432,7 @@ impl<'a> Parser<'a> { }) } - crate fn this_token_descr(&self) -> String { + pub(super) fn this_token_descr(&self) -> String { if let Some(prefix) = self.token_descr() { format!("{} `{}`", prefix, self.this_token_to_string()) } else { @@ -465,7 +482,7 @@ impl<'a> Parser<'a> { } } - pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { + fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { self.parse_ident_common(true) } @@ -498,7 +515,7 @@ impl<'a> Parser<'a> { /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not /// encountered. - crate fn check(&mut self, tok: &TokenKind) -> bool { + fn check(&mut self, tok: &TokenKind) -> bool { let is_present = self.token == *tok; if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); } is_present @@ -511,14 +528,16 @@ impl<'a> Parser<'a> { is_present } + /// If the next token is the given keyword, returns `true` without eating it. + /// An expectation is also added for diagnostics purposes. fn check_keyword(&mut self, kw: Symbol) -> bool { self.expected_tokens.push(TokenType::Keyword(kw)); self.token.is_keyword(kw) } - /// If the next token is the given keyword, eats it and returns - /// `true`. Otherwise, returns `false`. - pub fn eat_keyword(&mut self, kw: Symbol) -> bool { + /// If the next token is the given keyword, eats it and returns `true`. + /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. + fn eat_keyword(&mut self, kw: Symbol) -> bool { if self.check_keyword(kw) { self.bump(); true @@ -547,40 +566,38 @@ impl<'a> Parser<'a> { } } - crate fn check_ident(&mut self) -> bool { - if self.token.is_ident() { + fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool { + if ok { true } else { - self.expected_tokens.push(TokenType::Ident); + self.expected_tokens.push(typ); false } } + fn check_ident(&mut self) -> bool { + self.check_or_expected(self.token.is_ident(), TokenType::Ident) + } + fn check_path(&mut self) -> bool { - if self.token.is_path_start() { - true - } else { - self.expected_tokens.push(TokenType::Path); - false - } + self.check_or_expected(self.token.is_path_start(), TokenType::Path) } fn check_type(&mut self) -> bool { - if self.token.can_begin_type() { - true - } else { - self.expected_tokens.push(TokenType::Type); - false - } + self.check_or_expected(self.token.can_begin_type(), TokenType::Type) } fn check_const_arg(&mut self) -> bool { - if self.token.can_begin_const_arg() { - true - } else { - self.expected_tokens.push(TokenType::Const); - false - } + self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) + } + + /// Checks to see if the next token is either `+` or `+=`. + /// Otherwise returns `false`. + fn check_plus(&mut self) -> bool { + self.check_or_expected( + self.token.is_like_plus(), + TokenType::Token(token::BinOp(token::Plus)), + ) } /// Expects and consumes a `+`. if `+=` is seen, replaces it with a `=` @@ -604,18 +621,6 @@ impl<'a> Parser<'a> { } } - /// Checks to see if the next token is either `+` or `+=`. - /// Otherwise returns `false`. - fn check_plus(&mut self) -> bool { - if self.token.is_like_plus() { - true - } - else { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); - false - } - } - /// Expects and consumes an `&`. If `&&` is seen, replaces it with a single /// `&` and continues. If an `&` is not seen, signals an error. fn expect_and(&mut self) -> PResult<'a, ()> { @@ -650,10 +655,6 @@ impl<'a> Parser<'a> { } } - fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) { - literal::expect_no_suffix(&self.sess.span_diagnostic, sp, kind, suffix) - } - /// Attempts to consume a `<`. If `<<` is seen, replaces it with a single /// `<` and continue. If `<-` is seen, replaces it with a single `<` /// and continue. If a `<` is not seen, returns false. @@ -739,7 +740,7 @@ impl<'a> Parser<'a> { /// Parses a sequence, including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. - pub fn parse_seq_to_end<T>( + fn parse_seq_to_end<T>( &mut self, ket: &TokenKind, sep: SeqSep, @@ -755,7 +756,7 @@ impl<'a> Parser<'a> { /// Parses a sequence, not including the closing delimiter. The function /// `f` must consume tokens until reaching the next separator or /// closing bracket. - pub fn parse_seq_to_before_end<T>( + fn parse_seq_to_before_end<T>( &mut self, ket: &TokenKind, sep: SeqSep, @@ -773,7 +774,7 @@ impl<'a> Parser<'a> { }) } - crate fn parse_seq_to_before_tokens<T>( + fn parse_seq_to_before_tokens<T>( &mut self, kets: &[&TokenKind], sep: SeqSep, @@ -910,15 +911,15 @@ impl<'a> Parser<'a> { self.expected_tokens.clear(); } - pub fn look_ahead<R, F>(&self, dist: usize, f: F) -> R where - F: FnOnce(&Token) -> R, - { + /// Look-ahead `dist` tokens of `self.token` and get access to that token there. + /// When `dist == 0` then the current token is looked at. + pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R { if dist == 0 { - return f(&self.token); + return looker(&self.token); } let frame = &self.token_cursor.frame; - f(&match frame.tree_cursor.look_ahead(dist - 1) { + looker(&match frame.tree_cursor.look_ahead(dist - 1) { Some(tree) => match tree { TokenTree::Token(token) => token, TokenTree::Delimited(dspan, delim, _) => @@ -954,102 +955,6 @@ impl<'a> Parser<'a> { } } - fn is_named_argument(&self) -> bool { - let offset = match self.token.kind { - token::Interpolated(ref nt) => match **nt { - token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), - _ => 0, - } - token::BinOp(token::And) | token::AndAnd => 1, - _ if self.token.is_keyword(kw::Mut) => 1, - _ => 0, - }; - - self.look_ahead(offset, |t| t.is_ident()) && - self.look_ahead(offset + 1, |t| t == &token::Colon) - } - - /// Skips unexpected attributes and doc comments in this position and emits an appropriate - /// error. - /// This version of parse param doesn't necessarily require identifier names. - fn parse_param_general( - &mut self, - is_trait_item: bool, - allow_c_variadic: bool, - is_name_required: impl Fn(&token::Token) -> bool, - ) -> PResult<'a, Param> { - let lo = self.token.span; - let attrs = self.parse_outer_attributes()?; - if let Some(mut param) = self.parse_self_param()? { - param.attrs = attrs.into(); - return self.recover_bad_self_param(param, is_trait_item); - } - - let is_name_required = is_name_required(&self.token); - let (pat, ty) = if is_name_required || self.is_named_argument() { - debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); - - let pat = self.parse_fn_param_pat()?; - if let Err(mut err) = self.expect(&token::Colon) { - if let Some(ident) = self.parameter_without_type( - &mut err, - pat, - is_name_required, - is_trait_item, - ) { - err.emit(); - return Ok(dummy_arg(ident)); - } else { - return Err(err); - } - } - - self.eat_incorrect_doc_comment_for_param_type(); - (pat, self.parse_ty_common(true, true, allow_c_variadic)?) - } else { - debug!("parse_param_general ident_to_pat"); - let parser_snapshot_before_ty = self.clone(); - self.eat_incorrect_doc_comment_for_param_type(); - let mut ty = self.parse_ty_common(true, true, allow_c_variadic); - if ty.is_ok() && self.token != token::Comma && - self.token != token::CloseDelim(token::Paren) { - // This wasn't actually a type, but a pattern looking like a type, - // so we are going to rollback and re-parse for recovery. - ty = self.unexpected(); - } - match ty { - Ok(ty) => { - let ident = Ident::new(kw::Invalid, self.prev_span); - let bm = BindingMode::ByValue(Mutability::Immutable); - let pat = self.mk_pat_ident(ty.span, bm, ident); - (pat, ty) - } - Err(mut err) => { - // If this is a C-variadic argument and we hit an error, return the - // error. - if self.token == token::DotDotDot { - return Err(err); - } - // Recover from attempting to parse the argument as a type without pattern. - err.cancel(); - mem::replace(self, parser_snapshot_before_ty); - self.recover_arg_parse()? - } - } - }; - - let span = lo.to(self.token.span); - - Ok(Param { - attrs: attrs.into(), - id: ast::DUMMY_NODE_ID, - is_placeholder: false, - pat, - span, - ty, - }) - } - /// Parses mutability (`mut` or nothing). fn parse_mutability(&mut self) -> Mutability { if self.eat_keyword(kw::Mut) { @@ -1059,6 +964,17 @@ impl<'a> Parser<'a> { } } + /// Possibly parses mutability (`const` or `mut`). + fn parse_const_or_mut(&mut self) -> Option<Mutability> { + if self.eat_keyword(kw::Mut) { + Some(Mutability::Mutable) + } else if self.eat_keyword(kw::Const) { + Some(Mutability::Immutable) + } else { + None + } + } + fn parse_field_name(&mut self) -> PResult<'a, Ident> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind { @@ -1093,9 +1009,10 @@ impl<'a> Parser<'a> { Ok((delim, tts.into())) } - fn parse_or_use_outer_attributes(&mut self, - already_parsed_attrs: Option<ThinVec<Attribute>>) - -> PResult<'a, ThinVec<Attribute>> { + fn parse_or_use_outer_attributes( + &mut self, + already_parsed_attrs: Option<ThinVec<Attribute>>, + ) -> PResult<'a, ThinVec<Attribute>> { if let Some(attrs) = already_parsed_attrs { Ok(attrs) } else { @@ -1103,7 +1020,7 @@ impl<'a> Parser<'a> { } } - crate fn process_potential_macro_variable(&mut self) { + pub fn process_potential_macro_variable(&mut self) { self.token = match self.token.kind { token::Dollar if self.token.span.from_expansion() && self.look_ahead(1, |t| t.is_ident()) => { @@ -1137,7 +1054,7 @@ impl<'a> Parser<'a> { } /// Parses a single token tree from the input. - crate fn parse_token_tree(&mut self) -> TokenTree { + pub fn parse_token_tree(&mut self) -> TokenTree { match self.token.kind { token::OpenDelim(..) => { let frame = mem::replace(&mut self.token_cursor.frame, @@ -1182,240 +1099,12 @@ impl<'a> Parser<'a> { /// Evaluates the closure with restrictions in place. /// /// Afters the closure is evaluated, restrictions are reset. - fn with_res<F, T>(&mut self, r: Restrictions, f: F) -> T - where F: FnOnce(&mut Self) -> T - { + fn with_res<T>(&mut self, res: Restrictions, f: impl FnOnce(&mut Self) -> T) -> T { let old = self.restrictions; - self.restrictions = r; - let r = f(self); + self.restrictions = res; + let res = f(self); self.restrictions = old; - return r; - - } - - fn parse_fn_params(&mut self, named_params: bool, allow_c_variadic: bool) - -> PResult<'a, (Vec<Param> , bool)> { - let sp = self.token.span; - let mut c_variadic = false; - let (params, _): (Vec<Option<Param>>, _) = self.parse_paren_comma_seq(|p| { - let do_not_enforce_named_arguments_for_c_variadic = - |token: &token::Token| -> bool { - if token == &token::DotDotDot { - false - } else { - named_params - } - }; - match p.parse_param_general( - false, - allow_c_variadic, - do_not_enforce_named_arguments_for_c_variadic - ) { - Ok(param) => { - if let TyKind::CVarArgs = param.ty.kind { - c_variadic = true; - if p.token != token::CloseDelim(token::Paren) { - let span = p.token.span; - p.span_err(span, - "`...` must be the last argument of a C-variadic function"); - Ok(None) - } else { - Ok(Some(param)) - } - } else { - Ok(Some(param)) - } - }, - Err(mut e) => { - e.emit(); - let lo = p.prev_span; - // Skip every token until next possible arg or end. - p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); - // Create a placeholder argument for proper arg count (issue #34264). - let span = lo.to(p.prev_span); - Ok(Some(dummy_arg(Ident::new(kw::Invalid, span)))) - } - } - })?; - - let params: Vec<_> = params.into_iter().filter_map(|x| x).collect(); - - if c_variadic && params.len() <= 1 { - self.span_err(sp, - "C-variadic function must be declared with at least one named argument"); - } - - Ok((params, c_variadic)) - } - - /// Returns the parsed optional self parameter and whether a self shortcut was used. - /// - /// See `parse_self_param_with_attrs` to collect attributes. - fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> { - let expect_ident = |this: &mut Self| match this.token.kind { - // Preserve hygienic context. - token::Ident(name, _) => - { let span = this.token.span; this.bump(); Ident::new(name, span) } - _ => unreachable!() - }; - let isolated_self = |this: &mut Self, n| { - this.look_ahead(n, |t| t.is_keyword(kw::SelfLower)) && - this.look_ahead(n + 1, |t| t != &token::ModSep) - }; - - // Parse optional `self` parameter of a method. - // Only a limited set of initial token sequences is considered `self` parameters; anything - // else is parsed as a normal function parameter list, so some lookahead is required. - let eself_lo = self.token.span; - let (eself, eself_ident, eself_hi) = match self.token.kind { - token::BinOp(token::And) => { - // `&self` - // `&mut self` - // `&'lt self` - // `&'lt mut self` - // `¬_self` - (if isolated_self(self, 1) { - self.bump(); - SelfKind::Region(None, Mutability::Immutable) - } else if self.is_keyword_ahead(1, &[kw::Mut]) && - isolated_self(self, 2) { - self.bump(); - self.bump(); - SelfKind::Region(None, Mutability::Mutable) - } else if self.look_ahead(1, |t| t.is_lifetime()) && - isolated_self(self, 2) { - self.bump(); - let lt = self.expect_lifetime(); - SelfKind::Region(Some(lt), Mutability::Immutable) - } else if self.look_ahead(1, |t| t.is_lifetime()) && - self.is_keyword_ahead(2, &[kw::Mut]) && - isolated_self(self, 3) { - self.bump(); - let lt = self.expect_lifetime(); - self.bump(); - SelfKind::Region(Some(lt), Mutability::Mutable) - } else { - return Ok(None); - }, expect_ident(self), self.prev_span) - } - token::BinOp(token::Star) => { - // `*self` - // `*const self` - // `*mut self` - // `*not_self` - // Emit special error for `self` cases. - let msg = "cannot pass `self` by raw pointer"; - (if isolated_self(self, 1) { - self.bump(); - self.struct_span_err(self.token.span, msg) - .span_label(self.token.span, msg) - .emit(); - SelfKind::Value(Mutability::Immutable) - } else if self.look_ahead(1, |t| t.is_mutability()) && - isolated_self(self, 2) { - self.bump(); - self.bump(); - self.struct_span_err(self.token.span, msg) - .span_label(self.token.span, msg) - .emit(); - SelfKind::Value(Mutability::Immutable) - } else { - return Ok(None); - }, expect_ident(self), self.prev_span) - } - token::Ident(..) => { - if isolated_self(self, 0) { - // `self` - // `self: TYPE` - let eself_ident = expect_ident(self); - let eself_hi = self.prev_span; - (if self.eat(&token::Colon) { - let ty = self.parse_ty()?; - SelfKind::Explicit(ty, Mutability::Immutable) - } else { - SelfKind::Value(Mutability::Immutable) - }, eself_ident, eself_hi) - } else if self.token.is_keyword(kw::Mut) && - isolated_self(self, 1) { - // `mut self` - // `mut self: TYPE` - self.bump(); - let eself_ident = expect_ident(self); - let eself_hi = self.prev_span; - (if self.eat(&token::Colon) { - let ty = self.parse_ty()?; - SelfKind::Explicit(ty, Mutability::Mutable) - } else { - SelfKind::Value(Mutability::Mutable) - }, eself_ident, eself_hi) - } else { - return Ok(None); - } - } - _ => return Ok(None), - }; - - let eself = source_map::respan(eself_lo.to(eself_hi), eself); - Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident))) - } - - /// Returns the parsed optional self parameter with attributes and whether a self - /// shortcut was used. - fn parse_self_parameter_with_attrs(&mut self) -> PResult<'a, Option<Param>> { - let attrs = self.parse_outer_attributes()?; - let param_opt = self.parse_self_param()?; - Ok(param_opt.map(|mut param| { - param.attrs = attrs.into(); - param - })) - } - - /// Parses the parameter list and result type of a function that may have a `self` parameter. - fn parse_fn_decl_with_self<F>(&mut self, parse_param_fn: F) -> PResult<'a, P<FnDecl>> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, Param>, - { - self.expect(&token::OpenDelim(token::Paren))?; - - // Parse optional self argument. - let self_param = self.parse_self_parameter_with_attrs()?; - - // Parse the rest of the function parameter list. - let sep = SeqSep::trailing_allowed(token::Comma); - let (mut fn_inputs, recovered) = if let Some(self_param) = self_param { - if self.check(&token::CloseDelim(token::Paren)) { - (vec![self_param], false) - } else if self.eat(&token::Comma) { - let mut fn_inputs = vec![self_param]; - let (mut input, _, recovered) = self.parse_seq_to_before_end( - &token::CloseDelim(token::Paren), sep, parse_param_fn)?; - fn_inputs.append(&mut input); - (fn_inputs, recovered) - } else { - match self.expect_one_of(&[], &[]) { - Err(err) => return Err(err), - Ok(recovered) => (vec![self_param], recovered), - } - } - } else { - let (input, _, recovered) = - self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), - sep, - parse_param_fn)?; - (input, recovered) - }; - - if !recovered { - // Parse closing paren and return type. - self.expect(&token::CloseDelim(token::Paren))?; - } - // Replace duplicated recovered params with `_` pattern to avoid unecessary errors. - self.deduplicate_recovered_params_names(&mut fn_inputs); - - Ok(P(FnDecl { - inputs: fn_inputs, - output: self.parse_ret_ty(true)?, - c_variadic: false - })) + res } fn is_crate_vis(&self) -> bool { @@ -1433,6 +1122,7 @@ impl<'a> Parser<'a> { self.expected_tokens.push(TokenType::Keyword(kw::Crate)); if self.is_crate_vis() { self.bump(); // `crate` + self.sess.gated_spans.crate_visibility_modifier.borrow_mut().push(self.prev_span); return Ok(respan(self.prev_span, VisibilityKind::Crate(CrateSugar::JustCrate))); } @@ -1449,100 +1139,118 @@ impl<'a> Parser<'a> { // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so // by the following tokens. - if self.is_keyword_ahead(1, &[kw::Crate]) && - self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)` + if self.is_keyword_ahead(1, &[kw::Crate]) + && self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)` { - // `pub(crate)` + // Parse `pub(crate)`. self.bump(); // `(` self.bump(); // `crate` self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = respan( - lo.to(self.prev_span), - VisibilityKind::Crate(CrateSugar::PubCrate), - ); - return Ok(vis) + let vis = VisibilityKind::Crate(CrateSugar::PubCrate); + return Ok(respan(lo.to(self.prev_span), vis)); } else if self.is_keyword_ahead(1, &[kw::In]) { - // `pub(in path)` + // Parse `pub(in path)`. self.bump(); // `(` self.bump(); // `in` let path = self.parse_path(PathStyle::Mod)?; // `path` self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted { + let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID, - }); - return Ok(vis) - } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && - self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower]) + }; + return Ok(respan(lo.to(self.prev_span), vis)); + } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) + && self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower]) { - // `pub(self)` or `pub(super)` + // Parse `pub(self)` or `pub(super)`. self.bump(); // `(` let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = respan(lo.to(self.prev_span), VisibilityKind::Restricted { + let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID, - }); - return Ok(vis) - } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct - // `pub(something) fn ...` or `struct X { pub(something) y: Z }` - self.bump(); // `(` - let msg = "incorrect visibility restriction"; - let suggestion = r##"some possible visibility restrictions are: -`pub(crate)`: visible only on the current crate -`pub(super)`: visible only in the current module's parent -`pub(in path::to::module)`: visible only on the specified path"##; - let path = self.parse_path(PathStyle::Mod)?; - let sp = path.span; - let help_msg = format!("make this visible only to module `{}` with `in`", path); - self.expect(&token::CloseDelim(token::Paren))?; // `)` - struct_span_err!(self.sess.span_diagnostic, sp, E0704, "{}", msg) - .help(suggestion) - .span_suggestion( - sp, - &help_msg, - format!("in {}", path), - Applicability::MachineApplicable, - ) - .emit(); // Emit diagnostic, but continue with public visibility. + }; + return Ok(respan(lo.to(self.prev_span), vis)); + } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct. + self.recover_incorrect_vis_restriction()?; + // Emit diagnostic, but continue with public visibility. } } Ok(respan(lo, VisibilityKind::Public)) } + /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` + fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + + let msg = "incorrect visibility restriction"; + let suggestion = r##"some possible visibility restrictions are: +`pub(crate)`: visible only on the current crate +`pub(super)`: visible only in the current module's parent +`pub(in path::to::module)`: visible only on the specified path"##; + + let path_str = pprust::path_to_string(&path); + + struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg) + .help(suggestion) + .span_suggestion( + path.span, + &format!("make this visible only to module `{}` with `in`", path_str), + format!("in {}", path_str), + Applicability::MachineApplicable, + ) + .emit(); + + Ok(()) + } + + /// Parses `extern` followed by an optional ABI string, or nothing. + fn parse_extern_abi(&mut self) -> PResult<'a, Abi> { + if self.eat_keyword(kw::Extern) { + Ok(self.parse_opt_abi()?.unwrap_or(Abi::C)) + } else { + Ok(Abi::Rust) + } + } + /// Parses a string as an ABI spec on an extern type or module. Consumes /// the `extern` keyword, if one is found. fn parse_opt_abi(&mut self) -> PResult<'a, Option<Abi>> { match self.token.kind { token::Literal(token::Lit { kind: token::Str, symbol, suffix }) | token::Literal(token::Lit { kind: token::StrRaw(..), symbol, suffix }) => { - let sp = self.token.span; - self.expect_no_suffix(sp, "an ABI spec", suffix); + self.expect_no_suffix(self.token.span, "an ABI spec", suffix); self.bump(); match abi::lookup(&symbol.as_str()) { Some(abi) => Ok(Some(abi)), None => { - let prev_span = self.prev_span; - struct_span_err!( - self.sess.span_diagnostic, - prev_span, - E0703, - "invalid ABI: found `{}`", - symbol - ) - .span_label(prev_span, "invalid ABI") - .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) - .emit(); + self.error_on_invalid_abi(symbol); Ok(None) } } } - _ => Ok(None), } } + /// Emit an error where `symbol` is an invalid ABI. + fn error_on_invalid_abi(&self, symbol: Symbol) { + let prev_span = self.prev_span; + struct_span_err!( + self.sess.span_diagnostic, + prev_span, + E0703, + "invalid ABI: found `{}`", + symbol + ) + .span_label(prev_span, "invalid ABI") + .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) + .emit(); + } + /// We are parsing `async fn`. If we are on Rust 2015, emit an error. fn ban_async_in_2015(&self, async_span: Span) { if async_span.rust_2015() { @@ -1556,9 +1264,10 @@ impl<'a> Parser<'a> { } } - fn collect_tokens<F, R>(&mut self, f: F) -> PResult<'a, (R, TokenStream)> - where F: FnOnce(&mut Self) -> PResult<'a, R> - { + fn collect_tokens<R>( + &mut self, + f: impl FnOnce(&mut Self) -> PResult<'a, R>, + ) -> PResult<'a, (R, TokenStream)> { // Record all tokens we parse when parsing this item. let mut tokens = Vec::new(); let prev_collecting = match self.token_cursor.frame.last_token { @@ -1579,7 +1288,7 @@ impl<'a> Parser<'a> { // This can happen due to a bad interaction of two unrelated recovery mechanisms with // mismatched delimiters *and* recovery lookahead on the likely typo `pub ident(` // (#62881). - return Ok((ret?, TokenStream::new(vec![]))); + return Ok((ret?, TokenStream::default())); } else { &mut self.token_cursor.stack[prev].last_token }; @@ -1594,7 +1303,7 @@ impl<'a> Parser<'a> { // This can happen due to a bad interaction of two unrelated recovery mechanisms // with mismatched delimiters *and* recovery lookahead on the likely typo // `pub ident(` (#62895, different but similar to the case above). - return Ok((ret?, TokenStream::new(vec![]))); + return Ok((ret?, TokenStream::default())); } }; @@ -1632,7 +1341,7 @@ impl<'a> Parser<'a> { *t == token::BinOp(token::Star)) } - pub fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option<ast::Name>)> { + fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option<ast::Name>)> { let ret = match self.token.kind { token::Literal(token::Lit { kind: token::Str, symbol, suffix }) => (symbol, ast::StrStyle::Cooked, suffix), @@ -1659,25 +1368,6 @@ impl<'a> Parser<'a> { } } } - - fn report_invalid_macro_expansion_item(&self) { - self.struct_span_err( - self.prev_span, - "macros that expand to items must be delimited with braces or followed by a semicolon", - ).multipart_suggestion( - "change the delimiters to curly braces", - vec![ - (self.prev_span.with_hi(self.prev_span.lo() + BytePos(1)), String::from(" {")), - (self.prev_span.with_lo(self.prev_span.hi() - BytePos(1)), '}'.to_string()), - ], - Applicability::MaybeIncorrect, - ).span_suggestion( - self.sess.source_map.next_point(self.prev_span), - "add a semicolon", - ';'.to_string(), - Applicability::MaybeIncorrect, - ).emit(); - } } pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, handler: &errors::Handler) { |
