diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f7dced76b64..6537f59395f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2,44 +2,34 @@ mod expr; use expr::LhsExpr; - mod pat; +mod item; +pub use item::AliasKind; +mod module; +pub use module::{ModulePath, ModulePathSuccess}; -use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy}; -use crate::ast::{GenericBound, TraitBoundModifier}; -use crate::ast::Unsafety; -use crate::ast::{Mod, AnonConst, Arg, Attribute, BindingMode, TraitItemKind}; -use crate::ast::{Block, BlockCheckMode}; -use crate::ast::{Constness, Crate}; -use crate::ast::Defaultness; -use crate::ast::EnumDef; -use crate::ast::{Expr, ExprKind}; -use crate::ast::{FnDecl, FnHeader}; -use crate::ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; -use crate::ast::{GenericParam, GenericParamKind}; -use crate::ast::GenericArg; -use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind, Local, Lifetime}; -use crate::ast::{MacStmtStyle, Mac, Mac_, MacDelimiter}; +use crate::ast::{self, AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy}; +use crate::ast::{AnonConst, Arg, Attribute, BindingMode}; +use crate::ast::{Block, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind}; +use crate::ast::{FnDecl, FunctionRetTy}; +use crate::ast::{Ident, IsAsync, Local, Lifetime}; +use crate::ast::{MacStmtStyle, Mac_, MacDelimiter}; use crate::ast::{MutTy, Mutability}; -use crate::ast::{PathSegment}; -use crate::ast::{PolyTraitRef, QSelf}; -use crate::ast::{Stmt, StmtKind}; -use crate::ast::{VariantData, StructField}; +use crate::ast::{PolyTraitRef, QSelf, PathSegment}; use crate::ast::StrStyle; use crate::ast::SelfKind; -use crate::ast::{TraitItem, TraitRef, TraitObjectSyntax}; +use crate::ast::{GenericBound, TraitBoundModifier, TraitObjectSyntax}; +use crate::ast::{GenericParam, GenericParamKind, GenericArg, WhereClause}; use crate::ast::{Ty, TyKind, AssocTyConstraint, AssocTyConstraintKind, GenericBounds}; -use crate::ast::{Visibility, VisibilityKind, WhereClause, CrateSugar}; -use crate::ast::{UseTree, UseTreeKind}; -use crate::{ast, attr}; +use crate::ast::{Visibility, VisibilityKind, Unsafety, CrateSugar}; use crate::ext::base::DummyResult; use crate::ext::hygiene::SyntaxContext; -use crate::source_map::{self, SourceMap, Spanned, respan}; +use crate::source_map::{self, respan}; use crate::parse::{SeqSep, classify, literal, token}; 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::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership}; +use crate::parse::{ParseSess, Directory, DirectoryOwnership}; use crate::print::pprust; use crate::ptr::P; use crate::parse::PResult; @@ -48,25 +38,14 @@ use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; use crate::symbol::{kw, sym, Symbol}; use crate::parse::diagnostics::{Error, dummy_arg}; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; +use errors::{Applicability, DiagnosticId, FatalError}; use rustc_target::spec::abi::{self, Abi}; use syntax_pos::{Span, BytePos, DUMMY_SP, FileName}; use log::debug; use std::borrow::Cow; -use std::cmp; -use std::mem; -use std::path::{self, Path, PathBuf}; -use std::slice; - -#[derive(Debug)] -/// Whether the type alias or associated type is a concrete type or an opaque type -pub enum AliasKind { - /// Just a new name for the same type - Weak(P), - /// Only trait impls of the type will be usable, not the actual type itself - OpaqueTy(GenericBounds), -} +use std::{cmp, mem, slice}; +use std::path::PathBuf; bitflags::bitflags! { struct Restrictions: u8 { @@ -75,8 +54,6 @@ bitflags::bitflags! { } } -type ItemInfo = (Ident, ItemKind, Option>); - /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] pub enum PathStyle { @@ -390,19 +367,6 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { t == &token::BinOp(token::Shl) } -/// Information about the path to a module. -pub struct ModulePath { - name: String, - path_exists: bool, - pub result: Result, -} - -pub struct ModulePathSuccess { - pub path: PathBuf, - pub directory_ownership: DirectoryOwnership, - warn: bool, -} - #[derive(Copy, Clone, Debug)] crate enum TokenExpectType { Expect, @@ -1077,120 +1041,6 @@ impl<'a> Parser<'a> { } } - /// Parses the items in a trait declaration. - pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { - maybe_whole!(self, NtTraitItem, |x| x); - let attrs = self.parse_outer_attributes()?; - let mut unclosed_delims = vec![]; - let (mut item, tokens) = self.collect_tokens(|this| { - let item = this.parse_trait_item_(at_end, attrs); - unclosed_delims.append(&mut this.unclosed_delims); - item - })?; - self.unclosed_delims.append(&mut unclosed_delims); - // See `parse_item` for why this clause is here. - if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { - item.tokens = Some(tokens); - } - Ok(item) - } - - fn parse_trait_item_(&mut self, - at_end: &mut bool, - mut attrs: Vec) -> PResult<'a, TraitItem> { - let lo = self.token.span; - self.eat_bad_pub(); - let (name, node, generics) = if self.eat_keyword(kw::Type) { - self.parse_trait_item_assoc_ty()? - } else if self.is_const_item() { - self.expect_keyword(kw::Const)?; - let ident = self.parse_ident()?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - let default = if self.eat(&token::Eq) { - let expr = self.parse_expr()?; - self.expect(&token::Semi)?; - Some(expr) - } else { - self.expect(&token::Semi)?; - None - }; - (ident, TraitItemKind::Const(ty, default), ast::Generics::default()) - } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? { - // trait item macro. - (Ident::invalid(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) - } else { - let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; - - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; - - let decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { - // This is somewhat dubious; We don't want to allow - // argument names to be left off if there is a - // definition... - - // We don't allow argument names to be left off in edition 2018. - let is_name_required = p.token.span.rust_2018(); - p.parse_arg_general(true, false, |_| is_name_required) - })?; - generics.where_clause = self.parse_where_clause()?; - - let sig = ast::MethodSig { - header: FnHeader { - unsafety, - constness, - abi, - asyncness, - }, - decl, - }; - - let body = match self.token.kind { - token::Semi => { - self.bump(); - *at_end = true; - debug!("parse_trait_methods(): parsing required method"); - None - } - token::OpenDelim(token::Brace) => { - debug!("parse_trait_methods(): parsing provided method"); - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } - token::Interpolated(ref nt) => { - match **nt { - token::NtBlock(..) => { - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - attrs.extend(inner_attrs.iter().cloned()); - Some(body) - } - _ => { - return self.expected_semi_or_open_brace(); - } - } - } - _ => { - return self.expected_semi_or_open_brace(); - } - }; - (ident, ast::TraitItemKind::Method(sig, body), generics) - }; - - Ok(TraitItem { - id: ast::DUMMY_NODE_ID, - ident: name, - attrs, - generics, - node, - span: lo.to(self.prev_span), - tokens: None, - }) - } - /// Parses an optional return type `[ -> TY ]` in a function declaration. fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> { if self.eat(&token::RArrow) { @@ -1992,39 +1842,6 @@ impl<'a> Parser<'a> { })) } - /// Parses a structure field. - fn parse_name_and_ty(&mut self, - lo: Span, - vis: Visibility, - attrs: Vec) - -> PResult<'a, StructField> { - let name = self.parse_ident()?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - Ok(StructField { - span: lo.to(self.prev_span), - ident: Some(name), - vis, - id: ast::DUMMY_NODE_ID, - ty, - attrs, - }) - } - - /// Emits an expected-item-after-attributes error. - fn expected_item_err(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> { - let message = match attrs.last() { - Some(&Attribute { is_sugared_doc: true, .. }) => "expected item after doc comment", - _ => "expected item after attributes", - }; - - let mut err = self.diagnostic().struct_span_err(self.prev_span, message); - if attrs.last().unwrap().is_sugared_doc { - err.span_label(self.prev_span, "this doc comment doesn't document anything"); - } - Err(err) - } - /// Parse a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. pub fn parse_stmt(&mut self) -> PResult<'a, Option> { @@ -2044,11 +1861,6 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(1, &[kw::Fn]) } - fn is_union_item(&self) -> bool { - self.token.is_keyword(kw::Union) && - self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) - } - fn is_crate_vis(&self) -> bool { self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep) } @@ -2063,58 +1875,6 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(2, &[kw::Trait])) } - fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility, lo: Span) - -> PResult<'a, Option>> { - let token_lo = self.token.span; - let (ident, def) = if self.eat_keyword(kw::Macro) { - let ident = self.parse_ident()?; - let tokens = if self.check(&token::OpenDelim(token::Brace)) { - match self.parse_token_tree() { - TokenTree::Delimited(_, _, tts) => tts, - _ => unreachable!(), - } - } else if self.check(&token::OpenDelim(token::Paren)) { - let args = self.parse_token_tree(); - let body = if self.check(&token::OpenDelim(token::Brace)) { - self.parse_token_tree() - } else { - self.unexpected()?; - unreachable!() - }; - TokenStream::new(vec![ - args.into(), - TokenTree::token(token::FatArrow, token_lo.to(self.prev_span)).into(), - body.into(), - ]) - } else { - self.unexpected()?; - unreachable!() - }; - - (ident, ast::MacroDef { tokens: tokens.into(), legacy: false }) - } else if self.check_keyword(sym::macro_rules) && - self.look_ahead(1, |t| *t == token::Not) && - self.look_ahead(2, |t| t.is_ident()) { - let prev_span = self.prev_span; - self.complain_if_pub_macro(&vis.node, prev_span); - self.bump(); - self.bump(); - - let ident = self.parse_ident()?; - let (delim, tokens) = self.expect_delimited_token_tree()?; - if delim != MacDelimiter::Brace && !self.eat(&token::Semi) { - self.report_invalid_macro_expansion_item(); - } - - (ident, ast::MacroDef { tokens, legacy: true }) - } else { - return Ok(None); - }; - - let span = lo.to(self.prev_span); - Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec()))) - } - fn parse_stmt_without_recovery( &mut self, macro_legacy_warnings: bool, @@ -2613,32 +2373,6 @@ impl<'a> Parser<'a> { }) } - /// Parses the following grammar: - /// - /// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty] - fn parse_trait_item_assoc_ty(&mut self) - -> PResult<'a, (Ident, TraitItemKind, ast::Generics)> { - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; - - // Parse optional colon and param bounds. - let bounds = if self.eat(&token::Colon) { - self.parse_generic_bounds(None)? - } else { - Vec::new() - }; - generics.where_clause = self.parse_where_clause()?; - - let default = if self.eat(&token::Eq) { - Some(self.parse_ty()?) - } else { - None - }; - self.expect(&token::Semi)?; - - Ok((ident, TraitItemKind::Type(bounds, default), generics)) - } - fn parse_const_param(&mut self, preceding_attrs: Vec) -> PResult<'a, GenericParam> { self.expect_keyword(kw::Const)?; let ident = self.parse_ident()?; @@ -3134,18 +2868,6 @@ impl<'a> Parser<'a> { Ok((args, c_variadic)) } - /// Parses the argument list and result type of a function declaration. - fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P> { - let (args, c_variadic) = self.parse_fn_args(true, allow_c_variadic)?; - let ret_ty = self.parse_ret_ty(true)?; - - Ok(P(FnDecl { - inputs: args, - output: ret_ty, - c_variadic, - })) - } - /// Returns the parsed optional self argument and whether a self shortcut was used. /// /// See `parse_self_arg_with_attrs` to collect attributes. @@ -3340,301 +3062,6 @@ impl<'a> Parser<'a> { })) } - /// Parses the name and optional generic types of a function header. - fn parse_fn_header(&mut self) -> PResult<'a, (Ident, ast::Generics)> { - let id = self.parse_ident()?; - let generics = self.parse_generics()?; - Ok((id, generics)) - } - - fn mk_item(&self, span: Span, ident: Ident, node: ItemKind, vis: Visibility, - attrs: Vec) -> P { - P(Item { - ident, - attrs, - id: ast::DUMMY_NODE_ID, - node, - vis, - span, - tokens: None, - }) - } - - /// Parses an item-position function declaration. - fn parse_item_fn(&mut self, - unsafety: Unsafety, - asyncness: Spanned, - constness: Spanned, - abi: Abi) - -> PResult<'a, ItemInfo> { - let (ident, mut generics) = self.parse_fn_header()?; - let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe; - let decl = self.parse_fn_decl(allow_c_variadic)?; - generics.where_clause = self.parse_where_clause()?; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - let header = FnHeader { unsafety, asyncness, constness, abi }; - Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) - } - - /// Returns `true` if we are looking at `const ID` - /// (returns `false` for things like `const fn`, etc.). - fn is_const_item(&self) -> bool { - self.token.is_keyword(kw::Const) && - !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) - } - - /// Parses all the "front matter" for a `fn` declaration, up to - /// and including the `fn` keyword: - /// - /// - `const fn` - /// - `unsafe fn` - /// - `const unsafe fn` - /// - `extern fn` - /// - etc. - fn parse_fn_front_matter(&mut self) - -> PResult<'a, ( - Spanned, - Unsafety, - Spanned, - Abi - )> - { - let is_const_fn = self.eat_keyword(kw::Const); - let const_span = self.prev_span; - let asyncness = self.parse_asyncness(); - if let IsAsync::Async { .. } = asyncness { - self.ban_async_in_2015(self.prev_span); - } - let asyncness = respan(self.prev_span, asyncness); - let unsafety = self.parse_unsafety(); - let (constness, unsafety, abi) = if is_const_fn { - (respan(const_span, Constness::Const), unsafety, Abi::Rust) - } else { - let abi = if self.eat_keyword(kw::Extern) { - self.parse_opt_abi()?.unwrap_or(Abi::C) - } else { - Abi::Rust - }; - (respan(self.prev_span, Constness::NotConst), unsafety, abi) - }; - if !self.eat_keyword(kw::Fn) { - // It is possible for `expect_one_of` to recover given the contents of - // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't - // account for this. - if !self.expect_one_of(&[], &[])? { unreachable!() } - } - Ok((constness, unsafety, asyncness, abi)) - } - - /// Parses an impl item. - pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> { - maybe_whole!(self, NtImplItem, |x| x); - let attrs = self.parse_outer_attributes()?; - let mut unclosed_delims = vec![]; - let (mut item, tokens) = self.collect_tokens(|this| { - let item = this.parse_impl_item_(at_end, attrs); - unclosed_delims.append(&mut this.unclosed_delims); - item - })?; - self.unclosed_delims.append(&mut unclosed_delims); - - // See `parse_item` for why this clause is here. - if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { - item.tokens = Some(tokens); - } - Ok(item) - } - - fn parse_impl_item_(&mut self, - at_end: &mut bool, - mut attrs: Vec) -> PResult<'a, ImplItem> { - let lo = self.token.span; - let vis = self.parse_visibility(false)?; - let defaultness = self.parse_defaultness(); - let (name, node, generics) = if let Some(type_) = self.eat_type() { - let (name, alias, generics) = type_?; - let kind = match alias { - AliasKind::Weak(typ) => ast::ImplItemKind::TyAlias(typ), - AliasKind::OpaqueTy(bounds) => ast::ImplItemKind::OpaqueTy(bounds), - }; - (name, kind, generics) - } else if self.is_const_item() { - // This parses the grammar: - // ImplItemConst = "const" Ident ":" Ty "=" Expr ";" - self.expect_keyword(kw::Const)?; - let name = self.parse_ident()?; - self.expect(&token::Colon)?; - let typ = self.parse_ty()?; - self.expect(&token::Eq)?; - let expr = self.parse_expr()?; - self.expect(&token::Semi)?; - (name, ast::ImplItemKind::Const(typ, expr), ast::Generics::default()) - } else { - let (name, inner_attrs, generics, node) = self.parse_impl_method(&vis, at_end)?; - attrs.extend(inner_attrs); - (name, node, generics) - }; - - Ok(ImplItem { - id: ast::DUMMY_NODE_ID, - span: lo.to(self.prev_span), - ident: name, - vis, - defaultness, - attrs, - generics, - node, - tokens: None, - }) - } - - fn complain_if_pub_macro(&self, vis: &VisibilityKind, sp: Span) { - match *vis { - VisibilityKind::Inherited => {} - _ => { - let mut err = if self.token.is_keyword(sym::macro_rules) { - let mut err = self.diagnostic() - .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); - err.span_suggestion( - sp, - "try exporting the macro", - "#[macro_export]".to_owned(), - Applicability::MaybeIncorrect // speculative - ); - err - } else { - let mut err = self.diagnostic() - .struct_span_err(sp, "can't qualify macro invocation with `pub`"); - err.help("try adjusting the macro to put `pub` inside the invocation"); - err - }; - err.emit(); - } - } - } - - fn missing_assoc_item_kind_err(&self, item_type: &str, prev_span: Span) - -> DiagnosticBuilder<'a> - { - let expected_kinds = if item_type == "extern" { - "missing `fn`, `type`, or `static`" - } else { - "missing `fn`, `type`, or `const`" - }; - - // Given this code `path(`, it seems like this is not - // setting the visibility of a macro invocation, but rather - // a mistyped method declaration. - // Create a diagnostic pointing out that `fn` is missing. - // - // x | pub path(&self) { - // | ^ missing `fn`, `type`, or `const` - // pub path( - // ^^ `sp` below will point to this - let sp = prev_span.between(self.prev_span); - let mut err = self.diagnostic().struct_span_err( - sp, - &format!("{} for {}-item declaration", - expected_kinds, item_type)); - err.span_label(sp, expected_kinds); - err - } - - /// Parse a method or a macro invocation in a trait impl. - fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool) - -> PResult<'a, (Ident, Vec, ast::Generics, - ast::ImplItemKind)> { - // code copied from parse_macro_use_or_failure... abstraction! - if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? { - // method macro - Ok((Ident::invalid(), vec![], ast::Generics::default(), - ast::ImplItemKind::Macro(mac))) - } else { - let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; - let ident = self.parse_ident()?; - let mut generics = self.parse_generics()?; - let decl = self.parse_fn_decl_with_self(|p| { - p.parse_arg_general(true, false, |_| true) - })?; - generics.where_clause = self.parse_where_clause()?; - *at_end = true; - let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - let header = ast::FnHeader { abi, unsafety, constness, asyncness }; - Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method( - ast::MethodSig { header, decl }, - body - ))) - } - } - - /// Parses `trait Foo { ... }` or `trait Foo = Bar;`. - fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> { - let ident = self.parse_ident()?; - let mut tps = self.parse_generics()?; - - // Parse optional colon and supertrait bounds. - let bounds = if self.eat(&token::Colon) { - self.parse_generic_bounds(Some(self.prev_span))? - } else { - Vec::new() - }; - - if self.eat(&token::Eq) { - // it's a trait alias - let bounds = self.parse_generic_bounds(None)?; - tps.where_clause = self.parse_where_clause()?; - self.expect(&token::Semi)?; - if is_auto == IsAuto::Yes { - let msg = "trait aliases cannot be `auto`"; - self.struct_span_err(self.prev_span, msg) - .span_label(self.prev_span, msg) - .emit(); - } - if unsafety != Unsafety::Normal { - let msg = "trait aliases cannot be `unsafe`"; - self.struct_span_err(self.prev_span, msg) - .span_label(self.prev_span, msg) - .emit(); - } - Ok((ident, ItemKind::TraitAlias(tps, bounds), None)) - } else { - // it's a normal trait - tps.where_clause = self.parse_where_clause()?; - self.expect(&token::OpenDelim(token::Brace))?; - let mut trait_items = vec![]; - while !self.eat(&token::CloseDelim(token::Brace)) { - if let token::DocComment(_) = self.token.kind { - if self.look_ahead(1, - |tok| tok == &token::CloseDelim(token::Brace)) { - self.diagnostic().struct_span_err_with_code( - self.token.span, - "found a documentation comment that doesn't document anything", - DiagnosticId::Error("E0584".into()), - ) - .help( - "doc comments must come before what they document, maybe a \ - comment was intended with `//`?", - ) - .emit(); - self.bump(); - continue; - } - } - let mut at_end = false; - match self.parse_trait_item(&mut at_end) { - Ok(item) => trait_items.push(item), - Err(mut e) => { - e.emit(); - if !at_end { - self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); - } - } - } - } - Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None)) - } - } - fn choose_generics_over_qpath(&self) -> bool { // There's an ambiguity between generic parameters and qualified paths in impls. // If we see `<` it may start both, so we have to inspect some following tokens. @@ -3660,118 +3087,6 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(1, &[kw::Const])) } - fn parse_impl_body(&mut self) -> PResult<'a, (Vec, Vec)> { - self.expect(&token::OpenDelim(token::Brace))?; - let attrs = self.parse_inner_attributes()?; - - let mut impl_items = Vec::new(); - while !self.eat(&token::CloseDelim(token::Brace)) { - let mut at_end = false; - match self.parse_impl_item(&mut at_end) { - Ok(impl_item) => impl_items.push(impl_item), - Err(mut err) => { - err.emit(); - if !at_end { - self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); - } - } - } - } - Ok((impl_items, attrs)) - } - - /// Parses an implementation item, `impl` keyword is already parsed. - /// - /// impl<'a, T> TYPE { /* impl items */ } - /// impl<'a, T> TRAIT for TYPE { /* impl items */ } - /// impl<'a, T> !TRAIT for TYPE { /* impl items */ } - /// - /// We actually parse slightly more relaxed grammar for better error reporting and recovery. - /// `impl` GENERICS `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}` - /// `impl` GENERICS `!`? TYPE (`where` PREDICATES)? `{` BODY `}` - fn parse_item_impl(&mut self, unsafety: Unsafety, defaultness: Defaultness) - -> PResult<'a, ItemInfo> { - // First, parse generic parameters if necessary. - let mut generics = if self.choose_generics_over_qpath() { - self.parse_generics()? - } else { - ast::Generics::default() - }; - - // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. - let polarity = if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) { - self.bump(); // `!` - ast::ImplPolarity::Negative - } else { - ast::ImplPolarity::Positive - }; - - // Parse both types and traits as a type, then reinterpret if necessary. - let err_path = |span| ast::Path::from_ident(Ident::new(kw::Invalid, span)); - let ty_first = if self.token.is_keyword(kw::For) && - self.look_ahead(1, |t| t != &token::Lt) { - let span = self.prev_span.between(self.token.span); - self.struct_span_err(span, "missing trait in a trait impl").emit(); - P(Ty { node: TyKind::Path(None, err_path(span)), span, id: ast::DUMMY_NODE_ID }) - } else { - self.parse_ty()? - }; - - // If `for` is missing we try to recover. - let has_for = self.eat_keyword(kw::For); - let missing_for_span = self.prev_span.between(self.token.span); - - let ty_second = if self.token == token::DotDot { - // We need to report this error after `cfg` expansion for compatibility reasons - self.bump(); // `..`, do not add it to expected tokens - Some(DummyResult::raw_ty(self.prev_span, true)) - } else if has_for || self.token.can_begin_type() { - Some(self.parse_ty()?) - } else { - None - }; - - generics.where_clause = self.parse_where_clause()?; - - let (impl_items, attrs) = self.parse_impl_body()?; - - let item_kind = match ty_second { - Some(ty_second) => { - // impl Trait for Type - if !has_for { - self.struct_span_err(missing_for_span, "missing `for` in a trait impl") - .span_suggestion_short( - missing_for_span, - "add `for` here", - " for ".to_string(), - Applicability::MachineApplicable, - ).emit(); - } - - let ty_first = ty_first.into_inner(); - let path = match ty_first.node { - // This notably includes paths passed through `ty` macro fragments (#46438). - TyKind::Path(None, path) => path, - _ => { - self.span_err(ty_first.span, "expected a trait, found type"); - err_path(ty_first.span) - } - }; - let trait_ref = TraitRef { path, ref_id: ty_first.id }; - - ItemKind::Impl(unsafety, polarity, defaultness, - generics, Some(trait_ref), ty_second, impl_items) - } - None => { - // impl Type - ItemKind::Impl(unsafety, polarity, defaultness, - generics, None, ty_first, impl_items) - } - }; - - Ok((Ident::invalid(), item_kind, Some(attrs))) - } - fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(kw::For) { self.expect_lt()?; @@ -3785,206 +3100,6 @@ impl<'a> Parser<'a> { } } - /// Parses `struct Foo { ... }`. - fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { - let class_name = self.parse_ident()?; - - let mut generics = self.parse_generics()?; - - // There is a special case worth noting here, as reported in issue #17904. - // If we are parsing a tuple struct it is the case that the where clause - // should follow the field list. Like so: - // - // struct Foo(T) where T: Copy; - // - // If we are parsing a normal record-style struct it is the case - // that the where clause comes before the body, and after the generics. - // So if we look ahead and see a brace or a where-clause we begin - // parsing a record style struct. - // - // Otherwise if we look ahead and see a paren we parse a tuple-style - // struct. - - let vdata = if self.token.is_keyword(kw::Where) { - generics.where_clause = self.parse_where_clause()?; - if self.eat(&token::Semi) { - // If we see a: `struct Foo where T: Copy;` style decl. - VariantData::Unit(ast::DUMMY_NODE_ID) - } else { - // If we see: `struct Foo where T: Copy { ... }` - let (fields, recovered) = self.parse_record_struct_body()?; - VariantData::Struct(fields, recovered) - } - // No `where` so: `struct Foo;` - } else if self.eat(&token::Semi) { - VariantData::Unit(ast::DUMMY_NODE_ID) - // Record-style struct definition - } else if self.token == token::OpenDelim(token::Brace) { - let (fields, recovered) = self.parse_record_struct_body()?; - VariantData::Struct(fields, recovered) - // Tuple-style struct definition with optional where-clause. - } else if self.token == token::OpenDelim(token::Paren) { - let body = VariantData::Tuple(self.parse_tuple_struct_body()?, ast::DUMMY_NODE_ID); - generics.where_clause = self.parse_where_clause()?; - self.expect(&token::Semi)?; - body - } else { - let token_str = self.this_token_descr(); - let mut err = self.fatal(&format!( - "expected `where`, `{{`, `(`, or `;` after struct name, found {}", - token_str - )); - err.span_label(self.token.span, "expected `where`, `{`, `(`, or `;` after struct name"); - return Err(err); - }; - - Ok((class_name, ItemKind::Struct(vdata, generics), None)) - } - - /// Parses `union Foo { ... }`. - fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { - let class_name = self.parse_ident()?; - - let mut generics = self.parse_generics()?; - - let vdata = if self.token.is_keyword(kw::Where) { - generics.where_clause = self.parse_where_clause()?; - let (fields, recovered) = self.parse_record_struct_body()?; - VariantData::Struct(fields, recovered) - } else if self.token == token::OpenDelim(token::Brace) { - let (fields, recovered) = self.parse_record_struct_body()?; - VariantData::Struct(fields, recovered) - } else { - let token_str = self.this_token_descr(); - let mut err = self.fatal(&format!( - "expected `where` or `{{` after union name, found {}", token_str)); - err.span_label(self.token.span, "expected `where` or `{` after union name"); - return Err(err); - }; - - Ok((class_name, ItemKind::Union(vdata, generics), None)) - } - - fn parse_record_struct_body( - &mut self, - ) -> PResult<'a, (Vec, /* recovered */ bool)> { - let mut fields = Vec::new(); - let mut recovered = false; - if self.eat(&token::OpenDelim(token::Brace)) { - while self.token != token::CloseDelim(token::Brace) { - let field = self.parse_struct_decl_field().map_err(|e| { - self.recover_stmt(); - recovered = true; - e - }); - match field { - Ok(field) => fields.push(field), - Err(mut err) => { - err.emit(); - } - } - } - self.eat(&token::CloseDelim(token::Brace)); - } else { - let token_str = self.this_token_descr(); - let mut err = self.fatal(&format!( - "expected `where`, or `{{` after struct name, found {}", token_str)); - err.span_label(self.token.span, "expected `where`, or `{` after struct name"); - return Err(err); - } - - Ok((fields, recovered)) - } - - fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec> { - // This is the case where we find `struct Foo(T) where T: Copy;` - // Unit like structs are handled in parse_item_struct function - self.parse_paren_comma_seq(|p| { - let attrs = p.parse_outer_attributes()?; - let lo = p.token.span; - let vis = p.parse_visibility(true)?; - let ty = p.parse_ty()?; - Ok(StructField { - span: lo.to(ty.span), - vis, - ident: None, - id: ast::DUMMY_NODE_ID, - ty, - attrs, - }) - }).map(|(r, _)| r) - } - - /// Parses a structure field declaration. - fn parse_single_struct_field(&mut self, - lo: Span, - vis: Visibility, - attrs: Vec ) - -> PResult<'a, StructField> { - let mut seen_comma: bool = false; - let a_var = self.parse_name_and_ty(lo, vis, attrs)?; - if self.token == token::Comma { - seen_comma = true; - } - match self.token.kind { - token::Comma => { - self.bump(); - } - token::CloseDelim(token::Brace) => {} - token::DocComment(_) => { - let previous_span = self.prev_span; - let mut err = self.span_fatal_err(self.token.span, Error::UselessDocComment); - self.bump(); // consume the doc comment - let comma_after_doc_seen = self.eat(&token::Comma); - // `seen_comma` is always false, because we are inside doc block - // condition is here to make code more readable - if seen_comma == false && comma_after_doc_seen == true { - seen_comma = true; - } - if comma_after_doc_seen || self.token == token::CloseDelim(token::Brace) { - err.emit(); - } else { - if seen_comma == false { - let sp = self.sess.source_map().next_point(previous_span); - err.span_suggestion( - sp, - "missing comma here", - ",".into(), - Applicability::MachineApplicable - ); - } - return Err(err); - } - } - _ => { - let sp = self.sess.source_map().next_point(self.prev_span); - let mut err = self.struct_span_err(sp, &format!("expected `,`, or `}}`, found {}", - self.this_token_descr())); - if self.token.is_ident() { - // This is likely another field; emit the diagnostic and keep going - err.span_suggestion( - sp, - "try adding a comma", - ",".into(), - Applicability::MachineApplicable, - ); - err.emit(); - } else { - return Err(err) - } - } - } - Ok(a_var) - } - - /// Parses an element of a struct declaration. - fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { - let attrs = self.parse_outer_attributes()?; - let lo = self.token.span; - let vis = self.parse_visibility(false)?; - self.parse_single_struct_field(lo, vis, attrs) - } - /// Parses `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `crate` for `pub(crate)`, /// `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. /// If the following element can't be a tuple (i.e., it's a function definition), then @@ -4074,606 +3189,6 @@ impl<'a> Parser<'a> { Ok(respan(lo, VisibilityKind::Public)) } - /// Parses defaultness (i.e., `default` or nothing). - fn parse_defaultness(&mut self) -> Defaultness { - // `pub` is included for better error messages - if self.check_keyword(kw::Default) && - self.is_keyword_ahead(1, &[ - kw::Impl, - kw::Const, - kw::Fn, - kw::Unsafe, - kw::Extern, - kw::Type, - kw::Pub, - ]) - { - self.bump(); // `default` - Defaultness::Default - } else { - Defaultness::Final - } - } - - /// Given a termination token, parses all of the items in a module. - fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> { - let mut items = vec![]; - while let Some(item) = self.parse_item()? { - items.push(item); - self.maybe_consume_incorrect_semicolon(&items); - } - - if !self.eat(term) { - let token_str = self.this_token_descr(); - if !self.maybe_consume_incorrect_semicolon(&items) { - let mut err = self.fatal(&format!("expected item, found {}", token_str)); - err.span_label(self.token.span, "expected item"); - return Err(err); - } - } - - let hi = if self.token.span.is_dummy() { - inner_lo - } else { - self.prev_span - }; - - Ok(ast::Mod { - inner: inner_lo.to(hi), - items, - inline: true - }) - } - - fn parse_item_const(&mut self, m: Option) -> PResult<'a, ItemInfo> { - let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - self.expect(&token::Eq)?; - let e = self.parse_expr()?; - self.expect(&token::Semi)?; - let item = match m { - Some(m) => ItemKind::Static(ty, m, e), - None => ItemKind::Const(ty, e), - }; - Ok((id, item, None)) - } - - /// Parse a `mod { ... }` or `mod ;` item - fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> { - let (in_cfg, outer_attrs) = { - let mut strip_unconfigured = crate::config::StripUnconfigured { - sess: self.sess, - features: None, // don't perform gated feature checking - }; - let mut outer_attrs = outer_attrs.to_owned(); - strip_unconfigured.process_cfg_attrs(&mut outer_attrs); - (!self.cfg_mods || strip_unconfigured.in_cfg(&outer_attrs), outer_attrs) - }; - - let id_span = self.token.span; - let id = self.parse_ident()?; - if self.eat(&token::Semi) { - if in_cfg && self.recurse_into_file_modules { - // This mod is in an external file. Let's go get it! - let ModulePathSuccess { path, directory_ownership, warn } = - self.submod_path(id, &outer_attrs, id_span)?; - let (module, mut attrs) = - self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?; - // Record that we fetched the mod from an external file - if warn { - let attr = attr::mk_attr_outer( - attr::mk_word_item(Ident::with_empty_ctxt(sym::warn_directory_ownership))); - attr::mark_known(&attr); - attrs.push(attr); - } - Ok((id, ItemKind::Mod(module), Some(attrs))) - } else { - let placeholder = ast::Mod { - inner: DUMMY_SP, - items: Vec::new(), - inline: false - }; - Ok((id, ItemKind::Mod(placeholder), None)) - } - } else { - let old_directory = self.directory.clone(); - self.push_directory(id, &outer_attrs); - - self.expect(&token::OpenDelim(token::Brace))?; - let mod_inner_lo = self.token.span; - let attrs = self.parse_inner_attributes()?; - let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; - - self.directory = old_directory; - Ok((id, ItemKind::Mod(module), Some(attrs))) - } - } - - fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { - if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { - self.directory.path.to_mut().push(&path.as_str()); - self.directory.ownership = DirectoryOwnership::Owned { relative: None }; - } else { - // We have to push on the current module name in the case of relative - // paths in order to ensure that any additional module paths from inline - // `mod x { ... }` come after the relative extension. - // - // For example, a `mod z { ... }` inside `x/y.rs` should set the current - // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`. - if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership { - if let Some(ident) = relative.take() { // remove the relative offset - self.directory.path.to_mut().push(ident.as_str()); - } - } - self.directory.path.to_mut().push(&id.as_str()); - } - } - - pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { - if let Some(s) = attr::first_attr_value_str_by_name(attrs, sym::path) { - let s = s.as_str(); - - // On windows, the base path might have the form - // `\\?\foo\bar` in which case it does not tolerate - // mixed `/` and `\` separators, so canonicalize - // `/` to `\`. - #[cfg(windows)] - let s = s.replace("/", "\\"); - Some(dir_path.join(s)) - } else { - None - } - } - - /// Returns a path to a module. - pub fn default_submod_path( - id: ast::Ident, - relative: Option, - dir_path: &Path, - source_map: &SourceMap) -> ModulePath - { - // If we're in a foo.rs file instead of a mod.rs file, - // we need to look for submodules in - // `./foo/.rs` and `./foo//mod.rs` rather than - // `./.rs` and `.//mod.rs`. - let relative_prefix_string; - let relative_prefix = if let Some(ident) = relative { - relative_prefix_string = format!("{}{}", ident.as_str(), path::MAIN_SEPARATOR); - &relative_prefix_string - } else { - "" - }; - - let mod_name = id.to_string(); - let default_path_str = format!("{}{}.rs", relative_prefix, mod_name); - let secondary_path_str = format!("{}{}{}mod.rs", - relative_prefix, mod_name, path::MAIN_SEPARATOR); - let default_path = dir_path.join(&default_path_str); - let secondary_path = dir_path.join(&secondary_path_str); - let default_exists = source_map.file_exists(&default_path); - let secondary_exists = source_map.file_exists(&secondary_path); - - let result = match (default_exists, secondary_exists) { - (true, false) => Ok(ModulePathSuccess { - path: default_path, - directory_ownership: DirectoryOwnership::Owned { - relative: Some(id), - }, - warn: false, - }), - (false, true) => Ok(ModulePathSuccess { - path: secondary_path, - directory_ownership: DirectoryOwnership::Owned { - relative: None, - }, - warn: false, - }), - (false, false) => Err(Error::FileNotFoundForModule { - mod_name: mod_name.clone(), - default_path: default_path_str, - secondary_path: secondary_path_str, - dir_path: dir_path.display().to_string(), - }), - (true, true) => Err(Error::DuplicatePaths { - mod_name: mod_name.clone(), - default_path: default_path_str, - secondary_path: secondary_path_str, - }), - }; - - ModulePath { - name: mod_name, - path_exists: default_exists || secondary_exists, - result, - } - } - - fn submod_path(&mut self, - id: ast::Ident, - outer_attrs: &[Attribute], - id_sp: Span) - -> PResult<'a, ModulePathSuccess> { - if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) { - return Ok(ModulePathSuccess { - directory_ownership: match path.file_name().and_then(|s| s.to_str()) { - // All `#[path]` files are treated as though they are a `mod.rs` file. - // This means that `mod foo;` declarations inside `#[path]`-included - // files are siblings, - // - // Note that this will produce weirdness when a file named `foo.rs` is - // `#[path]` included and contains a `mod foo;` declaration. - // If you encounter this, it's your own darn fault :P - Some(_) => DirectoryOwnership::Owned { relative: None }, - _ => DirectoryOwnership::UnownedViaMod(true), - }, - path, - warn: false, - }); - } - - let relative = match self.directory.ownership { - DirectoryOwnership::Owned { relative } => relative, - DirectoryOwnership::UnownedViaBlock | - DirectoryOwnership::UnownedViaMod(_) => None, - }; - let paths = Parser::default_submod_path( - id, relative, &self.directory.path, self.sess.source_map()); - - match self.directory.ownership { - DirectoryOwnership::Owned { .. } => { - paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) - }, - DirectoryOwnership::UnownedViaBlock => { - let msg = - "Cannot declare a non-inline module inside a block \ - unless it has a path attribute"; - let mut err = self.diagnostic().struct_span_err(id_sp, msg); - if paths.path_exists { - let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", - paths.name); - err.span_note(id_sp, &msg); - } - Err(err) - } - DirectoryOwnership::UnownedViaMod(warn) => { - if warn { - if let Ok(result) = paths.result { - return Ok(ModulePathSuccess { warn: true, ..result }); - } - } - let mut err = self.diagnostic().struct_span_err(id_sp, - "cannot declare a new module at this location"); - if !id_sp.is_dummy() { - let src_path = self.sess.source_map().span_to_filename(id_sp); - if let FileName::Real(src_path) = src_path { - if let Some(stem) = src_path.file_stem() { - let mut dest_path = src_path.clone(); - dest_path.set_file_name(stem); - dest_path.push("mod.rs"); - err.span_note(id_sp, - &format!("maybe move this module `{}` to its own \ - directory via `{}`", src_path.display(), - dest_path.display())); - } - } - } - if paths.path_exists { - err.span_note(id_sp, - &format!("... or maybe `use` the module `{}` instead \ - of possibly redeclaring it", - paths.name)); - } - Err(err) - } - } - } - - /// Reads a module from a source file. - fn eval_src_mod( - &mut self, - path: PathBuf, - directory_ownership: DirectoryOwnership, - name: String, - id_sp: Span, - ) -> PResult<'a, (ast::Mod, Vec)> { - let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut(); - if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { - let mut err = String::from("circular modules: "); - let len = included_mod_stack.len(); - for p in &included_mod_stack[i.. len] { - err.push_str(&p.to_string_lossy()); - err.push_str(" -> "); - } - err.push_str(&path.to_string_lossy()); - return Err(self.span_fatal(id_sp, &err[..])); - } - included_mod_stack.push(path.clone()); - drop(included_mod_stack); - - let mut p0 = - new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp); - p0.cfg_mods = self.cfg_mods; - let mod_inner_lo = p0.token.span; - let mod_attrs = p0.parse_inner_attributes()?; - let mut m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?; - m0.inline = false; - self.sess.included_mod_stack.borrow_mut().pop(); - Ok((m0, mod_attrs)) - } - - /// Parses a function declaration from a foreign module. - fn parse_item_foreign_fn( - &mut self, - vis: ast::Visibility, - lo: Span, - attrs: Vec, - extern_sp: Span, - ) -> PResult<'a, ForeignItem> { - self.expect_keyword(kw::Fn)?; - - let (ident, mut generics) = self.parse_fn_header()?; - let decl = self.parse_fn_decl(true)?; - generics.where_clause = self.parse_where_clause()?; - let hi = self.token.span; - self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?; - Ok(ast::ForeignItem { - ident, - attrs, - node: ForeignItemKind::Fn(decl, generics), - id: ast::DUMMY_NODE_ID, - span: lo.to(hi), - vis, - }) - } - - /// Parses a static item from a foreign module. - /// Assumes that the `static` keyword is already parsed. - fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec) - -> PResult<'a, ForeignItem> { - let mutbl = self.parse_mutability(); - let ident = self.parse_ident()?; - self.expect(&token::Colon)?; - let ty = self.parse_ty()?; - let hi = self.token.span; - self.expect(&token::Semi)?; - Ok(ForeignItem { - ident, - attrs, - node: ForeignItemKind::Static(ty, mutbl), - id: ast::DUMMY_NODE_ID, - span: lo.to(hi), - vis, - }) - } - - /// Parses a type from a foreign module. - fn parse_item_foreign_type(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec) - -> PResult<'a, ForeignItem> { - self.expect_keyword(kw::Type)?; - - let ident = self.parse_ident()?; - let hi = self.token.span; - self.expect(&token::Semi)?; - Ok(ast::ForeignItem { - ident, - attrs, - node: ForeignItemKind::Ty, - id: ast::DUMMY_NODE_ID, - span: lo.to(hi), - vis - }) - } - - fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> { - let error_msg = "crate name using dashes are not valid in `extern crate` statements"; - let suggestion_msg = "if the original crate name uses dashes you need to use underscores \ - in the code"; - let mut ident = if self.token.is_keyword(kw::SelfLower) { - self.parse_path_segment_ident() - } else { - self.parse_ident() - }?; - let mut idents = vec![]; - let mut replacement = vec![]; - let mut fixed_crate_name = false; - // Accept `extern crate name-like-this` for better diagnostics - let dash = token::BinOp(token::BinOpToken::Minus); - if self.token == dash { // Do not include `-` as part of the expected tokens list - while self.eat(&dash) { - fixed_crate_name = true; - replacement.push((self.prev_span, "_".to_string())); - idents.push(self.parse_ident()?); - } - } - if fixed_crate_name { - let fixed_name_sp = ident.span.to(idents.last().unwrap().span); - let mut fixed_name = format!("{}", ident.name); - for part in idents { - fixed_name.push_str(&format!("_{}", part.name)); - } - ident = Ident::from_str(&fixed_name).with_span_pos(fixed_name_sp); - - self.struct_span_err(fixed_name_sp, error_msg) - .span_label(fixed_name_sp, "dash-separated idents are not valid") - .multipart_suggestion(suggestion_msg, replacement, Applicability::MachineApplicable) - .emit(); - } - Ok(ident) - } - - /// Parses `extern crate` links. - /// - /// # Examples - /// - /// ``` - /// extern crate foo; - /// extern crate bar as foo; - /// ``` - fn parse_item_extern_crate(&mut self, - lo: Span, - visibility: Visibility, - attrs: Vec) - -> PResult<'a, P> { - // Accept `extern crate name-like-this` for better diagnostics - let orig_name = self.parse_crate_name_with_dashes()?; - let (item_name, orig_name) = if let Some(rename) = self.parse_rename()? { - (rename, Some(orig_name.name)) - } else { - (orig_name, None) - }; - self.expect(&token::Semi)?; - - let span = lo.to(self.prev_span); - Ok(self.mk_item(span, item_name, ItemKind::ExternCrate(orig_name), visibility, attrs)) - } - - /// Parses `extern` for foreign ABIs modules. - /// - /// `extern` is expected to have been - /// consumed before calling this method. - /// - /// # Examples - /// - /// ```ignore (only-for-syntax-highlight) - /// extern "C" {} - /// extern {} - /// ``` - fn parse_item_foreign_mod( - &mut self, - lo: Span, - opt_abi: Option, - visibility: Visibility, - mut attrs: Vec, - extern_sp: Span, - ) -> PResult<'a, P> { - self.expect(&token::OpenDelim(token::Brace))?; - - let abi = opt_abi.unwrap_or(Abi::C); - - attrs.extend(self.parse_inner_attributes()?); - - let mut foreign_items = vec![]; - while !self.eat(&token::CloseDelim(token::Brace)) { - foreign_items.push(self.parse_foreign_item(extern_sp)?); - } - - let prev_span = self.prev_span; - let m = ast::ForeignMod { - abi, - items: foreign_items - }; - let invalid = Ident::invalid(); - Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs)) - } - - /// Parses `type Foo = Bar;` or returns `None` - /// without modifying the parser state. - fn eat_type(&mut self) -> Option> { - // This parses the grammar: - // Ident ["<"...">"] ["where" ...] ("=" | ":") Ty ";" - if self.eat_keyword(kw::Type) { - Some(self.parse_type_alias()) - } else { - None - } - } - - /// Parses a type alias or opaque type. - fn parse_type_alias(&mut self) -> PResult<'a, (Ident, AliasKind, ast::Generics)> { - let ident = self.parse_ident()?; - let mut tps = self.parse_generics()?; - tps.where_clause = self.parse_where_clause()?; - self.expect(&token::Eq)?; - let alias = if self.check_keyword(kw::Impl) { - self.bump(); - let bounds = self.parse_generic_bounds(Some(self.prev_span))?; - AliasKind::OpaqueTy(bounds) - } else { - let ty = self.parse_ty()?; - AliasKind::Weak(ty) - }; - self.expect(&token::Semi)?; - Ok((ident, alias, tps)) - } - - /// Parses the part of an enum declaration following the `{`. - fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef> { - let mut variants = Vec::new(); - while self.token != token::CloseDelim(token::Brace) { - let variant_attrs = self.parse_outer_attributes()?; - let vlo = self.token.span; - - self.eat_bad_pub(); - let ident = self.parse_ident()?; - - let struct_def = if self.check(&token::OpenDelim(token::Brace)) { - // Parse a struct variant. - let (fields, recovered) = self.parse_record_struct_body()?; - VariantData::Struct(fields, recovered) - } else if self.check(&token::OpenDelim(token::Paren)) { - VariantData::Tuple( - self.parse_tuple_struct_body()?, - ast::DUMMY_NODE_ID, - ) - } else { - VariantData::Unit(ast::DUMMY_NODE_ID) - }; - - let disr_expr = if self.eat(&token::Eq) { - Some(AnonConst { - id: ast::DUMMY_NODE_ID, - value: self.parse_expr()?, - }) - } else { - None - }; - - let vr = ast::Variant_ { - ident, - id: ast::DUMMY_NODE_ID, - attrs: variant_attrs, - data: struct_def, - disr_expr, - }; - variants.push(respan(vlo.to(self.prev_span), vr)); - - if !self.eat(&token::Comma) { - if self.token.is_ident() && !self.token.is_reserved_ident() { - let sp = self.sess.source_map().next_point(self.prev_span); - self.struct_span_err(sp, "missing comma") - .span_suggestion_short( - sp, - "missing comma", - ",".to_owned(), - Applicability::MaybeIncorrect, - ) - .emit(); - } else { - break; - } - } - } - self.expect(&token::CloseDelim(token::Brace))?; - - Ok(ast::EnumDef { variants }) - } - - /// Parses an enum declaration. - fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { - let id = self.parse_ident()?; - let mut generics = self.parse_generics()?; - generics.where_clause = self.parse_where_clause()?; - self.expect(&token::OpenDelim(token::Brace))?; - - let enum_definition = self.parse_enum_def(&generics).map_err(|e| { - self.recover_stmt(); - self.eat(&token::CloseDelim(token::Brace)); - e - })?; - Ok((id, ItemKind::Enum(enum_definition, generics), None)) - } - /// 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> { @@ -4706,489 +3221,6 @@ impl<'a> Parser<'a> { } } - fn is_static_global(&mut self) -> bool { - if self.check_keyword(kw::Static) { - // Check if this could be a closure - !self.look_ahead(1, |token| { - if token.is_keyword(kw::Move) { - return true; - } - match token.kind { - token::BinOp(token::Or) | token::OrOr => true, - _ => false, - } - }) - } else { - false - } - } - - fn parse_item_( - &mut self, - attrs: Vec, - macros_allowed: bool, - attributes_allowed: bool, - ) -> PResult<'a, Option>> { - let mut unclosed_delims = vec![]; - let (ret, tokens) = self.collect_tokens(|this| { - let item = this.parse_item_implementation(attrs, macros_allowed, attributes_allowed); - unclosed_delims.append(&mut this.unclosed_delims); - item - })?; - self.unclosed_delims.append(&mut unclosed_delims); - - // Once we've parsed an item and recorded the tokens we got while - // parsing we may want to store `tokens` into the item we're about to - // return. Note, though, that we specifically didn't capture tokens - // related to outer attributes. The `tokens` field here may later be - // used with procedural macros to convert this item back into a token - // stream, but during expansion we may be removing attributes as we go - // along. - // - // If we've got inner attributes then the `tokens` we've got above holds - // these inner attributes. If an inner attribute is expanded we won't - // actually remove it from the token stream, so we'll just keep yielding - // it (bad!). To work around this case for now we just avoid recording - // `tokens` if we detect any inner attributes. This should help keep - // expansion correct, but we should fix this bug one day! - Ok(ret.map(|item| { - item.map(|mut i| { - if !i.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { - i.tokens = Some(tokens); - } - i - }) - })) - } - - /// Parses one of the items allowed by the flags. - fn parse_item_implementation( - &mut self, - attrs: Vec, - macros_allowed: bool, - attributes_allowed: bool, - ) -> PResult<'a, Option>> { - maybe_whole!(self, NtItem, |item| { - let mut item = item.into_inner(); - let mut attrs = attrs; - mem::swap(&mut item.attrs, &mut attrs); - item.attrs.extend(attrs); - Some(P(item)) - }); - - let lo = self.token.span; - - let visibility = self.parse_visibility(false)?; - - if self.eat_keyword(kw::Use) { - // USE ITEM - let item_ = ItemKind::Use(P(self.parse_use_tree()?)); - self.expect(&token::Semi)?; - - let span = lo.to(self.prev_span); - let item = - self.mk_item(span, Ident::invalid(), item_, visibility, attrs); - return Ok(Some(item)); - } - - if self.eat_keyword(kw::Extern) { - let extern_sp = self.prev_span; - if self.eat_keyword(kw::Crate) { - return Ok(Some(self.parse_item_extern_crate(lo, visibility, attrs)?)); - } - - let opt_abi = self.parse_opt_abi()?; - - if self.eat_keyword(kw::Fn) { - // EXTERN FUNCTION ITEM - let fn_span = self.prev_span; - let abi = opt_abi.unwrap_or(Abi::C); - let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, - respan(fn_span, IsAsync::NotAsync), - respan(fn_span, Constness::NotConst), - abi)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } else if self.check(&token::OpenDelim(token::Brace)) { - return Ok(Some( - self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs, extern_sp)?, - )); - } - - self.unexpected()?; - } - - if self.is_static_global() { - self.bump(); - // STATIC ITEM - let m = if self.eat_keyword(kw::Mut) { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - if self.eat_keyword(kw::Const) { - let const_span = self.prev_span; - if self.check_keyword(kw::Fn) - || (self.check_keyword(kw::Unsafe) - && self.is_keyword_ahead(1, &[kw::Fn])) { - // CONST FUNCTION ITEM - let unsafety = self.parse_unsafety(); - self.bump(); - let (ident, item_, extra_attrs) = - self.parse_item_fn(unsafety, - respan(const_span, IsAsync::NotAsync), - respan(const_span, Constness::Const), - Abi::Rust)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - - // CONST ITEM - if self.eat_keyword(kw::Mut) { - let prev_span = self.prev_span; - self.struct_span_err(prev_span, "const globals cannot be mutable") - .span_label(prev_span, "cannot be mutable") - .span_suggestion( - const_span, - "you might want to declare a static instead", - "static".to_owned(), - Applicability::MaybeIncorrect, - ) - .emit(); - } - let (ident, item_, extra_attrs) = self.parse_item_const(None)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - - // Parse `async unsafe? fn`. - if self.check_keyword(kw::Async) { - let async_span = self.token.span; - if self.is_keyword_ahead(1, &[kw::Fn]) - || self.is_keyword_ahead(2, &[kw::Fn]) - { - // ASYNC FUNCTION ITEM - self.bump(); // `async` - let unsafety = self.parse_unsafety(); // `unsafe`? - self.expect_keyword(kw::Fn)?; // `fn` - let fn_span = self.prev_span; - let (ident, item_, extra_attrs) = - self.parse_item_fn(unsafety, - respan(async_span, IsAsync::Async { - closure_id: ast::DUMMY_NODE_ID, - return_impl_trait_id: ast::DUMMY_NODE_ID, - }), - respan(fn_span, Constness::NotConst), - Abi::Rust)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - self.ban_async_in_2015(async_span); - return Ok(Some(item)); - } - } - if self.check_keyword(kw::Unsafe) && - self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) - { - // UNSAFE TRAIT ITEM - self.bump(); // `unsafe` - let is_auto = if self.eat_keyword(kw::Trait) { - IsAuto::No - } else { - self.expect_keyword(kw::Auto)?; - self.expect_keyword(kw::Trait)?; - IsAuto::Yes - }; - let (ident, item_, extra_attrs) = - self.parse_item_trait(is_auto, Unsafety::Unsafe)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - if self.check_keyword(kw::Impl) || - self.check_keyword(kw::Unsafe) && - self.is_keyword_ahead(1, &[kw::Impl]) || - self.check_keyword(kw::Default) && - self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe]) { - // IMPL ITEM - let defaultness = self.parse_defaultness(); - let unsafety = self.parse_unsafety(); - self.expect_keyword(kw::Impl)?; - let (ident, item, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?; - let span = lo.to(self.prev_span); - return Ok(Some(self.mk_item(span, ident, item, visibility, - maybe_append(attrs, extra_attrs)))); - } - if self.check_keyword(kw::Fn) { - // FUNCTION ITEM - self.bump(); - let fn_span = self.prev_span; - let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, - respan(fn_span, IsAsync::NotAsync), - respan(fn_span, Constness::NotConst), - Abi::Rust)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - if self.check_keyword(kw::Unsafe) - && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { - // UNSAFE FUNCTION ITEM - self.bump(); // `unsafe` - // `{` is also expected after `unsafe`, in case of error, include it in the diagnostic - self.check(&token::OpenDelim(token::Brace)); - let abi = if self.eat_keyword(kw::Extern) { - self.parse_opt_abi()?.unwrap_or(Abi::C) - } else { - Abi::Rust - }; - self.expect_keyword(kw::Fn)?; - let fn_span = self.prev_span; - let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Unsafe, - respan(fn_span, IsAsync::NotAsync), - respan(fn_span, Constness::NotConst), - abi)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - if self.eat_keyword(kw::Mod) { - // MODULE ITEM - let (ident, item_, extra_attrs) = - self.parse_item_mod(&attrs[..])?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - if let Some(type_) = self.eat_type() { - let (ident, alias, generics) = type_?; - // TYPE ITEM - let item_ = match alias { - AliasKind::Weak(ty) => ItemKind::TyAlias(ty, generics), - AliasKind::OpaqueTy(bounds) => ItemKind::OpaqueTy(bounds, generics), - }; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - attrs); - return Ok(Some(item)); - } - if self.eat_keyword(kw::Enum) { - // ENUM ITEM - let (ident, item_, extra_attrs) = self.parse_item_enum()?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - if self.check_keyword(kw::Trait) - || (self.check_keyword(kw::Auto) - && self.is_keyword_ahead(1, &[kw::Trait])) - { - let is_auto = if self.eat_keyword(kw::Trait) { - IsAuto::No - } else { - self.expect_keyword(kw::Auto)?; - self.expect_keyword(kw::Trait)?; - IsAuto::Yes - }; - // TRAIT ITEM - let (ident, item_, extra_attrs) = - self.parse_item_trait(is_auto, Unsafety::Normal)?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - if self.eat_keyword(kw::Struct) { - // STRUCT ITEM - let (ident, item_, extra_attrs) = self.parse_item_struct()?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - if self.is_union_item() { - // UNION ITEM - self.bump(); - let (ident, item_, extra_attrs) = self.parse_item_union()?; - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - item_, - visibility, - maybe_append(attrs, extra_attrs)); - return Ok(Some(item)); - } - if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility, lo)? { - return Ok(Some(macro_def)); - } - - // Verify whether we have encountered a struct or method definition where the user forgot to - // add the `struct` or `fn` keyword after writing `pub`: `pub S {}` - if visibility.node.is_pub() && - self.check_ident() && - self.look_ahead(1, |t| *t != token::Not) - { - // Space between `pub` keyword and the identifier - // - // pub S {} - // ^^^ `sp` points here - let sp = self.prev_span.between(self.token.span); - let full_sp = self.prev_span.to(self.token.span); - let ident_sp = self.token.span; - if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) { - // possible public struct definition where `struct` was forgotten - let ident = self.parse_ident().unwrap(); - let msg = format!("add `struct` here to parse `{}` as a public struct", - ident); - let mut err = self.diagnostic() - .struct_span_err(sp, "missing `struct` for struct definition"); - err.span_suggestion_short( - sp, &msg, " struct ".into(), Applicability::MaybeIncorrect // speculative - ); - return Err(err); - } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { - let ident = self.parse_ident().unwrap(); - self.bump(); // `(` - let kw_name = if let Ok(Some(_)) = self.parse_self_arg_with_attrs() - .map_err(|mut e| e.cancel()) - { - "method" - } else { - "function" - }; - self.consume_block(token::Paren); - let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) { - self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]); - self.bump(); // `{` - ("fn", kw_name, false) - } else if self.check(&token::OpenDelim(token::Brace)) { - self.bump(); // `{` - ("fn", kw_name, false) - } else if self.check(&token::Colon) { - let kw = "struct"; - (kw, kw, false) - } else { - ("fn` or `struct", "function or struct", true) - }; - - let msg = format!("missing `{}` for {} definition", kw, kw_name); - let mut err = self.diagnostic().struct_span_err(sp, &msg); - if !ambiguous { - self.consume_block(token::Brace); - let suggestion = format!("add `{}` here to parse `{}` as a public {}", - kw, - ident, - kw_name); - err.span_suggestion_short( - sp, &suggestion, format!(" {} ", kw), Applicability::MachineApplicable - ); - } else { - if let Ok(snippet) = self.span_to_snippet(ident_sp) { - err.span_suggestion( - full_sp, - "if you meant to call a macro, try", - format!("{}!", snippet), - // this is the `ambiguous` conditional branch - Applicability::MaybeIncorrect - ); - } else { - err.help("if you meant to call a macro, remove the `pub` \ - and add a trailing `!` after the identifier"); - } - } - return Err(err); - } else if self.look_ahead(1, |t| *t == token::Lt) { - let ident = self.parse_ident().unwrap(); - self.eat_to_tokens(&[&token::Gt]); - self.bump(); // `>` - let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) { - if let Ok(Some(_)) = self.parse_self_arg_with_attrs() - .map_err(|mut e| e.cancel()) - { - ("fn", "method", false) - } else { - ("fn", "function", false) - } - } else if self.check(&token::OpenDelim(token::Brace)) { - ("struct", "struct", false) - } else { - ("fn` or `struct", "function or struct", true) - }; - let msg = format!("missing `{}` for {} definition", kw, kw_name); - let mut err = self.diagnostic().struct_span_err(sp, &msg); - if !ambiguous { - err.span_suggestion_short( - sp, - &format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name), - format!(" {} ", kw), - Applicability::MachineApplicable, - ); - } - return Err(err); - } - } - self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility) - } - /// 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() { @@ -5202,155 +3234,6 @@ impl<'a> Parser<'a> { } } - /// Parses a foreign item. - crate fn parse_foreign_item(&mut self, extern_sp: Span) -> PResult<'a, ForeignItem> { - maybe_whole!(self, NtForeignItem, |ni| ni); - - let attrs = self.parse_outer_attributes()?; - let lo = self.token.span; - let visibility = self.parse_visibility(false)?; - - // FOREIGN STATIC ITEM - // Treat `const` as `static` for error recovery, but don't add it to expected tokens. - if self.check_keyword(kw::Static) || self.token.is_keyword(kw::Const) { - if self.token.is_keyword(kw::Const) { - self.diagnostic() - .struct_span_err(self.token.span, "extern items cannot be `const`") - .span_suggestion( - self.token.span, - "try using a static value", - "static".to_owned(), - Applicability::MachineApplicable - ).emit(); - } - self.bump(); // `static` or `const` - return Ok(self.parse_item_foreign_static(visibility, lo, attrs)?); - } - // FOREIGN FUNCTION ITEM - if self.check_keyword(kw::Fn) { - return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?); - } - // FOREIGN TYPE ITEM - if self.check_keyword(kw::Type) { - return Ok(self.parse_item_foreign_type(visibility, lo, attrs)?); - } - - match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? { - Some(mac) => { - Ok( - ForeignItem { - ident: Ident::invalid(), - span: lo.to(self.prev_span), - id: ast::DUMMY_NODE_ID, - attrs, - vis: visibility, - node: ForeignItemKind::Macro(mac), - } - ) - } - None => { - if !attrs.is_empty() { - self.expected_item_err(&attrs)?; - } - - self.unexpected() - } - } - } - - /// This is the fall-through for parsing items. - fn parse_macro_use_or_failure( - &mut self, - attrs: Vec , - macros_allowed: bool, - attributes_allowed: bool, - lo: Span, - visibility: Visibility - ) -> PResult<'a, Option>> { - if macros_allowed && self.token.is_path_start() && - !(self.is_async_fn() && self.token.span.rust_2015()) { - // MACRO INVOCATION ITEM - - let prev_span = self.prev_span; - self.complain_if_pub_macro(&visibility.node, prev_span); - - let mac_lo = self.token.span; - - // item macro. - let path = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; - let (delim, tts) = self.expect_delimited_token_tree()?; - if delim != MacDelimiter::Brace && !self.eat(&token::Semi) { - self.report_invalid_macro_expansion_item(); - } - - let hi = self.prev_span; - let mac = respan(mac_lo.to(hi), Mac_ { - path, - tts, - delim, - prior_type_ascription: self.last_type_ascription, - }); - let item = - self.mk_item(lo.to(hi), Ident::invalid(), ItemKind::Mac(mac), visibility, attrs); - return Ok(Some(item)); - } - - // FAILURE TO PARSE ITEM - match visibility.node { - VisibilityKind::Inherited => {} - _ => { - return Err(self.span_fatal(self.prev_span, "unmatched visibility `pub`")); - } - } - - if !attributes_allowed && !attrs.is_empty() { - self.expected_item_err(&attrs)?; - } - Ok(None) - } - - /// Parses a macro invocation inside a `trait`, `impl` or `extern` block. - fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>, - at_end: &mut bool) -> PResult<'a, Option> - { - if self.token.is_path_start() && - !(self.is_async_fn() && self.token.span.rust_2015()) { - let prev_span = self.prev_span; - let lo = self.token.span; - let path = self.parse_path(PathStyle::Mod)?; - - if path.segments.len() == 1 { - if !self.eat(&token::Not) { - return Err(self.missing_assoc_item_kind_err(item_kind, prev_span)); - } - } else { - self.expect(&token::Not)?; - } - - if let Some(vis) = vis { - self.complain_if_pub_macro(&vis.node, prev_span); - } - - *at_end = true; - - // eat a matched-delimiter token tree: - let (delim, tts) = self.expect_delimited_token_tree()?; - if delim != MacDelimiter::Brace { - self.expect(&token::Semi)?; - } - - Ok(Some(respan(lo.to(self.prev_span), Mac_ { - path, - tts, - delim, - prior_type_ascription: self.last_type_ascription, - }))) - } else { - Ok(None) - } - } - fn collect_tokens(&mut self, f: F) -> PResult<'a, (R, TokenStream)> where F: FnOnce(&mut Self) -> PResult<'a, R> { @@ -5420,11 +3303,6 @@ impl<'a> Parser<'a> { Ok((ret?, TokenStream::new(collected_tokens))) } - pub fn parse_item(&mut self) -> PResult<'a, Option>> { - let attrs = self.parse_outer_attributes()?; - self.parse_item_(attrs, true, false) - } - /// `::{` or `::*` fn is_import_coupler(&mut self) -> bool { self.check(&token::ModSep) && @@ -5432,82 +3310,6 @@ impl<'a> Parser<'a> { *t == token::BinOp(token::Star)) } - /// Parses a `UseTree`. - /// - /// ``` - /// USE_TREE = [`::`] `*` | - /// [`::`] `{` USE_TREE_LIST `}` | - /// PATH `::` `*` | - /// PATH `::` `{` USE_TREE_LIST `}` | - /// PATH [`as` IDENT] - /// ``` - fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { - let lo = self.token.span; - - let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo() }; - let kind = if self.check(&token::OpenDelim(token::Brace)) || - self.check(&token::BinOp(token::Star)) || - self.is_import_coupler() { - // `use *;` or `use ::*;` or `use {...};` or `use ::{...};` - let mod_sep_ctxt = self.token.span.ctxt(); - if self.eat(&token::ModSep) { - prefix.segments.push( - PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)) - ); - } - - if self.eat(&token::BinOp(token::Star)) { - UseTreeKind::Glob - } else { - UseTreeKind::Nested(self.parse_use_tree_list()?) - } - } else { - // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;` - prefix = self.parse_path(PathStyle::Mod)?; - - if self.eat(&token::ModSep) { - if self.eat(&token::BinOp(token::Star)) { - UseTreeKind::Glob - } else { - UseTreeKind::Nested(self.parse_use_tree_list()?) - } - } else { - UseTreeKind::Simple(self.parse_rename()?, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID) - } - }; - - Ok(UseTree { prefix, kind, span: lo.to(self.prev_span) }) - } - - /// Parses a `UseTreeKind::Nested(list)`. - /// - /// ``` - /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`] - /// ``` - fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> { - self.parse_delim_comma_seq(token::Brace, |p| Ok((p.parse_use_tree()?, ast::DUMMY_NODE_ID))) - .map(|(r, _)| r) - } - - fn parse_rename(&mut self) -> PResult<'a, Option> { - if self.eat_keyword(kw::As) { - self.parse_ident_or_underscore().map(Some) - } else { - Ok(None) - } - } - - /// Parses a source module as a crate. This is the main entry point for the parser. - pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> { - let lo = self.token.span; - let krate = Ok(ast::Crate { - attrs: self.parse_inner_attributes()?, - module: self.parse_mod_items(&token::Eof, lo)?, - span: lo.to(self.token.span), - }); - krate - } - pub fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option)> { let ret = match self.token.kind { token::Literal(token::Lit { kind: token::Str, symbol, suffix }) => diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs new file mode 100644 index 00000000000..5e264a0ca77 --- /dev/null +++ b/src/libsyntax/parse/parser/item.rs @@ -0,0 +1,1899 @@ +use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode}; + +use crate::maybe_whole; +use crate::ptr::P; +use crate::ast::{self, Ident, Attribute, AttrStyle}; +use crate::ast::{Item, ItemKind, ImplItem, TraitItem, TraitItemKind}; +use crate::ast::{UseTree, UseTreeKind, PathSegment}; +use crate::ast::{IsAuto, Constness, IsAsync, Unsafety, Defaultness}; +use crate::ast::{Visibility, VisibilityKind, Mutability, FnDecl, FnHeader}; +use crate::ast::{ForeignItem, ForeignItemKind}; +use crate::ast::{Ty, TyKind, GenericBounds, TraitRef}; +use crate::ast::{EnumDef, VariantData, StructField, AnonConst}; +use crate::ast::{Mac, Mac_, MacDelimiter}; +use crate::ext::base::DummyResult; +use crate::parse::token; +use crate::parse::parser::maybe_append; +use crate::parse::diagnostics::{Error}; +use crate::tokenstream::{TokenTree, TokenStream}; +use crate::source_map::{respan, Span, Spanned}; +use crate::symbol::{kw, sym}; + +use std::mem; +use log::debug; +use rustc_target::spec::abi::{Abi}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; + +/// Whether the type alias or associated type is a concrete type or an opaque type +#[derive(Debug)] +pub enum AliasKind { + /// Just a new name for the same type + Weak(P), + /// Only trait impls of the type will be usable, not the actual type itself + OpaqueTy(GenericBounds), +} + +pub(super) type ItemInfo = (Ident, ItemKind, Option>); + +impl<'a> Parser<'a> { + pub fn parse_item(&mut self) -> PResult<'a, Option>> { + let attrs = self.parse_outer_attributes()?; + self.parse_item_(attrs, true, false) + } + + pub(super) fn parse_item_( + &mut self, + attrs: Vec, + macros_allowed: bool, + attributes_allowed: bool, + ) -> PResult<'a, Option>> { + let mut unclosed_delims = vec![]; + let (ret, tokens) = self.collect_tokens(|this| { + let item = this.parse_item_implementation(attrs, macros_allowed, attributes_allowed); + unclosed_delims.append(&mut this.unclosed_delims); + item + })?; + self.unclosed_delims.append(&mut unclosed_delims); + + // Once we've parsed an item and recorded the tokens we got while + // parsing we may want to store `tokens` into the item we're about to + // return. Note, though, that we specifically didn't capture tokens + // related to outer attributes. The `tokens` field here may later be + // used with procedural macros to convert this item back into a token + // stream, but during expansion we may be removing attributes as we go + // along. + // + // If we've got inner attributes then the `tokens` we've got above holds + // these inner attributes. If an inner attribute is expanded we won't + // actually remove it from the token stream, so we'll just keep yielding + // it (bad!). To work around this case for now we just avoid recording + // `tokens` if we detect any inner attributes. This should help keep + // expansion correct, but we should fix this bug one day! + Ok(ret.map(|item| { + item.map(|mut i| { + if !i.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { + i.tokens = Some(tokens); + } + i + }) + })) + } + + /// Parses one of the items allowed by the flags. + fn parse_item_implementation( + &mut self, + attrs: Vec, + macros_allowed: bool, + attributes_allowed: bool, + ) -> PResult<'a, Option>> { + maybe_whole!(self, NtItem, |item| { + let mut item = item.into_inner(); + let mut attrs = attrs; + mem::swap(&mut item.attrs, &mut attrs); + item.attrs.extend(attrs); + Some(P(item)) + }); + + let lo = self.token.span; + + let visibility = self.parse_visibility(false)?; + + if self.eat_keyword(kw::Use) { + // USE ITEM + let item_ = ItemKind::Use(P(self.parse_use_tree()?)); + self.expect(&token::Semi)?; + + let span = lo.to(self.prev_span); + let item = + self.mk_item(span, Ident::invalid(), item_, visibility, attrs); + return Ok(Some(item)); + } + + if self.eat_keyword(kw::Extern) { + let extern_sp = self.prev_span; + if self.eat_keyword(kw::Crate) { + return Ok(Some(self.parse_item_extern_crate(lo, visibility, attrs)?)); + } + + let opt_abi = self.parse_opt_abi()?; + + if self.eat_keyword(kw::Fn) { + // EXTERN FUNCTION ITEM + let fn_span = self.prev_span; + let abi = opt_abi.unwrap_or(Abi::C); + let (ident, item_, extra_attrs) = + self.parse_item_fn(Unsafety::Normal, + respan(fn_span, IsAsync::NotAsync), + respan(fn_span, Constness::NotConst), + abi)?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } else if self.check(&token::OpenDelim(token::Brace)) { + return Ok(Some( + self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs, extern_sp)?, + )); + } + + self.unexpected()?; + } + + if self.is_static_global() { + self.bump(); + // STATIC ITEM + let m = self.parse_mutability(); + let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + if self.eat_keyword(kw::Const) { + let const_span = self.prev_span; + if self.check_keyword(kw::Fn) + || (self.check_keyword(kw::Unsafe) + && self.is_keyword_ahead(1, &[kw::Fn])) { + // CONST FUNCTION ITEM + let unsafety = self.parse_unsafety(); + self.bump(); + let (ident, item_, extra_attrs) = + self.parse_item_fn(unsafety, + respan(const_span, IsAsync::NotAsync), + respan(const_span, Constness::Const), + Abi::Rust)?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + + // CONST ITEM + if self.eat_keyword(kw::Mut) { + let prev_span = self.prev_span; + self.struct_span_err(prev_span, "const globals cannot be mutable") + .span_label(prev_span, "cannot be mutable") + .span_suggestion( + const_span, + "you might want to declare a static instead", + "static".to_owned(), + Applicability::MaybeIncorrect, + ) + .emit(); + } + let (ident, item_, extra_attrs) = self.parse_item_const(None)?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + + // Parse `async unsafe? fn`. + if self.check_keyword(kw::Async) { + let async_span = self.token.span; + if self.is_keyword_ahead(1, &[kw::Fn]) + || self.is_keyword_ahead(2, &[kw::Fn]) + { + // ASYNC FUNCTION ITEM + self.bump(); // `async` + let unsafety = self.parse_unsafety(); // `unsafe`? + self.expect_keyword(kw::Fn)?; // `fn` + let fn_span = self.prev_span; + let (ident, item_, extra_attrs) = + self.parse_item_fn(unsafety, + respan(async_span, IsAsync::Async { + closure_id: ast::DUMMY_NODE_ID, + return_impl_trait_id: ast::DUMMY_NODE_ID, + }), + respan(fn_span, Constness::NotConst), + Abi::Rust)?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + self.ban_async_in_2015(async_span); + return Ok(Some(item)); + } + } + if self.check_keyword(kw::Unsafe) && + self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) + { + // UNSAFE TRAIT ITEM + self.bump(); // `unsafe` + let is_auto = if self.eat_keyword(kw::Trait) { + IsAuto::No + } else { + self.expect_keyword(kw::Auto)?; + self.expect_keyword(kw::Trait)?; + IsAuto::Yes + }; + let (ident, item_, extra_attrs) = + self.parse_item_trait(is_auto, Unsafety::Unsafe)?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + if self.check_keyword(kw::Impl) || + self.check_keyword(kw::Unsafe) && + self.is_keyword_ahead(1, &[kw::Impl]) || + self.check_keyword(kw::Default) && + self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe]) { + // IMPL ITEM + let defaultness = self.parse_defaultness(); + let unsafety = self.parse_unsafety(); + self.expect_keyword(kw::Impl)?; + let (ident, item, extra_attrs) = self.parse_item_impl(unsafety, defaultness)?; + let span = lo.to(self.prev_span); + return Ok(Some(self.mk_item(span, ident, item, visibility, + maybe_append(attrs, extra_attrs)))); + } + if self.check_keyword(kw::Fn) { + // FUNCTION ITEM + self.bump(); + let fn_span = self.prev_span; + let (ident, item_, extra_attrs) = + self.parse_item_fn(Unsafety::Normal, + respan(fn_span, IsAsync::NotAsync), + respan(fn_span, Constness::NotConst), + Abi::Rust)?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + if self.check_keyword(kw::Unsafe) + && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { + // UNSAFE FUNCTION ITEM + self.bump(); // `unsafe` + // `{` is also expected after `unsafe`, in case of error, include it in the diagnostic + self.check(&token::OpenDelim(token::Brace)); + let abi = if self.eat_keyword(kw::Extern) { + self.parse_opt_abi()?.unwrap_or(Abi::C) + } else { + Abi::Rust + }; + self.expect_keyword(kw::Fn)?; + let fn_span = self.prev_span; + let (ident, item_, extra_attrs) = + self.parse_item_fn(Unsafety::Unsafe, + respan(fn_span, IsAsync::NotAsync), + respan(fn_span, Constness::NotConst), + abi)?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + if self.eat_keyword(kw::Mod) { + // MODULE ITEM + let (ident, item_, extra_attrs) = + self.parse_item_mod(&attrs[..])?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + if let Some(type_) = self.eat_type() { + let (ident, alias, generics) = type_?; + // TYPE ITEM + let item_ = match alias { + AliasKind::Weak(ty) => ItemKind::TyAlias(ty, generics), + AliasKind::OpaqueTy(bounds) => ItemKind::OpaqueTy(bounds, generics), + }; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + attrs); + return Ok(Some(item)); + } + if self.eat_keyword(kw::Enum) { + // ENUM ITEM + let (ident, item_, extra_attrs) = self.parse_item_enum()?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + if self.check_keyword(kw::Trait) + || (self.check_keyword(kw::Auto) + && self.is_keyword_ahead(1, &[kw::Trait])) + { + let is_auto = if self.eat_keyword(kw::Trait) { + IsAuto::No + } else { + self.expect_keyword(kw::Auto)?; + self.expect_keyword(kw::Trait)?; + IsAuto::Yes + }; + // TRAIT ITEM + let (ident, item_, extra_attrs) = + self.parse_item_trait(is_auto, Unsafety::Normal)?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + if self.eat_keyword(kw::Struct) { + // STRUCT ITEM + let (ident, item_, extra_attrs) = self.parse_item_struct()?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + if self.is_union_item() { + // UNION ITEM + self.bump(); + let (ident, item_, extra_attrs) = self.parse_item_union()?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } + if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility, lo)? { + return Ok(Some(macro_def)); + } + + // Verify whether we have encountered a struct or method definition where the user forgot to + // add the `struct` or `fn` keyword after writing `pub`: `pub S {}` + if visibility.node.is_pub() && + self.check_ident() && + self.look_ahead(1, |t| *t != token::Not) + { + // Space between `pub` keyword and the identifier + // + // pub S {} + // ^^^ `sp` points here + let sp = self.prev_span.between(self.token.span); + let full_sp = self.prev_span.to(self.token.span); + let ident_sp = self.token.span; + if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) { + // possible public struct definition where `struct` was forgotten + let ident = self.parse_ident().unwrap(); + let msg = format!("add `struct` here to parse `{}` as a public struct", + ident); + let mut err = self.diagnostic() + .struct_span_err(sp, "missing `struct` for struct definition"); + err.span_suggestion_short( + sp, &msg, " struct ".into(), Applicability::MaybeIncorrect // speculative + ); + return Err(err); + } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { + let ident = self.parse_ident().unwrap(); + self.bump(); // `(` + let kw_name = if let Ok(Some(_)) = self.parse_self_arg_with_attrs() + .map_err(|mut e| e.cancel()) + { + "method" + } else { + "function" + }; + self.consume_block(token::Paren); + let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) { + self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]); + self.bump(); // `{` + ("fn", kw_name, false) + } else if self.check(&token::OpenDelim(token::Brace)) { + self.bump(); // `{` + ("fn", kw_name, false) + } else if self.check(&token::Colon) { + let kw = "struct"; + (kw, kw, false) + } else { + ("fn` or `struct", "function or struct", true) + }; + + let msg = format!("missing `{}` for {} definition", kw, kw_name); + let mut err = self.diagnostic().struct_span_err(sp, &msg); + if !ambiguous { + self.consume_block(token::Brace); + let suggestion = format!("add `{}` here to parse `{}` as a public {}", + kw, + ident, + kw_name); + err.span_suggestion_short( + sp, &suggestion, format!(" {} ", kw), Applicability::MachineApplicable + ); + } else { + if let Ok(snippet) = self.span_to_snippet(ident_sp) { + err.span_suggestion( + full_sp, + "if you meant to call a macro, try", + format!("{}!", snippet), + // this is the `ambiguous` conditional branch + Applicability::MaybeIncorrect + ); + } else { + err.help("if you meant to call a macro, remove the `pub` \ + and add a trailing `!` after the identifier"); + } + } + return Err(err); + } else if self.look_ahead(1, |t| *t == token::Lt) { + let ident = self.parse_ident().unwrap(); + self.eat_to_tokens(&[&token::Gt]); + self.bump(); // `>` + let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) { + if let Ok(Some(_)) = self.parse_self_arg_with_attrs() + .map_err(|mut e| e.cancel()) + { + ("fn", "method", false) + } else { + ("fn", "function", false) + } + } else if self.check(&token::OpenDelim(token::Brace)) { + ("struct", "struct", false) + } else { + ("fn` or `struct", "function or struct", true) + }; + let msg = format!("missing `{}` for {} definition", kw, kw_name); + let mut err = self.diagnostic().struct_span_err(sp, &msg); + if !ambiguous { + err.span_suggestion_short( + sp, + &format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name), + format!(" {} ", kw), + Applicability::MachineApplicable, + ); + } + return Err(err); + } + } + self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility) + } + + /// This is the fall-through for parsing items. + fn parse_macro_use_or_failure( + &mut self, + attrs: Vec , + macros_allowed: bool, + attributes_allowed: bool, + lo: Span, + visibility: Visibility + ) -> PResult<'a, Option>> { + if macros_allowed && self.token.is_path_start() && + !(self.is_async_fn() && self.token.span.rust_2015()) { + // MACRO INVOCATION ITEM + + let prev_span = self.prev_span; + self.complain_if_pub_macro(&visibility.node, prev_span); + + let mac_lo = self.token.span; + + // item macro. + let path = self.parse_path(PathStyle::Mod)?; + self.expect(&token::Not)?; + let (delim, tts) = self.expect_delimited_token_tree()?; + if delim != MacDelimiter::Brace && !self.eat(&token::Semi) { + self.report_invalid_macro_expansion_item(); + } + + let hi = self.prev_span; + let mac = respan(mac_lo.to(hi), Mac_ { + path, + tts, + delim, + prior_type_ascription: self.last_type_ascription, + }); + let item = + self.mk_item(lo.to(hi), Ident::invalid(), ItemKind::Mac(mac), visibility, attrs); + return Ok(Some(item)); + } + + // FAILURE TO PARSE ITEM + match visibility.node { + VisibilityKind::Inherited => {} + _ => { + return Err(self.span_fatal(self.prev_span, "unmatched visibility `pub`")); + } + } + + if !attributes_allowed && !attrs.is_empty() { + self.expected_item_err(&attrs)?; + } + Ok(None) + } + + /// Emits an expected-item-after-attributes error. + fn expected_item_err(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> { + let message = match attrs.last() { + Some(&Attribute { is_sugared_doc: true, .. }) => "expected item after doc comment", + _ => "expected item after attributes", + }; + + let mut err = self.diagnostic().struct_span_err(self.prev_span, message); + if attrs.last().unwrap().is_sugared_doc { + err.span_label(self.prev_span, "this doc comment doesn't document anything"); + } + Err(err) + } + + /// Parses a macro invocation inside a `trait`, `impl` or `extern` block. + fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>, + at_end: &mut bool) -> PResult<'a, Option> + { + if self.token.is_path_start() && + !(self.is_async_fn() && self.token.span.rust_2015()) { + let prev_span = self.prev_span; + let lo = self.token.span; + let path = self.parse_path(PathStyle::Mod)?; + + if path.segments.len() == 1 { + if !self.eat(&token::Not) { + return Err(self.missing_assoc_item_kind_err(item_kind, prev_span)); + } + } else { + self.expect(&token::Not)?; + } + + if let Some(vis) = vis { + self.complain_if_pub_macro(&vis.node, prev_span); + } + + *at_end = true; + + // eat a matched-delimiter token tree: + let (delim, tts) = self.expect_delimited_token_tree()?; + if delim != MacDelimiter::Brace { + self.expect(&token::Semi)?; + } + + Ok(Some(respan(lo.to(self.prev_span), Mac_ { + path, + tts, + delim, + prior_type_ascription: self.last_type_ascription, + }))) + } else { + Ok(None) + } + } + + fn missing_assoc_item_kind_err(&self, item_type: &str, prev_span: Span) + -> DiagnosticBuilder<'a> + { + let expected_kinds = if item_type == "extern" { + "missing `fn`, `type`, or `static`" + } else { + "missing `fn`, `type`, or `const`" + }; + + // Given this code `path(`, it seems like this is not + // setting the visibility of a macro invocation, but rather + // a mistyped method declaration. + // Create a diagnostic pointing out that `fn` is missing. + // + // x | pub path(&self) { + // | ^ missing `fn`, `type`, or `const` + // pub path( + // ^^ `sp` below will point to this + let sp = prev_span.between(self.prev_span); + let mut err = self.diagnostic().struct_span_err( + sp, + &format!("{} for {}-item declaration", + expected_kinds, item_type)); + err.span_label(sp, expected_kinds); + err + } + + /// Parses an implementation item, `impl` keyword is already parsed. + /// + /// impl<'a, T> TYPE { /* impl items */ } + /// impl<'a, T> TRAIT for TYPE { /* impl items */ } + /// impl<'a, T> !TRAIT for TYPE { /* impl items */ } + /// + /// We actually parse slightly more relaxed grammar for better error reporting and recovery. + /// `impl` GENERICS `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}` + /// `impl` GENERICS `!`? TYPE (`where` PREDICATES)? `{` BODY `}` + fn parse_item_impl(&mut self, unsafety: Unsafety, defaultness: Defaultness) + -> PResult<'a, ItemInfo> { + // First, parse generic parameters if necessary. + let mut generics = if self.choose_generics_over_qpath() { + self.parse_generics()? + } else { + ast::Generics::default() + }; + + // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. + let polarity = if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) { + self.bump(); // `!` + ast::ImplPolarity::Negative + } else { + ast::ImplPolarity::Positive + }; + + // Parse both types and traits as a type, then reinterpret if necessary. + let err_path = |span| ast::Path::from_ident(Ident::new(kw::Invalid, span)); + let ty_first = if self.token.is_keyword(kw::For) && + self.look_ahead(1, |t| t != &token::Lt) { + let span = self.prev_span.between(self.token.span); + self.struct_span_err(span, "missing trait in a trait impl").emit(); + P(Ty { node: TyKind::Path(None, err_path(span)), span, id: ast::DUMMY_NODE_ID }) + } else { + self.parse_ty()? + }; + + // If `for` is missing we try to recover. + let has_for = self.eat_keyword(kw::For); + let missing_for_span = self.prev_span.between(self.token.span); + + let ty_second = if self.token == token::DotDot { + // We need to report this error after `cfg` expansion for compatibility reasons + self.bump(); // `..`, do not add it to expected tokens + Some(DummyResult::raw_ty(self.prev_span, true)) + } else if has_for || self.token.can_begin_type() { + Some(self.parse_ty()?) + } else { + None + }; + + generics.where_clause = self.parse_where_clause()?; + + let (impl_items, attrs) = self.parse_impl_body()?; + + let item_kind = match ty_second { + Some(ty_second) => { + // impl Trait for Type + if !has_for { + self.struct_span_err(missing_for_span, "missing `for` in a trait impl") + .span_suggestion_short( + missing_for_span, + "add `for` here", + " for ".to_string(), + Applicability::MachineApplicable, + ).emit(); + } + + let ty_first = ty_first.into_inner(); + let path = match ty_first.node { + // This notably includes paths passed through `ty` macro fragments (#46438). + TyKind::Path(None, path) => path, + _ => { + self.span_err(ty_first.span, "expected a trait, found type"); + err_path(ty_first.span) + } + }; + let trait_ref = TraitRef { path, ref_id: ty_first.id }; + + ItemKind::Impl(unsafety, polarity, defaultness, + generics, Some(trait_ref), ty_second, impl_items) + } + None => { + // impl Type + ItemKind::Impl(unsafety, polarity, defaultness, + generics, None, ty_first, impl_items) + } + }; + + Ok((Ident::invalid(), item_kind, Some(attrs))) + } + + fn parse_impl_body(&mut self) -> PResult<'a, (Vec, Vec)> { + self.expect(&token::OpenDelim(token::Brace))?; + let attrs = self.parse_inner_attributes()?; + + let mut impl_items = Vec::new(); + while !self.eat(&token::CloseDelim(token::Brace)) { + let mut at_end = false; + match self.parse_impl_item(&mut at_end) { + Ok(impl_item) => impl_items.push(impl_item), + Err(mut err) => { + err.emit(); + if !at_end { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + } + } + } + } + Ok((impl_items, attrs)) + } + + /// Parses an impl item. + pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> { + maybe_whole!(self, NtImplItem, |x| x); + let attrs = self.parse_outer_attributes()?; + let mut unclosed_delims = vec![]; + let (mut item, tokens) = self.collect_tokens(|this| { + let item = this.parse_impl_item_(at_end, attrs); + unclosed_delims.append(&mut this.unclosed_delims); + item + })?; + self.unclosed_delims.append(&mut unclosed_delims); + + // See `parse_item` for why this clause is here. + if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { + item.tokens = Some(tokens); + } + Ok(item) + } + + fn parse_impl_item_(&mut self, + at_end: &mut bool, + mut attrs: Vec) -> PResult<'a, ImplItem> { + let lo = self.token.span; + let vis = self.parse_visibility(false)?; + let defaultness = self.parse_defaultness(); + let (name, node, generics) = if let Some(type_) = self.eat_type() { + let (name, alias, generics) = type_?; + let kind = match alias { + AliasKind::Weak(typ) => ast::ImplItemKind::TyAlias(typ), + AliasKind::OpaqueTy(bounds) => ast::ImplItemKind::OpaqueTy(bounds), + }; + (name, kind, generics) + } else if self.is_const_item() { + // This parses the grammar: + // ImplItemConst = "const" Ident ":" Ty "=" Expr ";" + self.expect_keyword(kw::Const)?; + let name = self.parse_ident()?; + self.expect(&token::Colon)?; + let typ = self.parse_ty()?; + self.expect(&token::Eq)?; + let expr = self.parse_expr()?; + self.expect(&token::Semi)?; + (name, ast::ImplItemKind::Const(typ, expr), ast::Generics::default()) + } else { + let (name, inner_attrs, generics, node) = self.parse_impl_method(&vis, at_end)?; + attrs.extend(inner_attrs); + (name, node, generics) + }; + + Ok(ImplItem { + id: ast::DUMMY_NODE_ID, + span: lo.to(self.prev_span), + ident: name, + vis, + defaultness, + attrs, + generics, + node, + tokens: None, + }) + } + + /// Parses defaultness (i.e., `default` or nothing). + fn parse_defaultness(&mut self) -> Defaultness { + // `pub` is included for better error messages + if self.check_keyword(kw::Default) && + self.is_keyword_ahead(1, &[ + kw::Impl, + kw::Const, + kw::Fn, + kw::Unsafe, + kw::Extern, + kw::Type, + kw::Pub, + ]) + { + self.bump(); // `default` + Defaultness::Default + } else { + Defaultness::Final + } + } + + /// Returns `true` if we are looking at `const ID` + /// (returns `false` for things like `const fn`, etc.). + fn is_const_item(&self) -> bool { + self.token.is_keyword(kw::Const) && + !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) + } + + /// Parse a method or a macro invocation in a trait impl. + fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool) + -> PResult<'a, (Ident, Vec, ast::Generics, + ast::ImplItemKind)> { + // code copied from parse_macro_use_or_failure... abstraction! + if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? { + // method macro + Ok((Ident::invalid(), vec![], ast::Generics::default(), + ast::ImplItemKind::Macro(mac))) + } else { + let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; + let ident = self.parse_ident()?; + let mut generics = self.parse_generics()?; + let decl = self.parse_fn_decl_with_self(|p| { + p.parse_arg_general(true, false, |_| true) + })?; + generics.where_clause = self.parse_where_clause()?; + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + let header = ast::FnHeader { abi, unsafety, constness, asyncness }; + Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method( + ast::MethodSig { header, decl }, + body + ))) + } + } + + /// Parses all the "front matter" for a `fn` declaration, up to + /// and including the `fn` keyword: + /// + /// - `const fn` + /// - `unsafe fn` + /// - `const unsafe fn` + /// - `extern fn` + /// - etc. + fn parse_fn_front_matter(&mut self) + -> PResult<'a, ( + Spanned, + Unsafety, + Spanned, + Abi + )> + { + let is_const_fn = self.eat_keyword(kw::Const); + let const_span = self.prev_span; + let asyncness = self.parse_asyncness(); + if let IsAsync::Async { .. } = asyncness { + self.ban_async_in_2015(self.prev_span); + } + let asyncness = respan(self.prev_span, asyncness); + let unsafety = self.parse_unsafety(); + let (constness, unsafety, abi) = if is_const_fn { + (respan(const_span, Constness::Const), unsafety, Abi::Rust) + } else { + let abi = if self.eat_keyword(kw::Extern) { + self.parse_opt_abi()?.unwrap_or(Abi::C) + } else { + Abi::Rust + }; + (respan(self.prev_span, Constness::NotConst), unsafety, abi) + }; + if !self.eat_keyword(kw::Fn) { + // It is possible for `expect_one_of` to recover given the contents of + // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't + // account for this. + if !self.expect_one_of(&[], &[])? { unreachable!() } + } + Ok((constness, unsafety, asyncness, abi)) + } + + /// Parses `trait Foo { ... }` or `trait Foo = Bar;`. + fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> { + let ident = self.parse_ident()?; + let mut tps = self.parse_generics()?; + + // Parse optional colon and supertrait bounds. + let bounds = if self.eat(&token::Colon) { + self.parse_generic_bounds(Some(self.prev_span))? + } else { + Vec::new() + }; + + if self.eat(&token::Eq) { + // it's a trait alias + let bounds = self.parse_generic_bounds(None)?; + tps.where_clause = self.parse_where_clause()?; + self.expect(&token::Semi)?; + if is_auto == IsAuto::Yes { + let msg = "trait aliases cannot be `auto`"; + self.struct_span_err(self.prev_span, msg) + .span_label(self.prev_span, msg) + .emit(); + } + if unsafety != Unsafety::Normal { + let msg = "trait aliases cannot be `unsafe`"; + self.struct_span_err(self.prev_span, msg) + .span_label(self.prev_span, msg) + .emit(); + } + Ok((ident, ItemKind::TraitAlias(tps, bounds), None)) + } else { + // it's a normal trait + tps.where_clause = self.parse_where_clause()?; + self.expect(&token::OpenDelim(token::Brace))?; + let mut trait_items = vec![]; + while !self.eat(&token::CloseDelim(token::Brace)) { + if let token::DocComment(_) = self.token.kind { + if self.look_ahead(1, + |tok| tok == &token::CloseDelim(token::Brace)) { + self.diagnostic().struct_span_err_with_code( + self.token.span, + "found a documentation comment that doesn't document anything", + DiagnosticId::Error("E0584".into()), + ) + .help( + "doc comments must come before what they document, maybe a \ + comment was intended with `//`?", + ) + .emit(); + self.bump(); + continue; + } + } + let mut at_end = false; + match self.parse_trait_item(&mut at_end) { + Ok(item) => trait_items.push(item), + Err(mut e) => { + e.emit(); + if !at_end { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + } + } + } + } + Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None)) + } + } + + /// Parses the items in a trait declaration. + pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { + maybe_whole!(self, NtTraitItem, |x| x); + let attrs = self.parse_outer_attributes()?; + let mut unclosed_delims = vec![]; + let (mut item, tokens) = self.collect_tokens(|this| { + let item = this.parse_trait_item_(at_end, attrs); + unclosed_delims.append(&mut this.unclosed_delims); + item + })?; + self.unclosed_delims.append(&mut unclosed_delims); + // See `parse_item` for why this clause is here. + if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { + item.tokens = Some(tokens); + } + Ok(item) + } + + fn parse_trait_item_(&mut self, + at_end: &mut bool, + mut attrs: Vec) -> PResult<'a, TraitItem> { + let lo = self.token.span; + self.eat_bad_pub(); + let (name, node, generics) = if self.eat_keyword(kw::Type) { + self.parse_trait_item_assoc_ty()? + } else if self.is_const_item() { + self.expect_keyword(kw::Const)?; + let ident = self.parse_ident()?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + let default = if self.eat(&token::Eq) { + let expr = self.parse_expr()?; + self.expect(&token::Semi)?; + Some(expr) + } else { + self.expect(&token::Semi)?; + None + }; + (ident, TraitItemKind::Const(ty, default), ast::Generics::default()) + } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? { + // trait item macro. + (Ident::invalid(), ast::TraitItemKind::Macro(mac), ast::Generics::default()) + } else { + let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?; + + let ident = self.parse_ident()?; + let mut generics = self.parse_generics()?; + + let decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { + // This is somewhat dubious; We don't want to allow + // argument names to be left off if there is a + // definition... + + // We don't allow argument names to be left off in edition 2018. + let is_name_required = p.token.span.rust_2018(); + p.parse_arg_general(true, false, |_| is_name_required) + })?; + generics.where_clause = self.parse_where_clause()?; + + let sig = ast::MethodSig { + header: FnHeader { + unsafety, + constness, + abi, + asyncness, + }, + decl, + }; + + let body = match self.token.kind { + token::Semi => { + self.bump(); + *at_end = true; + debug!("parse_trait_methods(): parsing required method"); + None + } + token::OpenDelim(token::Brace) => { + debug!("parse_trait_methods(): parsing provided method"); + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } + token::Interpolated(ref nt) => { + match **nt { + token::NtBlock(..) => { + *at_end = true; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(inner_attrs.iter().cloned()); + Some(body) + } + _ => { + return self.expected_semi_or_open_brace(); + } + } + } + _ => { + return self.expected_semi_or_open_brace(); + } + }; + (ident, ast::TraitItemKind::Method(sig, body), generics) + }; + + Ok(TraitItem { + id: ast::DUMMY_NODE_ID, + ident: name, + attrs, + generics, + node, + span: lo.to(self.prev_span), + tokens: None, + }) + } + + /// Parses the following grammar: + /// + /// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty] + fn parse_trait_item_assoc_ty(&mut self) + -> PResult<'a, (Ident, TraitItemKind, ast::Generics)> { + let ident = self.parse_ident()?; + let mut generics = self.parse_generics()?; + + // Parse optional colon and param bounds. + let bounds = if self.eat(&token::Colon) { + self.parse_generic_bounds(None)? + } else { + Vec::new() + }; + generics.where_clause = self.parse_where_clause()?; + + let default = if self.eat(&token::Eq) { + Some(self.parse_ty()?) + } else { + None + }; + self.expect(&token::Semi)?; + + Ok((ident, TraitItemKind::Type(bounds, default), generics)) + } + + /// Parses a `UseTree`. + /// + /// ``` + /// USE_TREE = [`::`] `*` | + /// [`::`] `{` USE_TREE_LIST `}` | + /// PATH `::` `*` | + /// PATH `::` `{` USE_TREE_LIST `}` | + /// PATH [`as` IDENT] + /// ``` + fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { + let lo = self.token.span; + + let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo() }; + let kind = if self.check(&token::OpenDelim(token::Brace)) || + self.check(&token::BinOp(token::Star)) || + self.is_import_coupler() { + // `use *;` or `use ::*;` or `use {...};` or `use ::{...};` + let mod_sep_ctxt = self.token.span.ctxt(); + if self.eat(&token::ModSep) { + prefix.segments.push( + PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)) + ); + } + + if self.eat(&token::BinOp(token::Star)) { + UseTreeKind::Glob + } else { + UseTreeKind::Nested(self.parse_use_tree_list()?) + } + } else { + // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;` + prefix = self.parse_path(PathStyle::Mod)?; + + if self.eat(&token::ModSep) { + if self.eat(&token::BinOp(token::Star)) { + UseTreeKind::Glob + } else { + UseTreeKind::Nested(self.parse_use_tree_list()?) + } + } else { + UseTreeKind::Simple(self.parse_rename()?, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID) + } + }; + + Ok(UseTree { prefix, kind, span: lo.to(self.prev_span) }) + } + + /// Parses a `UseTreeKind::Nested(list)`. + /// + /// ``` + /// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`] + /// ``` + fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> { + self.parse_delim_comma_seq(token::Brace, |p| Ok((p.parse_use_tree()?, ast::DUMMY_NODE_ID))) + .map(|(r, _)| r) + } + + fn parse_rename(&mut self) -> PResult<'a, Option> { + if self.eat_keyword(kw::As) { + self.parse_ident_or_underscore().map(Some) + } else { + Ok(None) + } + } + + /// Parses `extern crate` links. + /// + /// # Examples + /// + /// ``` + /// extern crate foo; + /// extern crate bar as foo; + /// ``` + fn parse_item_extern_crate( + &mut self, + lo: Span, + visibility: Visibility, + attrs: Vec + ) -> PResult<'a, P> { + // Accept `extern crate name-like-this` for better diagnostics + let orig_name = self.parse_crate_name_with_dashes()?; + let (item_name, orig_name) = if let Some(rename) = self.parse_rename()? { + (rename, Some(orig_name.name)) + } else { + (orig_name, None) + }; + self.expect(&token::Semi)?; + + let span = lo.to(self.prev_span); + Ok(self.mk_item(span, item_name, ItemKind::ExternCrate(orig_name), visibility, attrs)) + } + + fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> { + let error_msg = "crate name using dashes are not valid in `extern crate` statements"; + let suggestion_msg = "if the original crate name uses dashes you need to use underscores \ + in the code"; + let mut ident = if self.token.is_keyword(kw::SelfLower) { + self.parse_path_segment_ident() + } else { + self.parse_ident() + }?; + let mut idents = vec![]; + let mut replacement = vec![]; + let mut fixed_crate_name = false; + // Accept `extern crate name-like-this` for better diagnostics + let dash = token::BinOp(token::BinOpToken::Minus); + if self.token == dash { // Do not include `-` as part of the expected tokens list + while self.eat(&dash) { + fixed_crate_name = true; + replacement.push((self.prev_span, "_".to_string())); + idents.push(self.parse_ident()?); + } + } + if fixed_crate_name { + let fixed_name_sp = ident.span.to(idents.last().unwrap().span); + let mut fixed_name = format!("{}", ident.name); + for part in idents { + fixed_name.push_str(&format!("_{}", part.name)); + } + ident = Ident::from_str(&fixed_name).with_span_pos(fixed_name_sp); + + self.struct_span_err(fixed_name_sp, error_msg) + .span_label(fixed_name_sp, "dash-separated idents are not valid") + .multipart_suggestion(suggestion_msg, replacement, Applicability::MachineApplicable) + .emit(); + } + Ok(ident) + } + + /// Parses an item-position function declaration. + fn parse_item_fn( + &mut self, + unsafety: Unsafety, + asyncness: Spanned, + constness: Spanned, + abi: Abi + ) -> PResult<'a, ItemInfo> { + let (ident, mut generics) = self.parse_fn_header()?; + let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe; + let decl = self.parse_fn_decl(allow_c_variadic)?; + generics.where_clause = self.parse_where_clause()?; + let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + let header = FnHeader { unsafety, asyncness, constness, abi }; + Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) + } + + /// Parses the name and optional generic types of a function header. + fn parse_fn_header(&mut self) -> PResult<'a, (Ident, ast::Generics)> { + let id = self.parse_ident()?; + let generics = self.parse_generics()?; + Ok((id, generics)) + } + + /// Parses the argument list and result type of a function declaration. + fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P> { + let (args, c_variadic) = self.parse_fn_args(true, allow_c_variadic)?; + let ret_ty = self.parse_ret_ty(true)?; + + Ok(P(FnDecl { + inputs: args, + output: ret_ty, + c_variadic, + })) + } + + /// Parses `extern` for foreign ABIs modules. + /// + /// `extern` is expected to have been + /// consumed before calling this method. + /// + /// # Examples + /// + /// ```ignore (only-for-syntax-highlight) + /// extern "C" {} + /// extern {} + /// ``` + fn parse_item_foreign_mod( + &mut self, + lo: Span, + opt_abi: Option, + visibility: Visibility, + mut attrs: Vec, + extern_sp: Span, + ) -> PResult<'a, P> { + self.expect(&token::OpenDelim(token::Brace))?; + + let abi = opt_abi.unwrap_or(Abi::C); + + attrs.extend(self.parse_inner_attributes()?); + + let mut foreign_items = vec![]; + while !self.eat(&token::CloseDelim(token::Brace)) { + foreign_items.push(self.parse_foreign_item(extern_sp)?); + } + + let prev_span = self.prev_span; + let m = ast::ForeignMod { + abi, + items: foreign_items + }; + let invalid = Ident::invalid(); + Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs)) + } + + /// Parses a foreign item. + crate fn parse_foreign_item(&mut self, extern_sp: Span) -> PResult<'a, ForeignItem> { + maybe_whole!(self, NtForeignItem, |ni| ni); + + let attrs = self.parse_outer_attributes()?; + let lo = self.token.span; + let visibility = self.parse_visibility(false)?; + + // FOREIGN STATIC ITEM + // Treat `const` as `static` for error recovery, but don't add it to expected tokens. + if self.check_keyword(kw::Static) || self.token.is_keyword(kw::Const) { + if self.token.is_keyword(kw::Const) { + self.diagnostic() + .struct_span_err(self.token.span, "extern items cannot be `const`") + .span_suggestion( + self.token.span, + "try using a static value", + "static".to_owned(), + Applicability::MachineApplicable + ).emit(); + } + self.bump(); // `static` or `const` + return Ok(self.parse_item_foreign_static(visibility, lo, attrs)?); + } + // FOREIGN FUNCTION ITEM + if self.check_keyword(kw::Fn) { + return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?); + } + // FOREIGN TYPE ITEM + if self.check_keyword(kw::Type) { + return Ok(self.parse_item_foreign_type(visibility, lo, attrs)?); + } + + match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? { + Some(mac) => { + Ok( + ForeignItem { + ident: Ident::invalid(), + span: lo.to(self.prev_span), + id: ast::DUMMY_NODE_ID, + attrs, + vis: visibility, + node: ForeignItemKind::Macro(mac), + } + ) + } + None => { + if !attrs.is_empty() { + self.expected_item_err(&attrs)?; + } + + self.unexpected() + } + } + } + + /// Parses a function declaration from a foreign module. + fn parse_item_foreign_fn( + &mut self, + vis: ast::Visibility, + lo: Span, + attrs: Vec, + extern_sp: Span, + ) -> PResult<'a, ForeignItem> { + self.expect_keyword(kw::Fn)?; + + let (ident, mut generics) = self.parse_fn_header()?; + let decl = self.parse_fn_decl(true)?; + generics.where_clause = self.parse_where_clause()?; + let hi = self.token.span; + self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?; + Ok(ast::ForeignItem { + ident, + attrs, + node: ForeignItemKind::Fn(decl, generics), + id: ast::DUMMY_NODE_ID, + span: lo.to(hi), + vis, + }) + } + + /// Parses a static item from a foreign module. + /// Assumes that the `static` keyword is already parsed. + fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec) + -> PResult<'a, ForeignItem> { + let mutbl = self.parse_mutability(); + let ident = self.parse_ident()?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + let hi = self.token.span; + self.expect(&token::Semi)?; + Ok(ForeignItem { + ident, + attrs, + node: ForeignItemKind::Static(ty, mutbl), + id: ast::DUMMY_NODE_ID, + span: lo.to(hi), + vis, + }) + } + + /// Parses a type from a foreign module. + fn parse_item_foreign_type(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec) + -> PResult<'a, ForeignItem> { + self.expect_keyword(kw::Type)?; + + let ident = self.parse_ident()?; + let hi = self.token.span; + self.expect(&token::Semi)?; + Ok(ast::ForeignItem { + ident, + attrs, + node: ForeignItemKind::Ty, + id: ast::DUMMY_NODE_ID, + span: lo.to(hi), + vis + }) + } + + fn is_static_global(&mut self) -> bool { + if self.check_keyword(kw::Static) { + // Check if this could be a closure + !self.look_ahead(1, |token| { + if token.is_keyword(kw::Move) { + return true; + } + match token.kind { + token::BinOp(token::Or) | token::OrOr => true, + _ => false, + } + }) + } else { + false + } + } + + fn parse_item_const(&mut self, m: Option) -> PResult<'a, ItemInfo> { + let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + self.expect(&token::Eq)?; + let e = self.parse_expr()?; + self.expect(&token::Semi)?; + let item = match m { + Some(m) => ItemKind::Static(ty, m, e), + None => ItemKind::Const(ty, e), + }; + Ok((id, item, None)) + } + + /// Parses `type Foo = Bar;` or returns `None` + /// without modifying the parser state. + fn eat_type(&mut self) -> Option> { + // This parses the grammar: + // Ident ["<"...">"] ["where" ...] ("=" | ":") Ty ";" + if self.eat_keyword(kw::Type) { + Some(self.parse_type_alias()) + } else { + None + } + } + + /// Parses a type alias or opaque type. + fn parse_type_alias(&mut self) -> PResult<'a, (Ident, AliasKind, ast::Generics)> { + let ident = self.parse_ident()?; + let mut tps = self.parse_generics()?; + tps.where_clause = self.parse_where_clause()?; + self.expect(&token::Eq)?; + let alias = if self.check_keyword(kw::Impl) { + self.bump(); + let bounds = self.parse_generic_bounds(Some(self.prev_span))?; + AliasKind::OpaqueTy(bounds) + } else { + let ty = self.parse_ty()?; + AliasKind::Weak(ty) + }; + self.expect(&token::Semi)?; + Ok((ident, alias, tps)) + } + + /// Parses an enum declaration. + fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { + let id = self.parse_ident()?; + let mut generics = self.parse_generics()?; + generics.where_clause = self.parse_where_clause()?; + self.expect(&token::OpenDelim(token::Brace))?; + + let enum_definition = self.parse_enum_def(&generics).map_err(|e| { + self.recover_stmt(); + self.eat(&token::CloseDelim(token::Brace)); + e + })?; + Ok((id, ItemKind::Enum(enum_definition, generics), None)) + } + + /// Parses the part of an enum declaration following the `{`. + fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult<'a, EnumDef> { + let mut variants = Vec::new(); + while self.token != token::CloseDelim(token::Brace) { + let variant_attrs = self.parse_outer_attributes()?; + let vlo = self.token.span; + + self.eat_bad_pub(); + let ident = self.parse_ident()?; + + let struct_def = if self.check(&token::OpenDelim(token::Brace)) { + // Parse a struct variant. + let (fields, recovered) = self.parse_record_struct_body()?; + VariantData::Struct(fields, recovered) + } else if self.check(&token::OpenDelim(token::Paren)) { + VariantData::Tuple( + self.parse_tuple_struct_body()?, + ast::DUMMY_NODE_ID, + ) + } else { + VariantData::Unit(ast::DUMMY_NODE_ID) + }; + + let disr_expr = if self.eat(&token::Eq) { + Some(AnonConst { + id: ast::DUMMY_NODE_ID, + value: self.parse_expr()?, + }) + } else { + None + }; + + let vr = ast::Variant_ { + ident, + id: ast::DUMMY_NODE_ID, + attrs: variant_attrs, + data: struct_def, + disr_expr, + }; + variants.push(respan(vlo.to(self.prev_span), vr)); + + if !self.eat(&token::Comma) { + if self.token.is_ident() && !self.token.is_reserved_ident() { + let sp = self.sess.source_map().next_point(self.prev_span); + self.struct_span_err(sp, "missing comma") + .span_suggestion_short( + sp, + "missing comma", + ",".to_owned(), + Applicability::MaybeIncorrect, + ) + .emit(); + } else { + break; + } + } + } + self.expect(&token::CloseDelim(token::Brace))?; + + Ok(ast::EnumDef { variants }) + } + + /// Parses `struct Foo { ... }`. + fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { + let class_name = self.parse_ident()?; + + let mut generics = self.parse_generics()?; + + // There is a special case worth noting here, as reported in issue #17904. + // If we are parsing a tuple struct it is the case that the where clause + // should follow the field list. Like so: + // + // struct Foo(T) where T: Copy; + // + // If we are parsing a normal record-style struct it is the case + // that the where clause comes before the body, and after the generics. + // So if we look ahead and see a brace or a where-clause we begin + // parsing a record style struct. + // + // Otherwise if we look ahead and see a paren we parse a tuple-style + // struct. + + let vdata = if self.token.is_keyword(kw::Where) { + generics.where_clause = self.parse_where_clause()?; + if self.eat(&token::Semi) { + // If we see a: `struct Foo where T: Copy;` style decl. + VariantData::Unit(ast::DUMMY_NODE_ID) + } else { + // If we see: `struct Foo where T: Copy { ... }` + let (fields, recovered) = self.parse_record_struct_body()?; + VariantData::Struct(fields, recovered) + } + // No `where` so: `struct Foo;` + } else if self.eat(&token::Semi) { + VariantData::Unit(ast::DUMMY_NODE_ID) + // Record-style struct definition + } else if self.token == token::OpenDelim(token::Brace) { + let (fields, recovered) = self.parse_record_struct_body()?; + VariantData::Struct(fields, recovered) + // Tuple-style struct definition with optional where-clause. + } else if self.token == token::OpenDelim(token::Paren) { + let body = VariantData::Tuple(self.parse_tuple_struct_body()?, ast::DUMMY_NODE_ID); + generics.where_clause = self.parse_where_clause()?; + self.expect(&token::Semi)?; + body + } else { + let token_str = self.this_token_descr(); + let mut err = self.fatal(&format!( + "expected `where`, `{{`, `(`, or `;` after struct name, found {}", + token_str + )); + err.span_label(self.token.span, "expected `where`, `{`, `(`, or `;` after struct name"); + return Err(err); + }; + + Ok((class_name, ItemKind::Struct(vdata, generics), None)) + } + + /// Parses `union Foo { ... }`. + fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { + let class_name = self.parse_ident()?; + + let mut generics = self.parse_generics()?; + + let vdata = if self.token.is_keyword(kw::Where) { + generics.where_clause = self.parse_where_clause()?; + let (fields, recovered) = self.parse_record_struct_body()?; + VariantData::Struct(fields, recovered) + } else if self.token == token::OpenDelim(token::Brace) { + let (fields, recovered) = self.parse_record_struct_body()?; + VariantData::Struct(fields, recovered) + } else { + let token_str = self.this_token_descr(); + let mut err = self.fatal(&format!( + "expected `where` or `{{` after union name, found {}", token_str)); + err.span_label(self.token.span, "expected `where` or `{` after union name"); + return Err(err); + }; + + Ok((class_name, ItemKind::Union(vdata, generics), None)) + } + + pub(super) fn is_union_item(&self) -> bool { + self.token.is_keyword(kw::Union) && + self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) + } + + fn parse_record_struct_body( + &mut self, + ) -> PResult<'a, (Vec, /* recovered */ bool)> { + let mut fields = Vec::new(); + let mut recovered = false; + if self.eat(&token::OpenDelim(token::Brace)) { + while self.token != token::CloseDelim(token::Brace) { + let field = self.parse_struct_decl_field().map_err(|e| { + self.recover_stmt(); + recovered = true; + e + }); + match field { + Ok(field) => fields.push(field), + Err(mut err) => { + err.emit(); + } + } + } + self.eat(&token::CloseDelim(token::Brace)); + } else { + let token_str = self.this_token_descr(); + let mut err = self.fatal(&format!( + "expected `where`, or `{{` after struct name, found {}", token_str)); + err.span_label(self.token.span, "expected `where`, or `{` after struct name"); + return Err(err); + } + + Ok((fields, recovered)) + } + + fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec> { + // This is the case where we find `struct Foo(T) where T: Copy;` + // Unit like structs are handled in parse_item_struct function + self.parse_paren_comma_seq(|p| { + let attrs = p.parse_outer_attributes()?; + let lo = p.token.span; + let vis = p.parse_visibility(true)?; + let ty = p.parse_ty()?; + Ok(StructField { + span: lo.to(ty.span), + vis, + ident: None, + id: ast::DUMMY_NODE_ID, + ty, + attrs, + }) + }).map(|(r, _)| r) + } + + /// Parses an element of a struct declaration. + fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { + let attrs = self.parse_outer_attributes()?; + let lo = self.token.span; + let vis = self.parse_visibility(false)?; + self.parse_single_struct_field(lo, vis, attrs) + } + + /// Parses a structure field declaration. + fn parse_single_struct_field(&mut self, + lo: Span, + vis: Visibility, + attrs: Vec ) + -> PResult<'a, StructField> { + let mut seen_comma: bool = false; + let a_var = self.parse_name_and_ty(lo, vis, attrs)?; + if self.token == token::Comma { + seen_comma = true; + } + match self.token.kind { + token::Comma => { + self.bump(); + } + token::CloseDelim(token::Brace) => {} + token::DocComment(_) => { + let previous_span = self.prev_span; + let mut err = self.span_fatal_err(self.token.span, Error::UselessDocComment); + self.bump(); // consume the doc comment + let comma_after_doc_seen = self.eat(&token::Comma); + // `seen_comma` is always false, because we are inside doc block + // condition is here to make code more readable + if seen_comma == false && comma_after_doc_seen == true { + seen_comma = true; + } + if comma_after_doc_seen || self.token == token::CloseDelim(token::Brace) { + err.emit(); + } else { + if seen_comma == false { + let sp = self.sess.source_map().next_point(previous_span); + err.span_suggestion( + sp, + "missing comma here", + ",".into(), + Applicability::MachineApplicable + ); + } + return Err(err); + } + } + _ => { + let sp = self.sess.source_map().next_point(self.prev_span); + let mut err = self.struct_span_err(sp, &format!("expected `,`, or `}}`, found {}", + self.this_token_descr())); + if self.token.is_ident() { + // This is likely another field; emit the diagnostic and keep going + err.span_suggestion( + sp, + "try adding a comma", + ",".into(), + Applicability::MachineApplicable, + ); + err.emit(); + } else { + return Err(err) + } + } + } + Ok(a_var) + } + + /// Parses a structure field. + fn parse_name_and_ty( + &mut self, + lo: Span, + vis: Visibility, + attrs: Vec + ) -> PResult<'a, StructField> { + let name = self.parse_ident()?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + Ok(StructField { + span: lo.to(self.prev_span), + ident: Some(name), + vis, + id: ast::DUMMY_NODE_ID, + ty, + attrs, + }) + } + + pub(super) fn eat_macro_def( + &mut self, + attrs: &[Attribute], + vis: &Visibility, + lo: Span + ) -> PResult<'a, Option>> { + let token_lo = self.token.span; + let (ident, def) = if self.eat_keyword(kw::Macro) { + let ident = self.parse_ident()?; + let tokens = if self.check(&token::OpenDelim(token::Brace)) { + match self.parse_token_tree() { + TokenTree::Delimited(_, _, tts) => tts, + _ => unreachable!(), + } + } else if self.check(&token::OpenDelim(token::Paren)) { + let args = self.parse_token_tree(); + let body = if self.check(&token::OpenDelim(token::Brace)) { + self.parse_token_tree() + } else { + self.unexpected()?; + unreachable!() + }; + TokenStream::new(vec![ + args.into(), + TokenTree::token(token::FatArrow, token_lo.to(self.prev_span)).into(), + body.into(), + ]) + } else { + self.unexpected()?; + unreachable!() + }; + + (ident, ast::MacroDef { tokens: tokens.into(), legacy: false }) + } else if self.check_keyword(sym::macro_rules) && + self.look_ahead(1, |t| *t == token::Not) && + self.look_ahead(2, |t| t.is_ident()) { + let prev_span = self.prev_span; + self.complain_if_pub_macro(&vis.node, prev_span); + self.bump(); + self.bump(); + + let ident = self.parse_ident()?; + let (delim, tokens) = self.expect_delimited_token_tree()?; + if delim != MacDelimiter::Brace && !self.eat(&token::Semi) { + self.report_invalid_macro_expansion_item(); + } + + (ident, ast::MacroDef { tokens, legacy: true }) + } else { + return Ok(None); + }; + + let span = lo.to(self.prev_span); + Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec()))) + } + + fn complain_if_pub_macro(&self, vis: &VisibilityKind, sp: Span) { + match *vis { + VisibilityKind::Inherited => {} + _ => { + let mut err = if self.token.is_keyword(sym::macro_rules) { + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); + err.span_suggestion( + sp, + "try exporting the macro", + "#[macro_export]".to_owned(), + Applicability::MaybeIncorrect // speculative + ); + err + } else { + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro invocation with `pub`"); + err.help("try adjusting the macro to put `pub` inside the invocation"); + err + }; + err.emit(); + } + } + } + + fn mk_item(&self, span: Span, ident: Ident, node: ItemKind, vis: Visibility, + attrs: Vec) -> P { + P(Item { + ident, + attrs, + id: ast::DUMMY_NODE_ID, + node, + vis, + span, + tokens: None, + }) + } +} diff --git a/src/libsyntax/parse/parser/module.rs b/src/libsyntax/parse/parser/module.rs new file mode 100644 index 00000000000..58a7ffba948 --- /dev/null +++ b/src/libsyntax/parse/parser/module.rs @@ -0,0 +1,332 @@ +use super::{Parser, PResult}; +use super::item::ItemInfo; + +use crate::attr; +use crate::ast::{self, Ident, Attribute, ItemKind, Mod, Crate}; +use crate::parse::{new_sub_parser_from_file, DirectoryOwnership}; +use crate::parse::token::{self, TokenKind}; +use crate::parse::diagnostics::{Error}; +use crate::source_map::{SourceMap, Span, DUMMY_SP, FileName}; +use crate::symbol::sym; + +use std::path::{self, Path, PathBuf}; + +/// Information about the path to a module. +pub struct ModulePath { + name: String, + path_exists: bool, + pub result: Result, +} + +pub struct ModulePathSuccess { + pub path: PathBuf, + pub directory_ownership: DirectoryOwnership, + warn: bool, +} + +impl<'a> Parser<'a> { + /// Parses a source module as a crate. This is the main entry point for the parser. + pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> { + let lo = self.token.span; + let krate = Ok(ast::Crate { + attrs: self.parse_inner_attributes()?, + module: self.parse_mod_items(&token::Eof, lo)?, + span: lo.to(self.token.span), + }); + krate + } + + /// Parse a `mod { ... }` or `mod ;` item + pub(super) fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> { + let (in_cfg, outer_attrs) = { + let mut strip_unconfigured = crate::config::StripUnconfigured { + sess: self.sess, + features: None, // don't perform gated feature checking + }; + let mut outer_attrs = outer_attrs.to_owned(); + strip_unconfigured.process_cfg_attrs(&mut outer_attrs); + (!self.cfg_mods || strip_unconfigured.in_cfg(&outer_attrs), outer_attrs) + }; + + let id_span = self.token.span; + let id = self.parse_ident()?; + if self.eat(&token::Semi) { + if in_cfg && self.recurse_into_file_modules { + // This mod is in an external file. Let's go get it! + let ModulePathSuccess { path, directory_ownership, warn } = + self.submod_path(id, &outer_attrs, id_span)?; + let (module, mut attrs) = + self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?; + // Record that we fetched the mod from an external file + if warn { + let attr = attr::mk_attr_outer( + attr::mk_word_item(Ident::with_empty_ctxt(sym::warn_directory_ownership))); + attr::mark_known(&attr); + attrs.push(attr); + } + Ok((id, ItemKind::Mod(module), Some(attrs))) + } else { + let placeholder = ast::Mod { + inner: DUMMY_SP, + items: Vec::new(), + inline: false + }; + Ok((id, ItemKind::Mod(placeholder), None)) + } + } else { + let old_directory = self.directory.clone(); + self.push_directory(id, &outer_attrs); + + self.expect(&token::OpenDelim(token::Brace))?; + let mod_inner_lo = self.token.span; + let attrs = self.parse_inner_attributes()?; + let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; + + self.directory = old_directory; + Ok((id, ItemKind::Mod(module), Some(attrs))) + } + } + + /// Given a termination token, parses all of the items in a module. + fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> { + let mut items = vec![]; + while let Some(item) = self.parse_item()? { + items.push(item); + self.maybe_consume_incorrect_semicolon(&items); + } + + if !self.eat(term) { + let token_str = self.this_token_descr(); + if !self.maybe_consume_incorrect_semicolon(&items) { + let mut err = self.fatal(&format!("expected item, found {}", token_str)); + err.span_label(self.token.span, "expected item"); + return Err(err); + } + } + + let hi = if self.token.span.is_dummy() { + inner_lo + } else { + self.prev_span + }; + + Ok(Mod { + inner: inner_lo.to(hi), + items, + inline: true + }) + } + + fn submod_path( + &mut self, + id: ast::Ident, + outer_attrs: &[Attribute], + id_sp: Span + ) -> PResult<'a, ModulePathSuccess> { + if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) { + return Ok(ModulePathSuccess { + directory_ownership: match path.file_name().and_then(|s| s.to_str()) { + // All `#[path]` files are treated as though they are a `mod.rs` file. + // This means that `mod foo;` declarations inside `#[path]`-included + // files are siblings, + // + // Note that this will produce weirdness when a file named `foo.rs` is + // `#[path]` included and contains a `mod foo;` declaration. + // If you encounter this, it's your own darn fault :P + Some(_) => DirectoryOwnership::Owned { relative: None }, + _ => DirectoryOwnership::UnownedViaMod(true), + }, + path, + warn: false, + }); + } + + let relative = match self.directory.ownership { + DirectoryOwnership::Owned { relative } => relative, + DirectoryOwnership::UnownedViaBlock | + DirectoryOwnership::UnownedViaMod(_) => None, + }; + let paths = Parser::default_submod_path( + id, relative, &self.directory.path, self.sess.source_map()); + + match self.directory.ownership { + DirectoryOwnership::Owned { .. } => { + paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) + }, + DirectoryOwnership::UnownedViaBlock => { + let msg = + "Cannot declare a non-inline module inside a block \ + unless it has a path attribute"; + let mut err = self.diagnostic().struct_span_err(id_sp, msg); + if paths.path_exists { + let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", + paths.name); + err.span_note(id_sp, &msg); + } + Err(err) + } + DirectoryOwnership::UnownedViaMod(warn) => { + if warn { + if let Ok(result) = paths.result { + return Ok(ModulePathSuccess { warn: true, ..result }); + } + } + let mut err = self.diagnostic().struct_span_err(id_sp, + "cannot declare a new module at this location"); + if !id_sp.is_dummy() { + let src_path = self.sess.source_map().span_to_filename(id_sp); + if let FileName::Real(src_path) = src_path { + if let Some(stem) = src_path.file_stem() { + let mut dest_path = src_path.clone(); + dest_path.set_file_name(stem); + dest_path.push("mod.rs"); + err.span_note(id_sp, + &format!("maybe move this module `{}` to its own \ + directory via `{}`", src_path.display(), + dest_path.display())); + } + } + } + if paths.path_exists { + err.span_note(id_sp, + &format!("... or maybe `use` the module `{}` instead \ + of possibly redeclaring it", + paths.name)); + } + Err(err) + } + } + } + + pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { + if let Some(s) = attr::first_attr_value_str_by_name(attrs, sym::path) { + let s = s.as_str(); + + // On windows, the base path might have the form + // `\\?\foo\bar` in which case it does not tolerate + // mixed `/` and `\` separators, so canonicalize + // `/` to `\`. + #[cfg(windows)] + let s = s.replace("/", "\\"); + Some(dir_path.join(s)) + } else { + None + } + } + + /// Returns a path to a module. + pub fn default_submod_path( + id: ast::Ident, + relative: Option, + dir_path: &Path, + source_map: &SourceMap) -> ModulePath + { + // If we're in a foo.rs file instead of a mod.rs file, + // we need to look for submodules in + // `./foo/.rs` and `./foo//mod.rs` rather than + // `./.rs` and `.//mod.rs`. + let relative_prefix_string; + let relative_prefix = if let Some(ident) = relative { + relative_prefix_string = format!("{}{}", ident.as_str(), path::MAIN_SEPARATOR); + &relative_prefix_string + } else { + "" + }; + + let mod_name = id.to_string(); + let default_path_str = format!("{}{}.rs", relative_prefix, mod_name); + let secondary_path_str = format!("{}{}{}mod.rs", + relative_prefix, mod_name, path::MAIN_SEPARATOR); + let default_path = dir_path.join(&default_path_str); + let secondary_path = dir_path.join(&secondary_path_str); + let default_exists = source_map.file_exists(&default_path); + let secondary_exists = source_map.file_exists(&secondary_path); + + let result = match (default_exists, secondary_exists) { + (true, false) => Ok(ModulePathSuccess { + path: default_path, + directory_ownership: DirectoryOwnership::Owned { + relative: Some(id), + }, + warn: false, + }), + (false, true) => Ok(ModulePathSuccess { + path: secondary_path, + directory_ownership: DirectoryOwnership::Owned { + relative: None, + }, + warn: false, + }), + (false, false) => Err(Error::FileNotFoundForModule { + mod_name: mod_name.clone(), + default_path: default_path_str, + secondary_path: secondary_path_str, + dir_path: dir_path.display().to_string(), + }), + (true, true) => Err(Error::DuplicatePaths { + mod_name: mod_name.clone(), + default_path: default_path_str, + secondary_path: secondary_path_str, + }), + }; + + ModulePath { + name: mod_name, + path_exists: default_exists || secondary_exists, + result, + } + } + + /// Reads a module from a source file. + fn eval_src_mod( + &mut self, + path: PathBuf, + directory_ownership: DirectoryOwnership, + name: String, + id_sp: Span, + ) -> PResult<'a, (Mod, Vec)> { + let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut(); + if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { + let mut err = String::from("circular modules: "); + let len = included_mod_stack.len(); + for p in &included_mod_stack[i.. len] { + err.push_str(&p.to_string_lossy()); + err.push_str(" -> "); + } + err.push_str(&path.to_string_lossy()); + return Err(self.span_fatal(id_sp, &err[..])); + } + included_mod_stack.push(path.clone()); + drop(included_mod_stack); + + let mut p0 = + new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp); + p0.cfg_mods = self.cfg_mods; + let mod_inner_lo = p0.token.span; + let mod_attrs = p0.parse_inner_attributes()?; + let mut m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?; + m0.inline = false; + self.sess.included_mod_stack.borrow_mut().pop(); + Ok((m0, mod_attrs)) + } + + fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { + if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { + self.directory.path.to_mut().push(&path.as_str()); + self.directory.ownership = DirectoryOwnership::Owned { relative: None }; + } else { + // We have to push on the current module name in the case of relative + // paths in order to ensure that any additional module paths from inline + // `mod x { ... }` come after the relative extension. + // + // For example, a `mod z { ... }` inside `x/y.rs` should set the current + // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`. + if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership { + if let Some(ident) = relative.take() { // remove the relative offset + self.directory.path.to_mut().push(ident.as_str()); + } + } + self.directory.path.to_mut().push(&id.as_str()); + } + } +}