From bc75cba23feb45b2d1b67ee07e6eb8264c0d5fd6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 18:59:44 +0100 Subject: submod_path_from_attr: simplify & document --- src/librustc_parse/parser/module.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 7b46601cc7d..4965615c64c 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -179,21 +179,22 @@ impl<'a> Parser<'a> { } } + /// Derive a submodule path from the first found `#[path = "path_string"]`. + /// The provided `dir_path` is joined with the `path_string`. // Public for rustfmt usage. 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(); + // Extract path string from first `#[path = "path_string"]` attribute. + let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?; + let path_string = path_string.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 - } + // 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 path_string = path_string.replace("/", "\\"); + + Some(dir_path.join(&*path_string)) } /// Returns a path to a module. -- cgit 1.4.1-3-g733a5 From 2899a58cab62e132dc7af7b7e0446a90b6d0feff Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 19:11:47 +0100 Subject: extract error_cannot_declare_mod_here --- src/librustc_parse/parser/module.rs | 54 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 4965615c64c..43d93e39575 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -142,41 +142,41 @@ impl<'a> Parser<'a> { } Err(err) } - DirectoryOwnership::UnownedViaMod => { - let mut err = - self.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 { + DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id_sp, paths), + } + } + + fn error_cannot_declare_mod_here(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> { + let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location"); + if !id_sp.is_dummy() { + if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) { + 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!( - "... or maybe `use` the module `{}` instead \ - of possibly redeclaring it", - paths.name + "maybe move this module `{}` to its own \ + directory via `{}`", + src_path.display(), + dest_path.display() ), ); } - Err(err) } } + if paths.path_exists { + err.span_note( + id_sp, + &format!( + "... or maybe `use` the module `{}` instead \ + of possibly redeclaring it", + paths.name + ), + ); + } + Err(err) } /// Derive a submodule path from the first found `#[path = "path_string"]`. -- cgit 1.4.1-3-g733a5 From 185c1d340c5b985195abf15f69b06aa6572d793c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 19:15:35 +0100 Subject: extract error_decl_mod_in_block --- src/librustc_parse/parser/module.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 43d93e39575..c7d120e3cc6 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -129,23 +129,22 @@ impl<'a> Parser<'a> { 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.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::UnownedViaBlock => self.error_decl_mod_in_block(id_sp, paths), DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id_sp, paths), } } + fn error_decl_mod_in_block(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> { + let msg = + "Cannot declare a non-inline module inside a block unless it has a path attribute"; + let mut err = self.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) + } + fn error_cannot_declare_mod_here(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> { let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location"); if !id_sp.is_dummy() { -- cgit 1.4.1-3-g733a5 From 2db5d49d4791723b5335d5b66a0e2c304bf37d4c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 19:20:31 +0100 Subject: simplify submod_path --- src/librustc_parse/parser/module.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index c7d120e3cc6..c426b073a05 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -102,20 +102,18 @@ impl<'a> Parser<'a> { 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, - }, - path, - }); + let 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, + }; + return Ok(ModulePathSuccess { directory_ownership, path }); } let relative = match self.directory.ownership { -- cgit 1.4.1-3-g733a5 From 803de3188c59ecc782db46e3fc9e9f668e260be9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 19:41:24 +0100 Subject: submod_path: use id.span --- src/librustc_parse/parser/module.rs | 12 +++++------- src/test/ui/directory_ownership/macro-expanded-mod.rs | 6 ++++-- src/test/ui/directory_ownership/macro-expanded-mod.stderr | 9 ++------- 3 files changed, 11 insertions(+), 16 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index c426b073a05..45387999196 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -45,14 +45,13 @@ impl<'a> Parser<'a> { pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs); - let id_span = self.token.span; let id = self.parse_ident()?; let (module, mut inner_attrs) = 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 } = - self.submod_path(id, &attrs, id_span)?; - self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)? + self.submod_path(id, &attrs)?; + self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)? } else { (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new()) } @@ -99,7 +98,6 @@ impl<'a> Parser<'a> { &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) { let directory_ownership = match path.file_name().and_then(|s| s.to_str()) { @@ -125,10 +123,10 @@ impl<'a> Parser<'a> { match self.directory.ownership { DirectoryOwnership::Owned { .. } => { - paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) + paths.result.map_err(|err| self.span_fatal_err(id.span, err)) } - DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id_sp, paths), - DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id_sp, paths), + DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id.span, paths), + DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id.span, paths), } } diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.rs b/src/test/ui/directory_ownership/macro-expanded-mod.rs index 376c1a9cd66..1066a2ba712 100644 --- a/src/test/ui/directory_ownership/macro-expanded-mod.rs +++ b/src/test/ui/directory_ownership/macro-expanded-mod.rs @@ -1,7 +1,9 @@ // Test that macro-expanded non-inline modules behave correctly macro_rules! mod_decl { - ($i:ident) => { mod $i; } //~ ERROR Cannot declare a non-inline module inside a block + ($i:ident) => { + mod $i; + }; } mod macro_expanded_mod_helper { @@ -9,5 +11,5 @@ mod macro_expanded_mod_helper { } fn main() { - mod_decl!(foo); + mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block } diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.stderr b/src/test/ui/directory_ownership/macro-expanded-mod.stderr index c7780c869d6..d9d8a8ffed7 100644 --- a/src/test/ui/directory_ownership/macro-expanded-mod.stderr +++ b/src/test/ui/directory_ownership/macro-expanded-mod.stderr @@ -1,13 +1,8 @@ error: Cannot declare a non-inline module inside a block unless it has a path attribute - --> $DIR/macro-expanded-mod.rs:4:25 + --> $DIR/macro-expanded-mod.rs:14:15 | -LL | ($i:ident) => { mod $i; } - | ^^ -... LL | mod_decl!(foo); - | --------------- in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^ error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 7108b7fbfea50bd311617cc217616b88c8b647c9 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 20:19:52 +0100 Subject: extract parse_mod --- src/librustc_parse/parser/module.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 45387999196..9ccafd7932a 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -31,14 +31,10 @@ 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), - // Filled in by proc_macro_harness::inject() - proc_macros: Vec::new(), - }); - krate + let (module, attrs) = self.parse_mod(&token::Eof)?; + let span = lo.to(self.token.span); + let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`. + Ok(ast::Crate { attrs, module, span, proc_macros }) } /// Parses a `mod { ... }` or `mod ;` item. @@ -60,17 +56,23 @@ impl<'a> Parser<'a> { self.push_directory(id, &attrs); self.expect(&token::OpenDelim(token::Brace))?; - let mod_inner_lo = self.token.span; - let inner_attrs = self.parse_inner_attributes()?; - let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; + let module = self.parse_mod(&token::CloseDelim(token::Brace))?; self.directory = old_directory; - (module, inner_attrs) + module }; attrs.append(&mut inner_attrs); Ok((id, ItemKind::Mod(module))) } + /// Parses the contents of a module (inner attributes followed by module items). + fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec)> { + let lo = self.token.span; + let attrs = self.parse_inner_attributes()?; + let module = self.parse_mod_items(term, lo)?; + Ok((module, 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![]; @@ -268,12 +270,11 @@ impl<'a> Parser<'a> { 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; + let mut module = p0.parse_mod(&token::Eof)?; + module.0.inline = false; + self.sess.included_mod_stack.borrow_mut().pop(); - Ok((m0, mod_attrs)) + Ok(module) } fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { -- cgit 1.4.1-3-g733a5 From dfcefa49ed5ce5018d279a8d1a60744da67c80c8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 7 Mar 2020 19:53:25 +0100 Subject: extract error_on_circular_module --- src/librustc_parse/parser/module.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 9ccafd7932a..d203e665c95 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -254,16 +254,7 @@ impl<'a> Parser<'a> { 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.struct_span_err(id_sp, &err[..])); - } + self.error_on_circular_module(id_sp, &path, &included_mod_stack)?; included_mod_stack.push(path.clone()); drop(included_mod_stack); @@ -277,6 +268,25 @@ impl<'a> Parser<'a> { Ok(module) } + fn error_on_circular_module( + &self, + span: Span, + path: &Path, + included_mod_stack: &[PathBuf], + ) -> PResult<'a, ()> { + 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.struct_span_err(span, &err[..])); + } + Ok(()) + } + 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.push(&*path.as_str()); -- cgit 1.4.1-3-g733a5 From ca098b16a4114fd96a4059ba3f807d33dde5ef07 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 09:28:46 +0100 Subject: detach submod_path from Parser --- src/librustc_parse/parser/diagnostics.rs | 31 --- src/librustc_parse/parser/module.rs | 348 +++++++++++++++++-------------- 2 files changed, 192 insertions(+), 187 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 8e52bb16147..87255386b9e 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -18,7 +18,6 @@ use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP}; use log::{debug, trace}; use std::mem; -use std::path::PathBuf; const TURBOFISH: &str = "use `::<...>` instead of `<...>` to specify type arguments"; @@ -41,42 +40,12 @@ pub(super) fn dummy_arg(ident: Ident) -> Param { } pub enum Error { - FileNotFoundForModule { mod_name: String, default_path: PathBuf }, - DuplicatePaths { mod_name: String, default_path: String, secondary_path: String }, UselessDocComment, } impl Error { fn span_err(self, sp: impl Into, handler: &Handler) -> DiagnosticBuilder<'_> { match self { - Error::FileNotFoundForModule { ref mod_name, ref default_path } => { - let mut err = struct_span_err!( - handler, - sp, - E0583, - "file not found for module `{}`", - mod_name, - ); - err.help(&format!( - "to create the module `{}`, create file \"{}\"", - mod_name, - default_path.display(), - )); - err - } - Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { - let mut err = struct_span_err!( - handler, - sp, - E0584, - "file for module `{}` found at both {} and {}", - mod_name, - default_path, - secondary_path, - ); - err.help("delete or rename one of them to remove the ambiguity"); - err - } Error::UselessDocComment => { let mut err = struct_span_err!( handler, diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index d203e665c95..a30d6da281a 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -1,4 +1,3 @@ -use super::diagnostics::Error; use super::item::ItemInfo; use super::Parser; @@ -7,18 +6,19 @@ use crate::{new_sub_parser_from_file, DirectoryOwnership}; use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod}; use rustc_ast::attr; use rustc_ast::token::{self, TokenKind}; -use rustc_errors::PResult; -use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP}; +use rustc_errors::{struct_span_err, PResult}; +use rustc_session::parse::ParseSess; +use rustc_span::source_map::{FileName, Span, DUMMY_SP}; use rustc_span::symbol::sym; use std::path::{self, Path, PathBuf}; /// Information about the path to a module. // Public for rustfmt usage. -pub struct ModulePath { +pub struct ModulePath<'a> { name: String, path_exists: bool, - pub result: Result, + pub result: PResult<'a, ModulePathSuccess>, } // Public for rustfmt usage. @@ -45,8 +45,13 @@ impl<'a> Parser<'a> { let (module, mut inner_attrs) = 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 } = - self.submod_path(id, &attrs)?; + let ModulePathSuccess { path, directory_ownership } = submod_path( + self.sess, + id, + &attrs, + self.directory.ownership, + &self.directory.path, + )?; self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)? } else { (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new()) @@ -96,155 +101,6 @@ impl<'a> Parser<'a> { Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) } - fn submod_path( - &mut self, - id: ast::Ident, - outer_attrs: &[Attribute], - ) -> PResult<'a, ModulePathSuccess> { - if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) { - let 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, - }; - return Ok(ModulePathSuccess { directory_ownership, path }); - } - - 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.span, err)) - } - DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id.span, paths), - DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id.span, paths), - } - } - - fn error_decl_mod_in_block(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> { - let msg = - "Cannot declare a non-inline module inside a block unless it has a path attribute"; - let mut err = self.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) - } - - fn error_cannot_declare_mod_here(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> { - let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location"); - if !id_sp.is_dummy() { - if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) { - 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) - } - - /// Derive a submodule path from the first found `#[path = "path_string"]`. - /// The provided `dir_path` is joined with the `path_string`. - // Public for rustfmt usage. - pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { - // Extract path string from first `#[path = "path_string"]` attribute. - let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?; - let path_string = path_string.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 path_string = path_string.replace("/", "\\"); - - Some(dir_path.join(&*path_string)) - } - - /// Returns a path to a module. - // Public for rustfmt usage. - 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.name, path::MAIN_SEPARATOR); - &relative_prefix_string - } else { - "" - }; - - let mod_name = id.name.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) }, - }), - (false, true) => Ok(ModulePathSuccess { - path: secondary_path, - directory_ownership: DirectoryOwnership::Owned { relative: None }, - }), - (false, false) => { - Err(Error::FileNotFoundForModule { mod_name: mod_name.clone(), default_path }) - } - (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, @@ -308,3 +164,183 @@ impl<'a> Parser<'a> { } } } + +fn submod_path<'a>( + sess: &'a ParseSess, + id: ast::Ident, + outer_attrs: &[Attribute], + directory_ownership: DirectoryOwnership, + dir_path: &Path, +) -> PResult<'a, ModulePathSuccess> { + if let Some(path) = submod_path_from_attr(outer_attrs, dir_path) { + let 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, + }; + return Ok(ModulePathSuccess { directory_ownership, path }); + } + + let relative = match directory_ownership { + DirectoryOwnership::Owned { relative } => relative, + DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None, + }; + let ModulePath { path_exists, name, result } = + default_submod_path(sess, id, relative, dir_path); + match directory_ownership { + DirectoryOwnership::Owned { .. } => Ok(result?), + DirectoryOwnership::UnownedViaBlock => { + let _ = result.map_err(|mut err| err.cancel()); + error_decl_mod_in_block(sess, id.span, path_exists, &name) + } + DirectoryOwnership::UnownedViaMod => { + let _ = result.map_err(|mut err| err.cancel()); + error_cannot_declare_mod_here(sess, id.span, path_exists, &name) + } + } +} + +fn error_decl_mod_in_block<'a, T>( + sess: &'a ParseSess, + id_sp: Span, + path_exists: bool, + name: &str, +) -> PResult<'a, T> { + let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute"; + let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg); + if path_exists { + let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name); + err.span_note(id_sp, &msg); + } + Err(err) +} + +fn error_cannot_declare_mod_here<'a, T>( + sess: &'a ParseSess, + id_sp: Span, + path_exists: bool, + name: &str, +) -> PResult<'a, T> { + let mut err = + sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location"); + if !id_sp.is_dummy() { + if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) { + 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 path_exists { + err.span_note( + id_sp, + &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name), + ); + } + Err(err) +} + +/// Derive a submodule path from the first found `#[path = "path_string"]`. +/// The provided `dir_path` is joined with the `path_string`. +// Public for rustfmt usage. +pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { + // Extract path string from first `#[path = "path_string"]` attribute. + let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?; + let path_string = path_string.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 path_string = path_string.replace("/", "\\"); + + Some(dir_path.join(&*path_string)) +} + +/// Returns a path to a module. +// Public for rustfmt usage. +pub fn default_submod_path<'a>( + sess: &'a ParseSess, + id: ast::Ident, + relative: Option, + dir_path: &Path, +) -> ModulePath<'a> { + // 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.name, path::MAIN_SEPARATOR); + &relative_prefix_string + } else { + "" + }; + + let mod_name = id.name.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 = sess.source_map().file_exists(&default_path); + let secondary_exists = sess.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) }, + }), + (false, true) => Ok(ModulePathSuccess { + path: secondary_path, + directory_ownership: DirectoryOwnership::Owned { relative: None }, + }), + (false, false) => { + let mut err = struct_span_err!( + sess.span_diagnostic, + id.span, + E0583, + "file not found for module `{}`", + mod_name, + ); + err.help(&format!( + "to create the module `{}`, create file \"{}\"", + mod_name, + default_path.display(), + )); + Err(err) + } + (true, true) => { + let mut err = struct_span_err!( + sess.span_diagnostic, + id.span, + E0584, + "file for module `{}` found at both {} and {}", + mod_name, + default_path_str, + secondary_path_str, + ); + err.help("delete or rename one of them to remove the ambiguity"); + Err(err) + } + }; + + ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result } +} -- cgit 1.4.1-3-g733a5 From 53a633fb445af045493f832fdce4f9d9ce48fbd4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 09:54:19 +0100 Subject: decouple push_directory from Parser --- src/librustc_parse/parser/module.rs | 41 +++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index a30d6da281a..53c0c9154bc 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -58,7 +58,7 @@ impl<'a> Parser<'a> { } } else { let old_directory = self.directory.clone(); - self.push_directory(id, &attrs); + push_directory(id, &attrs, &mut self.directory.ownership, &mut self.directory.path); self.expect(&token::OpenDelim(token::Brace))?; let module = self.parse_mod(&token::CloseDelim(token::Brace))?; @@ -142,26 +142,31 @@ impl<'a> Parser<'a> { } Ok(()) } +} - 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.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.push(&*ident.as_str()); - } +fn push_directory( + id: Ident, + attrs: &[Attribute], + dir_ownership: &mut DirectoryOwnership, + dir_path: &mut PathBuf, +) { + if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { + dir_path.push(&*path.as_str()); + *dir_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 } = dir_ownership { + if let Some(ident) = relative.take() { + // Remove the relative offset. + dir_path.push(&*ident.as_str()); } - self.directory.path.push(&*id.as_str()); } + dir_path.push(&*id.as_str()); } } -- cgit 1.4.1-3-g733a5 From 98e71cd5d788c1d8476ccd29974decb5d4b88dbc Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 11:06:30 +0100 Subject: decouple eval_src_mod from Parser --- src/librustc_parse/parser/module.rs | 69 ++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 40 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 53c0c9154bc..245d06333f7 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -52,7 +52,7 @@ impl<'a> Parser<'a> { self.directory.ownership, &self.directory.path, )?; - self.eval_src_mod(path, directory_ownership, id.to_string(), id.span)? + eval_src_mod(self.sess, self.cfg_mods, path, directory_ownership, id)? } else { (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new()) } @@ -100,48 +100,37 @@ impl<'a> Parser<'a> { Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) } +} - /// 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(); - self.error_on_circular_module(id_sp, &path, &included_mod_stack)?; - 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 mut module = p0.parse_mod(&token::Eof)?; - module.0.inline = false; - - self.sess.included_mod_stack.borrow_mut().pop(); - Ok(module) - } - - fn error_on_circular_module( - &self, - span: Span, - path: &Path, - included_mod_stack: &[PathBuf], - ) -> PResult<'a, ()> { - 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.struct_span_err(span, &err[..])); +/// Reads a module from a source file. +fn eval_src_mod<'a>( + sess: &'a ParseSess, + cfg_mods: bool, + path: PathBuf, + dir_ownership: DirectoryOwnership, + id: ast::Ident, +) -> PResult<'a, (Mod, Vec)> { + let mut included_mod_stack = 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: "); + for p in &included_mod_stack[i..] { + err.push_str(&p.to_string_lossy()); + err.push_str(" -> "); } - Ok(()) + err.push_str(&path.to_string_lossy()); + return Err(sess.span_diagnostic.struct_span_err(id.span, &err[..])); } + included_mod_stack.push(path.clone()); + drop(included_mod_stack); + + let mut p0 = + new_sub_parser_from_file(sess, &path, dir_ownership, Some(id.to_string()), id.span); + p0.cfg_mods = cfg_mods; + let mut module = p0.parse_mod(&token::Eof)?; + module.0.inline = false; + + sess.included_mod_stack.borrow_mut().pop(); + Ok(module) } fn push_directory( -- cgit 1.4.1-3-g733a5 From b9e1b2661159a9c63d47ef181c259465b90dca6d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 11:18:26 +0100 Subject: expand: use push_directory --- src/librustc_expand/expand.rs | 14 +++++++------- src/librustc_parse/parser/mod.rs | 2 +- src/librustc_parse/parser/module.rs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 4d0548f3f86..38b8ab62212 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -18,6 +18,7 @@ use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::configure; +use rustc_parse::parser::module; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; use rustc_parse::DirectoryOwnership; @@ -1448,13 +1449,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { module.mod_path.push(item.ident); if inline { - if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, sym::path) { - self.cx.current_expansion.directory_ownership = - DirectoryOwnership::Owned { relative: None }; - module.directory.push(&*path.as_str()); - } else { - module.directory.push(&*item.ident.as_str()); - } + module::push_directory( + item.ident, + &item.attrs, + &mut self.cx.current_expansion.directory_ownership, + &mut module.directory, + ); } else { let path = self.cx.parse_sess.source_map().span_to_unmapped_path(inner); let mut path = match path { diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 9376c7c1c72..40dc9275b32 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -1,7 +1,7 @@ pub mod attr; mod expr; mod item; -mod module; +pub mod module; pub use module::{ModulePath, ModulePathSuccess}; mod pat; mod path; diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 245d06333f7..d4cf39e28b0 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -133,7 +133,7 @@ fn eval_src_mod<'a>( Ok(module) } -fn push_directory( +pub fn push_directory( id: Ident, attrs: &[Attribute], dir_ownership: &mut DirectoryOwnership, -- cgit 1.4.1-3-g733a5 From 8bab88f2d9d1c81ab8d80d903359900ef106d21e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 12:19:27 +0100 Subject: de-fatalize outline module parsing --- src/librustc_ast/ast.rs | 2 +- src/librustc_parse/parser/module.rs | 37 ++++++++++++------------- src/test/ui/mod/mod_file_disambig.rs | 1 + src/test/ui/mod/mod_file_disambig.stderr | 11 ++++++-- src/test/ui/parser/circular_modules_main.rs | 2 +- src/test/ui/parser/circular_modules_main.stderr | 14 +++++++++- src/test/ui/parser/mod_file_not_exist.rs | 1 + src/test/ui/parser/mod_file_not_exist.stderr | 11 ++++++-- 8 files changed, 52 insertions(+), 27 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 68960ba9fe9..e3077b9897c 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -2153,7 +2153,7 @@ impl FnRetTy { /// Module declaration. /// /// E.g., `mod foo;` or `mod foo { .. }`. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)] pub struct Mod { /// A span from the first token past `{` to the last token until `}`. /// For `mod foo;`, the inner span ranges from the first token diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index d4cf39e28b0..8f99d88b8e4 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -8,7 +8,7 @@ use rustc_ast::attr; use rustc_ast::token::{self, TokenKind}; use rustc_errors::{struct_span_err, PResult}; use rustc_session::parse::ParseSess; -use rustc_span::source_map::{FileName, Span, DUMMY_SP}; +use rustc_span::source_map::{FileName, Span}; use rustc_span::symbol::sym; use std::path::{self, Path, PathBuf}; @@ -24,7 +24,7 @@ pub struct ModulePath<'a> { // Public for rustfmt usage. pub struct ModulePathSuccess { pub path: PathBuf, - pub directory_ownership: DirectoryOwnership, + pub ownership: DirectoryOwnership, } impl<'a> Parser<'a> { @@ -45,16 +45,13 @@ impl<'a> Parser<'a> { let (module, mut inner_attrs) = 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 } = submod_path( - self.sess, - id, - &attrs, - self.directory.ownership, - &self.directory.path, - )?; - eval_src_mod(self.sess, self.cfg_mods, path, directory_ownership, id)? + let dir = &self.directory; + submod_path(self.sess, id, &attrs, dir.ownership, &dir.path) + .and_then(|r| eval_src_mod(self.sess, self.cfg_mods, r.path, r.ownership, id)) + .map_err(|mut err| err.emit()) + .unwrap_or_default() } else { - (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new()) + Default::default() } } else { let old_directory = self.directory.clone(); @@ -162,12 +159,12 @@ pub fn push_directory( fn submod_path<'a>( sess: &'a ParseSess, id: ast::Ident, - outer_attrs: &[Attribute], - directory_ownership: DirectoryOwnership, + attrs: &[Attribute], + ownership: DirectoryOwnership, dir_path: &Path, ) -> PResult<'a, ModulePathSuccess> { - if let Some(path) = submod_path_from_attr(outer_attrs, dir_path) { - let directory_ownership = match path.file_name().and_then(|s| s.to_str()) { + if let Some(path) = submod_path_from_attr(attrs, dir_path) { + let 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, @@ -178,16 +175,16 @@ fn submod_path<'a>( Some(_) => DirectoryOwnership::Owned { relative: None }, _ => DirectoryOwnership::UnownedViaMod, }; - return Ok(ModulePathSuccess { directory_ownership, path }); + return Ok(ModulePathSuccess { ownership, path }); } - let relative = match directory_ownership { + let relative = match ownership { DirectoryOwnership::Owned { relative } => relative, DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None, }; let ModulePath { path_exists, name, result } = default_submod_path(sess, id, relative, dir_path); - match directory_ownership { + match ownership { DirectoryOwnership::Owned { .. } => Ok(result?), DirectoryOwnership::UnownedViaBlock => { let _ = result.map_err(|mut err| err.cancel()); @@ -300,11 +297,11 @@ pub fn default_submod_path<'a>( let result = match (default_exists, secondary_exists) { (true, false) => Ok(ModulePathSuccess { path: default_path, - directory_ownership: DirectoryOwnership::Owned { relative: Some(id) }, + ownership: DirectoryOwnership::Owned { relative: Some(id) }, }), (false, true) => Ok(ModulePathSuccess { path: secondary_path, - directory_ownership: DirectoryOwnership::Owned { relative: None }, + ownership: DirectoryOwnership::Owned { relative: None }, }), (false, false) => { let mut err = struct_span_err!( diff --git a/src/test/ui/mod/mod_file_disambig.rs b/src/test/ui/mod/mod_file_disambig.rs index ef203ef082b..7b182421d34 100644 --- a/src/test/ui/mod/mod_file_disambig.rs +++ b/src/test/ui/mod/mod_file_disambig.rs @@ -2,4 +2,5 @@ mod mod_file_disambig_aux; //~ ERROR file for module `mod_file_disambig_aux` fou fn main() { assert_eq!(mod_file_aux::bar(), 10); + //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` } diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 2b77d866fb3..230bfa79916 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -6,6 +6,13 @@ LL | mod mod_file_disambig_aux; | = help: delete or rename one of them to remove the ambiguity -error: aborting due to previous error +error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` + --> $DIR/mod_file_disambig.rs:4:16 + | +LL | assert_eq!(mod_file_aux::bar(), 10); + | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0584`. +Some errors have detailed explanations: E0433, E0584. +For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/parser/circular_modules_main.rs b/src/test/ui/parser/circular_modules_main.rs index b85003bf091..1ae36a1f760 100644 --- a/src/test/ui/parser/circular_modules_main.rs +++ b/src/test/ui/parser/circular_modules_main.rs @@ -6,5 +6,5 @@ pub fn hi_str() -> String { } fn main() { - circular_modules_hello::say_hello(); + circular_modules_hello::say_hello(); //~ ERROR cannot find function `say_hello` in module } diff --git a/src/test/ui/parser/circular_modules_main.stderr b/src/test/ui/parser/circular_modules_main.stderr index 33865fb7bca..ca84f2d2854 100644 --- a/src/test/ui/parser/circular_modules_main.stderr +++ b/src/test/ui/parser/circular_modules_main.stderr @@ -4,5 +4,17 @@ error: circular modules: $DIR/circular_modules_hello.rs -> $DIR/circular_modules LL | mod circular_modules_hello; | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0425]: cannot find function `say_hello` in module `circular_modules_hello` + --> $DIR/circular_modules_main.rs:9:29 + | +LL | circular_modules_hello::say_hello(); + | ^^^^^^^^^ not found in `circular_modules_hello` + | +help: possible candidate is found in another module, you can import it into scope + | +LL | use circular_modules_hello::say_hello; + | + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/parser/mod_file_not_exist.rs b/src/test/ui/parser/mod_file_not_exist.rs index 71fbc7aea45..aee778d1013 100644 --- a/src/test/ui/parser/mod_file_not_exist.rs +++ b/src/test/ui/parser/mod_file_not_exist.rs @@ -5,4 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); + //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index db3ea04ac76..c298c51c4f8 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -6,6 +6,13 @@ LL | mod not_a_real_file; | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error: aborting due to previous error +error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` + --> $DIR/mod_file_not_exist.rs:7:16 + | +LL | assert_eq!(mod_file_aux::bar(), 10); + | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0583`. +Some errors have detailed explanations: E0433, E0583. +For more information about an error, try `rustc --explain E0433`. -- cgit 1.4.1-3-g733a5 From 463995fe2974e2473392ddf7be8699746f6b7dac Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 12:33:15 +0100 Subject: extract parse_external_module --- src/librustc_parse/parser/module.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 8f99d88b8e4..0701b733076 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -44,12 +44,8 @@ impl<'a> Parser<'a> { let id = self.parse_ident()?; let (module, mut inner_attrs) = 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 dir = &self.directory; - submod_path(self.sess, id, &attrs, dir.ownership, &dir.path) - .and_then(|r| eval_src_mod(self.sess, self.cfg_mods, r.path, r.ownership, id)) - .map_err(|mut err| err.emit()) - .unwrap_or_default() + parse_external_module(self.sess, self.cfg_mods, id, dir.ownership, &dir.path, attrs) } else { Default::default() } @@ -99,6 +95,20 @@ impl<'a> Parser<'a> { } } +fn parse_external_module( + sess: &ParseSess, + cfg_mods: bool, + id: ast::Ident, + ownership: DirectoryOwnership, + dir_path: &Path, + attrs: &[Attribute], +) -> (Mod, Vec) { + submod_path(sess, id, &attrs, ownership, dir_path) + .and_then(|r| eval_src_mod(sess, cfg_mods, r.path, r.ownership, id)) + .map_err(|mut err| err.emit()) + .unwrap_or_default() +} + /// Reads a module from a source file. fn eval_src_mod<'a>( sess: &'a ParseSess, -- cgit 1.4.1-3-g733a5 From 59bf8a07f93d194abcc880a366bda37563a9402b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 13:29:37 +0100 Subject: extract error_on_circular_module --- src/librustc_parse/parser/module.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 0701b733076..66faf295b72 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -118,15 +118,7 @@ fn eval_src_mod<'a>( id: ast::Ident, ) -> PResult<'a, (Mod, Vec)> { let mut included_mod_stack = 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: "); - for p in &included_mod_stack[i..] { - err.push_str(&p.to_string_lossy()); - err.push_str(" -> "); - } - err.push_str(&path.to_string_lossy()); - return Err(sess.span_diagnostic.struct_span_err(id.span, &err[..])); - } + error_on_circular_module(sess, id.span, &path, &included_mod_stack)?; included_mod_stack.push(path.clone()); drop(included_mod_stack); @@ -140,6 +132,24 @@ fn eval_src_mod<'a>( Ok(module) } +fn error_on_circular_module<'a>( + sess: &'a ParseSess, + span: Span, + path: &Path, + included_mod_stack: &[PathBuf], +) -> PResult<'a, ()> { + if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { + let mut err = String::from("circular modules: "); + for p in &included_mod_stack[i..] { + err.push_str(&p.to_string_lossy()); + err.push_str(" -> "); + } + err.push_str(&path.to_string_lossy()); + return Err(sess.span_diagnostic.struct_span_err(span, &err[..])); + } + Ok(()) +} + pub fn push_directory( id: Ident, attrs: &[Attribute], -- cgit 1.4.1-3-g733a5 From 83a757a9ca0d0f61bd2325e9a95d591d53e01129 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 13:36:20 +0100 Subject: outline modules: parse -> expand. --- src/librustc_builtin_macros/source_util.rs | 5 +- src/librustc_expand/expand.rs | 77 ++++++++++++--------- src/librustc_expand/mbe/macro_rules.rs | 37 ++++------ src/librustc_parse/config.rs | 9 --- src/librustc_parse/lib.rs | 20 ++---- src/librustc_parse/parser/mod.rs | 33 +-------- src/librustc_parse/parser/module.rs | 105 +++++++++++++---------------- src/librustc_parse/parser/stmt.rs | 10 +-- 8 files changed, 116 insertions(+), 180 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_builtin_macros/source_util.rs b/src/librustc_builtin_macros/source_util.rs index 5ad72a7443d..662bbe6a287 100644 --- a/src/librustc_builtin_macros/source_util.rs +++ b/src/librustc_builtin_macros/source_util.rs @@ -5,7 +5,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; use rustc_expand::base::{self, *}; use rustc_expand::panictry; -use rustc_parse::{self, new_sub_parser_from_file, parser::Parser, DirectoryOwnership}; +use rustc_parse::{self, new_sub_parser_from_file, parser::Parser}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::symbol::Symbol; use rustc_span::{self, Pos, Span}; @@ -108,8 +108,7 @@ pub fn expand_include<'cx>( return DummyResult::any(sp); } }; - let directory_ownership = DirectoryOwnership::Owned { relative: None }; - let p = new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp); + let p = new_sub_parser_from_file(cx.parse_sess(), &file, None, sp); struct ExpandResult<'a> { p: Parser<'a>, diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 38b8ab62212..61a34a39d58 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -18,10 +18,10 @@ use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::configure; -use rustc_parse::parser::module; +use rustc_parse::parser::module::{parse_external_mod, push_directory}; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; -use rustc_parse::DirectoryOwnership; +use rustc_parse::{Directory, DirectoryOwnership}; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; @@ -1428,8 +1428,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_items(); } + let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck. + let ident = item.ident; + match item.kind { ast::ItemKind::MacCall(..) => { + item.attrs = attrs; self.check_attributes(&item.attrs); item.and_then(|item| match item.kind { ItemKind::MacCall(mac) => self @@ -1441,45 +1445,56 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { _ => unreachable!(), }) } - ast::ItemKind::Mod(ast::Mod { inner, inline, .. }) - if item.ident != Ident::invalid() => - { - let orig_directory_ownership = self.cx.current_expansion.directory_ownership; + ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => { + let sess = self.cx.parse_sess; + let orig_ownership = self.cx.current_expansion.directory_ownership; let mut module = (*self.cx.current_expansion.module).clone(); - module.mod_path.push(item.ident); - - if inline { - module::push_directory( - item.ident, - &item.attrs, - &mut self.cx.current_expansion.directory_ownership, - &mut module.directory, - ); + + let pushed = &mut false; // Record `parse_external_mod` pushing so we can pop. + let dir = Directory { ownership: orig_ownership, path: module.directory }; + let Directory { ownership, path } = if old_mod.inline { + // Inline `mod foo { ... }`, but we still need to push directories. + item.attrs = attrs; + push_directory(ident, &item.attrs, dir) } else { - let path = self.cx.parse_sess.source_map().span_to_unmapped_path(inner); - let mut path = match path { - FileName::Real(path) => path, - other => PathBuf::from(other.to_string()), - }; - let directory_ownership = match path.file_name().unwrap().to_str() { - Some("mod.rs") => DirectoryOwnership::Owned { relative: None }, - Some(_) => DirectoryOwnership::Owned { relative: Some(item.ident) }, - None => DirectoryOwnership::UnownedViaMod, + // We have an outline `mod foo;` so we need to parse the file. + let (new_mod, dir) = parse_external_mod(sess, ident, dir, &mut attrs, pushed); + *old_mod = new_mod; + item.attrs = attrs; + // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure. + item = match self.configure(item) { + Some(node) => node, + None => { + if *pushed { + sess.included_mod_stack.borrow_mut().pop(); + } + return Default::default(); + } }; - path.pop(); - module.directory = path; - self.cx.current_expansion.directory_ownership = directory_ownership; - } + dir + }; + // Set the module info before we flat map. + self.cx.current_expansion.directory_ownership = ownership; + module.directory = path; + module.mod_path.push(ident); let orig_module = mem::replace(&mut self.cx.current_expansion.module, Rc::new(module)); + let result = noop_flat_map_item(item, self); + + // Restore the module info. self.cx.current_expansion.module = orig_module; - self.cx.current_expansion.directory_ownership = orig_directory_ownership; + self.cx.current_expansion.directory_ownership = orig_ownership; + if *pushed { + sess.included_mod_stack.borrow_mut().pop(); + } result } - - _ => noop_flat_map_item(item, self), + _ => { + item.attrs = attrs; + noop_flat_map_item(item, self) + } } } diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 2268c9b3854..1628d8bfdbc 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -1,4 +1,4 @@ -use crate::base::{DummyResult, ExpansionData, ExtCtxt, MacResult, TTMacroExpander}; +use crate::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; use crate::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind}; use crate::mbe; @@ -18,7 +18,6 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder, FatalError}; use rustc_feature::Features; use rustc_parse::parser::Parser; -use rustc_parse::Directory; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; @@ -182,6 +181,8 @@ fn generic_extension<'cx>( lhses: &[mbe::TokenTree], rhses: &[mbe::TokenTree], ) -> Box { + let sess = cx.parse_sess; + if cx.trace_macros() { let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone())); trace_macros_note(&mut cx.expansions, sp, msg); @@ -209,7 +210,7 @@ fn generic_extension<'cx>( // hacky, but speeds up the `html5ever` benchmark significantly. (Issue // 68836 suggests a more comprehensive but more complex change to deal with // this situation.) - let parser = parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone()); + let parser = parser_from_cx(sess, arg.clone()); for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers @@ -222,14 +223,13 @@ fn generic_extension<'cx>( // This is used so that if a matcher is not `Success(..)`ful, // then the spans which became gated when parsing the unsuccessful matcher // are not recorded. On the first `Success(..)`ful matcher, the spans are merged. - let mut gated_spans_snapshot = - mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut()); + let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut()); match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) { Success(named_matches) => { // The matcher was `Success(..)`ful. // Merge the gated spans from parsing the matcher with the pre-existing ones. - cx.parse_sess.gated_spans.merge(gated_spans_snapshot); + sess.gated_spans.merge(gated_spans_snapshot); let rhs = match rhses[i] { // ignore delimiters @@ -258,11 +258,7 @@ fn generic_extension<'cx>( trace_macros_note(&mut cx.expansions, sp, msg); } - let directory = Directory { - path: cx.current_expansion.module.directory.clone(), - ownership: cx.current_expansion.directory_ownership, - }; - let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None); + let mut p = Parser::new(cx.parse_sess(), tts, false, None); p.root_module_name = cx.current_expansion.module.mod_path.last().map(|id| id.to_string()); p.last_type_ascription = cx.current_expansion.prior_type_ascription; @@ -289,7 +285,7 @@ fn generic_extension<'cx>( // The matcher was not `Success(..)`ful. // Restore to the state before snapshotting and maybe try again. - mem::swap(&mut gated_spans_snapshot, &mut cx.parse_sess.gated_spans.spans.borrow_mut()); + mem::swap(&mut gated_spans_snapshot, &mut sess.gated_spans.spans.borrow_mut()); } drop(parser); @@ -309,8 +305,7 @@ fn generic_extension<'cx>( mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], _ => continue, }; - let parser = parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone()); - match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) { + match parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt) { Success(_) => { if comma_span.is_dummy() { err.note("you might be missing a comma"); @@ -392,7 +387,7 @@ pub fn compile_declarative_macro( ), ]; - let parser = Parser::new(sess, body, None, true, true, rustc_parse::MACRO_ARGUMENTS); + let parser = Parser::new(sess, body, true, rustc_parse::MACRO_ARGUMENTS); let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) { Success(m) => m, Failure(token, msg) => { @@ -1209,16 +1204,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { } } -fn parser_from_cx<'cx>( - current_expansion: &'cx ExpansionData, - sess: &'cx ParseSess, - tts: TokenStream, -) -> Parser<'cx> { - let directory = Directory { - path: current_expansion.module.directory.clone(), - ownership: current_expansion.directory_ownership, - }; - Parser::new(sess, tts, Some(directory), true, true, rustc_parse::MACRO_ARGUMENTS) +fn parser_from_cx<'cx>(sess: &'cx ParseSess, tts: TokenStream) -> Parser<'cx> { + Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS) } /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs index d209da866e1..c611f249420 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_parse/config.rs @@ -538,12 +538,3 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { fn is_cfg(attr: &Attribute) -> bool { attr.check_name(sym::cfg) } - -/// Process the potential `cfg` attributes on a module. -/// Also determine if the module should be included in this configuration. -pub fn process_configure_mod(sess: &ParseSess, cfg_mods: bool, attrs: &mut Vec) -> bool { - // Don't perform gated feature checking. - let mut strip_unconfigured = StripUnconfigured { sess, features: None }; - strip_unconfigured.process_cfg_attrs(attrs); - !cfg_mods || strip_unconfigured.in_cfg(&attrs) -} diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 884499ff2dd..bcaae02942e 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -3,6 +3,7 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] +#![feature(try_blocks)] use rustc_ast::ast; use rustc_ast::token::{self, Nonterminal}; @@ -119,10 +120,7 @@ pub fn maybe_new_parser_from_source_str( name: FileName, source: String, ) -> Result, Vec> { - let mut parser = - maybe_source_file_to_parser(sess, sess.source_map().new_source_file(name, source))?; - parser.recurse_into_file_modules = false; - Ok(parser) + maybe_source_file_to_parser(sess, sess.source_map().new_source_file(name, source)) } /// Creates a new parser, handling errors as appropriate if the file doesn't exist. @@ -146,12 +144,10 @@ pub fn maybe_new_parser_from_file<'a>( pub fn new_sub_parser_from_file<'a>( sess: &'a ParseSess, path: &Path, - directory_ownership: DirectoryOwnership, module_name: Option, sp: Span, ) -> Parser<'a> { let mut p = source_file_to_parser(sess, file_to_source_file(sess, path, Some(sp))); - p.directory.ownership = directory_ownership; p.root_module_name = module_name; p } @@ -257,7 +253,7 @@ pub fn stream_to_parser<'a>( stream: TokenStream, subparser_name: Option<&'static str>, ) -> Parser<'a> { - Parser::new(sess, stream, None, true, false, subparser_name) + Parser::new(sess, stream, false, subparser_name) } /// Given a stream, the `ParseSess` and the base directory, produces a parser. @@ -271,12 +267,8 @@ pub fn stream_to_parser<'a>( /// The main usage of this function is outside of rustc, for those who uses /// librustc_ast as a library. Please do not remove this function while refactoring /// just because it is not used in rustc codebase! -pub fn stream_to_parser_with_base_dir( - sess: &ParseSess, - stream: TokenStream, - base_dir: Directory, -) -> Parser<'_> { - Parser::new(sess, stream, Some(base_dir), true, false, None) +pub fn stream_to_parser_with_base_dir(sess: &ParseSess, stream: TokenStream) -> Parser<'_> { + Parser::new(sess, stream, false, None) } /// Runs the given subparser `f` on the tokens of the given `attr`'s item. @@ -286,7 +278,7 @@ pub fn parse_in<'a, T>( name: &'static str, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, T> { - let mut parser = Parser::new(sess, tts, None, false, false, Some(name)); + let mut parser = Parser::new(sess, tts, false, Some(name)); let result = f(&mut parser)?; if parser.token != token::Eof { parser.unexpected()?; diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 40dc9275b32..f4862a6c87b 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -13,7 +13,6 @@ mod stmt; use diagnostics::Error; use crate::lexer::UnmatchedBrace; -use crate::{Directory, DirectoryOwnership}; use log::debug; use rustc_ast::ast::DUMMY_NODE_ID; @@ -28,11 +27,9 @@ use rustc_ast::util::comments::{doc_comment_style, strip_doc_comment_decoration} use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_session::parse::ParseSess; -use rustc_span::source_map::respan; +use rustc_span::source_map::{respan, Span, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{FileName, Span, DUMMY_SP}; -use std::path::PathBuf; use std::{cmp, mem, slice}; bitflags::bitflags! { @@ -93,11 +90,6 @@ pub struct Parser<'a> { /// The previous token. pub prev_token: Token, restrictions: Restrictions, - /// Used to determine the path to externally loaded source files. - pub(super) directory: Directory, - /// `true` to parse sub-modules in other files. - // Public for rustfmt usage. - pub recurse_into_file_modules: bool, /// Name of the root module this parser originated from. If `None`, then the /// name is not known. This does not change while the parser is descending /// into modules, and sub-parsers have new values for this name. @@ -105,9 +97,6 @@ pub struct Parser<'a> { expected_tokens: Vec, token_cursor: TokenCursor, desugar_doc_comments: bool, - /// `true` we should configure out of line modules as we parse. - // Public for rustfmt usage. - pub cfg_mods: bool, /// This field is used to keep track of how many left angle brackets we have seen. This is /// required in order to detect extra leading left angle brackets (`<` characters) and error /// appropriately. @@ -355,8 +344,6 @@ impl<'a> Parser<'a> { pub fn new( sess: &'a ParseSess, tokens: TokenStream, - directory: Option, - recurse_into_file_modules: bool, desugar_doc_comments: bool, subparser_name: Option<&'static str>, ) -> Self { @@ -365,11 +352,6 @@ impl<'a> Parser<'a> { token: Token::dummy(), prev_token: Token::dummy(), restrictions: Restrictions::empty(), - recurse_into_file_modules, - directory: Directory { - path: PathBuf::new(), - ownership: DirectoryOwnership::Owned { relative: None }, - }, root_module_name: None, expected_tokens: Vec::new(), token_cursor: TokenCursor { @@ -377,7 +359,6 @@ impl<'a> Parser<'a> { stack: Vec::new(), }, desugar_doc_comments, - cfg_mods: true, unmatched_angle_bracket_count: 0, max_angle_bracket_count: 0, unclosed_delims: Vec::new(), @@ -389,18 +370,6 @@ impl<'a> Parser<'a> { // Make parser point to the first token. parser.bump(); - if let Some(directory) = directory { - parser.directory = directory; - } else if !parser.token.span.is_dummy() { - if let Some(FileName::Real(path)) = - &sess.source_map().lookup_char_pos(parser.token.span.lo()).file.unmapped_path - { - if let Some(directory_path) = path.parent() { - parser.directory.path = directory_path.to_path_buf(); - } - } - } - parser } diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 66faf295b72..695afafdd82 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -1,7 +1,7 @@ use super::item::ItemInfo; use super::Parser; -use crate::{new_sub_parser_from_file, DirectoryOwnership}; +use crate::{new_sub_parser_from_file, Directory, DirectoryOwnership}; use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod}; use rustc_ast::attr; @@ -39,25 +39,12 @@ impl<'a> Parser<'a> { /// Parses a `mod { ... }` or `mod ;` item. pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { - let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs); - let id = self.parse_ident()?; let (module, mut inner_attrs) = if self.eat(&token::Semi) { - if in_cfg && self.recurse_into_file_modules { - let dir = &self.directory; - parse_external_module(self.sess, self.cfg_mods, id, dir.ownership, &dir.path, attrs) - } else { - Default::default() - } + Default::default() } else { - let old_directory = self.directory.clone(); - push_directory(id, &attrs, &mut self.directory.ownership, &mut self.directory.path); - self.expect(&token::OpenDelim(token::Brace))?; - let module = self.parse_mod(&token::CloseDelim(token::Brace))?; - - self.directory = old_directory; - module + self.parse_mod(&token::CloseDelim(token::Brace))? }; attrs.append(&mut inner_attrs); Ok((id, ItemKind::Mod(module))) @@ -95,41 +82,45 @@ impl<'a> Parser<'a> { } } -fn parse_external_module( +pub fn parse_external_mod( sess: &ParseSess, - cfg_mods: bool, - id: ast::Ident, - ownership: DirectoryOwnership, - dir_path: &Path, - attrs: &[Attribute], -) -> (Mod, Vec) { - submod_path(sess, id, &attrs, ownership, dir_path) - .and_then(|r| eval_src_mod(sess, cfg_mods, r.path, r.ownership, id)) - .map_err(|mut err| err.emit()) - .unwrap_or_default() -} - -/// Reads a module from a source file. -fn eval_src_mod<'a>( - sess: &'a ParseSess, - cfg_mods: bool, - path: PathBuf, - dir_ownership: DirectoryOwnership, id: ast::Ident, -) -> PResult<'a, (Mod, Vec)> { - let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); - error_on_circular_module(sess, id.span, &path, &included_mod_stack)?; - included_mod_stack.push(path.clone()); - drop(included_mod_stack); - - let mut p0 = - new_sub_parser_from_file(sess, &path, dir_ownership, Some(id.to_string()), id.span); - p0.cfg_mods = cfg_mods; - let mut module = p0.parse_mod(&token::Eof)?; - module.0.inline = false; + Directory { mut ownership, path }: Directory, + attrs: &mut Vec, + pop_mod_stack: &mut bool, +) -> (Mod, Directory) { + // We bail on the first error, but that error does not cause a fatal error... (1) + let result: PResult<'_, _> = try { + // Extract the file path and the new ownership. + let mp = submod_path(sess, id, &attrs, ownership, &path)?; + ownership = mp.ownership; + + // Ensure file paths are acyclic. + let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); + error_on_circular_module(sess, id.span, &mp.path, &included_mod_stack)?; + included_mod_stack.push(mp.path.clone()); + *pop_mod_stack = true; // We have pushed, so notify caller. + drop(included_mod_stack); + + // Actually parse the external file as amodule. + let mut p0 = new_sub_parser_from_file(sess, &mp.path, Some(id.to_string()), id.span); + let mut module = p0.parse_mod(&token::Eof)?; + module.0.inline = false; + module + }; + // (1) ...instead, we return a dummy module. + let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default(); + attrs.append(&mut new_attrs); + + // Extract the directory path for submodules of `module`. + let path = sess.source_map().span_to_unmapped_path(module.inner); + let mut path = match path { + FileName::Real(path) => path, + other => PathBuf::from(other.to_string()), + }; + path.pop(); - sess.included_mod_stack.borrow_mut().pop(); - Ok(module) + (module, Directory { ownership, path }) } fn error_on_circular_module<'a>( @@ -153,12 +144,11 @@ fn error_on_circular_module<'a>( pub fn push_directory( id: Ident, attrs: &[Attribute], - dir_ownership: &mut DirectoryOwnership, - dir_path: &mut PathBuf, -) { - if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { - dir_path.push(&*path.as_str()); - *dir_ownership = DirectoryOwnership::Owned { relative: None }; + Directory { mut ownership, mut path }: Directory, +) -> Directory { + if let Some(filename) = attr::first_attr_value_str_by_name(attrs, sym::path) { + path.push(&*filename.as_str()); + 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 @@ -166,14 +156,15 @@ pub fn push_directory( // // 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 } = dir_ownership { + if let DirectoryOwnership::Owned { relative } = &mut ownership { if let Some(ident) = relative.take() { // Remove the relative offset. - dir_path.push(&*ident.as_str()); + path.push(&*ident.as_str()); } } - dir_path.push(&*id.as_str()); + path.push(&*id.as_str()); } + Directory { ownership, path } } fn submod_path<'a>( diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index 4359823be08..d40597d8fcb 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -5,7 +5,6 @@ use super::pat::GateOr; use super::path::PathStyle; use super::{BlockMode, Parser, Restrictions, SemiColonMode}; use crate::maybe_whole; -use crate::DirectoryOwnership; use rustc_ast::ast; use rustc_ast::ast::{AttrStyle, AttrVec, Attribute, MacCall, MacStmtStyle}; @@ -54,7 +53,7 @@ impl<'a> Parser<'a> { // that starts like a path (1 token), but it fact not a path. // Also, we avoid stealing syntax from `parse_item_`. self.parse_stmt_path_start(lo, attrs)? - } else if let Some(item) = self.parse_stmt_item(attrs.clone())? { + } else if let Some(item) = self.parse_item_common(attrs.clone(), false, true, |_| true)? { // FIXME: Bad copy of attrs self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) } else if self.eat(&token::Semi) { @@ -72,13 +71,6 @@ impl<'a> Parser<'a> { Ok(Some(stmt)) } - fn parse_stmt_item(&mut self, attrs: Vec) -> PResult<'a, Option> { - let old = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); - let item = self.parse_item_common(attrs, false, true, |_| true)?; - self.directory.ownership = old; - Ok(item) - } - fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec) -> PResult<'a, Stmt> { let path = self.parse_path(PathStyle::Expr)?; -- cgit 1.4.1-3-g733a5 From f1ca9969bfb1a69e98dab6ff0413e099532f57f2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 21:50:01 +0100 Subject: parse: module parsing -> item.rs --- src/librustc_parse/parser/item.rs | 69 ++++++++++++++++++++++++++++++++++--- src/librustc_parse/parser/module.rs | 62 ++------------------------------- 2 files changed, 66 insertions(+), 65 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index e927bcd07e2..d0da8e6c7c1 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -4,14 +4,18 @@ use super::{FollowedByType, Parser, PathStyle}; use crate::maybe_whole; -use rustc_ast::ast::{self, Async, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; -use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind}; -use rustc_ast::ast::{BindingMode, Block, FnDecl, FnSig, MacArgs, MacCall, MacDelimiter, Param}; -use rustc_ast::ast::{Const, Defaultness, IsAuto, PathSegment, Unsafe, UseTree, UseTreeKind}; +use rustc_ast::ast::{self, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; +use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind, Mod}; +use rustc_ast::ast::{ + Async, Const, Defaultness, IsAuto, PathSegment, Unsafe, UseTree, UseTreeKind, +}; +use rustc_ast::ast::{ + BindingMode, Block, FnDecl, FnSig, MacArgs, MacCall, MacDelimiter, Param, SelfKind, +}; use rustc_ast::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; use rustc_ast::ast::{FnHeader, ForeignItem, Mutability, SelfKind, Visibility, VisibilityKind}; use rustc_ast::ptr::P; -use rustc_ast::token; +use rustc_ast::token::{self, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, PResult, StashKey}; @@ -23,6 +27,61 @@ use log::debug; use std::convert::TryFrom; use std::mem; +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, ast::Crate> { + let lo = self.token.span; + let (module, attrs) = self.parse_mod(&token::Eof)?; + let span = lo.to(self.token.span); + let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`. + Ok(ast::Crate { attrs, module, span, proc_macros }) + } + + /// Parses a `mod { ... }` or `mod ;` item. + pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + let id = self.parse_ident()?; + let (module, mut inner_attrs) = if self.eat(&token::Semi) { + Default::default() + } else { + self.expect(&token::OpenDelim(token::Brace))?; + self.parse_mod(&token::CloseDelim(token::Brace))? + }; + attrs.append(&mut inner_attrs); + Ok((id, ItemKind::Mod(module))) + } + + /// Parses the contents of a module (inner attributes followed by module items). + pub fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec)> { + let lo = self.token.span; + let attrs = self.parse_inner_attributes()?; + let module = self.parse_mod_items(term, lo)?; + Ok((module, 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 = super::token_descr(&self.token); + if !self.maybe_consume_incorrect_semicolon(&items) { + let msg = &format!("expected item, found {}", token_str); + let mut err = self.struct_span_err(self.token.span, msg); + err.span_label(self.token.span, "expected item"); + return Err(err); + } + } + + let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span }; + + Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) + } +} + pub(super) type ItemInfo = (Ident, ItemKind); impl<'a> Parser<'a> { diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 695afafdd82..2c752bd9f0a 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -1,11 +1,8 @@ -use super::item::ItemInfo; -use super::Parser; - use crate::{new_sub_parser_from_file, Directory, DirectoryOwnership}; -use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod}; +use rustc_ast::ast::{self, Attribute, Ident, Mod}; use rustc_ast::attr; -use rustc_ast::token::{self, TokenKind}; +use rustc_ast::token; use rustc_errors::{struct_span_err, PResult}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FileName, Span}; @@ -27,61 +24,6 @@ pub struct ModulePathSuccess { pub ownership: DirectoryOwnership, } -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 (module, attrs) = self.parse_mod(&token::Eof)?; - let span = lo.to(self.token.span); - let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`. - Ok(ast::Crate { attrs, module, span, proc_macros }) - } - - /// Parses a `mod { ... }` or `mod ;` item. - pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { - let id = self.parse_ident()?; - let (module, mut inner_attrs) = if self.eat(&token::Semi) { - Default::default() - } else { - self.expect(&token::OpenDelim(token::Brace))?; - self.parse_mod(&token::CloseDelim(token::Brace))? - }; - attrs.append(&mut inner_attrs); - Ok((id, ItemKind::Mod(module))) - } - - /// Parses the contents of a module (inner attributes followed by module items). - fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec)> { - let lo = self.token.span; - let attrs = self.parse_inner_attributes()?; - let module = self.parse_mod_items(term, lo)?; - Ok((module, 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 = super::token_descr(&self.token); - if !self.maybe_consume_incorrect_semicolon(&items) { - let msg = &format!("expected item, found {}", token_str); - let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(self.token.span, "expected item"); - return Err(err); - } - } - - let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span }; - - Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) - } -} - pub fn parse_external_mod( sess: &ParseSess, id: ast::Ident, -- cgit 1.4.1-3-g733a5 From ddcc8ec89de7c2637a012eb14b1b07c8b9426d1e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 22:10:37 +0100 Subject: move Directory -> parser::module --- src/librustc_expand/base.rs | 3 ++- src/librustc_expand/expand.rs | 5 +++-- src/librustc_parse/lib.rs | 18 +----------------- src/librustc_parse/parser/module.rs | 21 ++++++++++++++++++--- 4 files changed, 24 insertions(+), 23 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index f5f2a5ed43f..315a1c950d8 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -10,7 +10,8 @@ use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; -use rustc_parse::{self, parser, DirectoryOwnership, MACRO_ARGUMENTS}; +use rustc_parse::parser::module::DirectoryOwnership; +use rustc_parse::{self, parser, MACRO_ARGUMENTS}; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind}; diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 61a34a39d58..46f10ca3614 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -18,10 +18,11 @@ use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::configure; -use rustc_parse::parser::module::{parse_external_mod, push_directory}; +use rustc_parse::parser::module::{ + parse_external_mod, push_directory, Directory, DirectoryOwnership, +}; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; -use rustc_parse::{Directory, DirectoryOwnership}; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index bcaae02942e..70aa8c0074a 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -14,7 +14,7 @@ use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::str; use log::info; @@ -29,22 +29,6 @@ pub mod validate_attr; #[macro_use] pub mod config; -#[derive(Clone)] -pub struct Directory { - pub path: PathBuf, - pub ownership: DirectoryOwnership, -} - -#[derive(Copy, Clone)] -pub enum DirectoryOwnership { - Owned { - // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`. - relative: Option, - }, - UnownedViaBlock, - UnownedViaMod, -} - // A bunch of utility functions of the form `parse__from_` // where includes crate, expr, item, stmt, tts, and one that // uses a HOF to parse anything, and includes file and diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 2c752bd9f0a..e45a26bd441 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -1,8 +1,7 @@ -use crate::{new_sub_parser_from_file, Directory, DirectoryOwnership}; +use crate::new_sub_parser_from_file; use rustc_ast::ast::{self, Attribute, Ident, Mod}; -use rustc_ast::attr; -use rustc_ast::token; +use rustc_ast::{attr, token}; use rustc_errors::{struct_span_err, PResult}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FileName, Span}; @@ -10,6 +9,22 @@ use rustc_span::symbol::sym; use std::path::{self, Path, PathBuf}; +#[derive(Clone)] +pub struct Directory { + pub path: PathBuf, + pub ownership: DirectoryOwnership, +} + +#[derive(Copy, Clone)] +pub enum DirectoryOwnership { + Owned { + // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`. + relative: Option, + }, + UnownedViaBlock, + UnownedViaMod, +} + /// Information about the path to a module. // Public for rustfmt usage. pub struct ModulePath<'a> { -- cgit 1.4.1-3-g733a5 From 3796faefb1d22f496514126d3d2b5a87b948ae47 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 22:21:37 +0100 Subject: {rustc_parse::parser -> rustc_expand}::module --- src/librustc_expand/base.rs | 2 +- src/librustc_expand/expand.rs | 4 +- src/librustc_expand/lib.rs | 2 + src/librustc_expand/module.rs | 304 +++++++++++++++++++++++++++++++++++ src/librustc_parse/parser/mod.rs | 2 - src/librustc_parse/parser/module.rs | 305 ------------------------------------ 6 files changed, 308 insertions(+), 311 deletions(-) create mode 100644 src/librustc_expand/module.rs delete mode 100644 src/librustc_parse/parser/module.rs (limited to 'src/librustc_parse') diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 315a1c950d8..1e9d59ca4bf 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -1,4 +1,5 @@ use crate::expand::{self, AstFragment, Invocation}; +use crate::module::DirectoryOwnership; use rustc_ast::ast::{self, Attribute, Name, NodeId, PatKind}; use rustc_ast::mut_visit::{self, MutVisitor}; @@ -10,7 +11,6 @@ use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; -use rustc_parse::parser::module::DirectoryOwnership; use rustc_parse::{self, parser, MACRO_ARGUMENTS}; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 46f10ca3614..8e83e13fa8a 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -2,6 +2,7 @@ use crate::base::*; use crate::config::StripUnconfigured; use crate::hygiene::{ExpnData, ExpnId, ExpnKind, SyntaxContext}; use crate::mbe::macro_rules::annotate_err_with_kind; +use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership}; use crate::placeholders::{placeholder, PlaceholderExpander}; use crate::proc_macro::collect_derives; @@ -18,9 +19,6 @@ use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; use rustc_parse::configure; -use rustc_parse::parser::module::{ - parse_external_mod, push_directory, Directory, DirectoryOwnership, -}; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; diff --git a/src/librustc_expand/lib.rs b/src/librustc_expand/lib.rs index f119c956ced..98d644eb77a 100644 --- a/src/librustc_expand/lib.rs +++ b/src/librustc_expand/lib.rs @@ -4,6 +4,7 @@ #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] #![feature(proc_macro_span)] +#![feature(try_blocks)] extern crate proc_macro as pm; @@ -34,6 +35,7 @@ crate use rustc_span::hygiene; pub mod base; pub mod build; pub mod expand; +pub mod module; pub use rustc_parse::config; pub mod proc_macro; diff --git a/src/librustc_expand/module.rs b/src/librustc_expand/module.rs new file mode 100644 index 00000000000..1d4c767b84f --- /dev/null +++ b/src/librustc_expand/module.rs @@ -0,0 +1,304 @@ +use rustc_ast::ast::{self, Attribute, Ident, Mod}; +use rustc_ast::{attr, token}; +use rustc_errors::{struct_span_err, PResult}; +use rustc_parse::new_sub_parser_from_file; +use rustc_session::parse::ParseSess; +use rustc_span::source_map::{FileName, Span}; +use rustc_span::symbol::sym; + +use std::path::{self, Path, PathBuf}; + +#[derive(Clone)] +pub struct Directory { + pub path: PathBuf, + pub ownership: DirectoryOwnership, +} + +#[derive(Copy, Clone)] +pub enum DirectoryOwnership { + Owned { + // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`. + relative: Option, + }, + UnownedViaBlock, + UnownedViaMod, +} + +/// Information about the path to a module. +// Public for rustfmt usage. +pub struct ModulePath<'a> { + name: String, + path_exists: bool, + pub result: PResult<'a, ModulePathSuccess>, +} + +// Public for rustfmt usage. +pub struct ModulePathSuccess { + pub path: PathBuf, + pub ownership: DirectoryOwnership, +} + +crate fn parse_external_mod( + sess: &ParseSess, + id: ast::Ident, + Directory { mut ownership, path }: Directory, + attrs: &mut Vec, + pop_mod_stack: &mut bool, +) -> (Mod, Directory) { + // We bail on the first error, but that error does not cause a fatal error... (1) + let result: PResult<'_, _> = try { + // Extract the file path and the new ownership. + let mp = submod_path(sess, id, &attrs, ownership, &path)?; + ownership = mp.ownership; + + // Ensure file paths are acyclic. + let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); + error_on_circular_module(sess, id.span, &mp.path, &included_mod_stack)?; + included_mod_stack.push(mp.path.clone()); + *pop_mod_stack = true; // We have pushed, so notify caller. + drop(included_mod_stack); + + // Actually parse the external file as amodule. + let mut p0 = new_sub_parser_from_file(sess, &mp.path, Some(id.to_string()), id.span); + let mut module = p0.parse_mod(&token::Eof)?; + module.0.inline = false; + module + }; + // (1) ...instead, we return a dummy module. + let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default(); + attrs.append(&mut new_attrs); + + // Extract the directory path for submodules of `module`. + let path = sess.source_map().span_to_unmapped_path(module.inner); + let mut path = match path { + FileName::Real(path) => path, + other => PathBuf::from(other.to_string()), + }; + path.pop(); + + (module, Directory { ownership, path }) +} + +fn error_on_circular_module<'a>( + sess: &'a ParseSess, + span: Span, + path: &Path, + included_mod_stack: &[PathBuf], +) -> PResult<'a, ()> { + if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { + let mut err = String::from("circular modules: "); + for p in &included_mod_stack[i..] { + err.push_str(&p.to_string_lossy()); + err.push_str(" -> "); + } + err.push_str(&path.to_string_lossy()); + return Err(sess.span_diagnostic.struct_span_err(span, &err[..])); + } + Ok(()) +} + +crate fn push_directory( + id: Ident, + attrs: &[Attribute], + Directory { mut ownership, mut path }: Directory, +) -> Directory { + if let Some(filename) = attr::first_attr_value_str_by_name(attrs, sym::path) { + path.push(&*filename.as_str()); + 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 ownership { + if let Some(ident) = relative.take() { + // Remove the relative offset. + path.push(&*ident.as_str()); + } + } + path.push(&*id.as_str()); + } + Directory { ownership, path } +} + +fn submod_path<'a>( + sess: &'a ParseSess, + id: ast::Ident, + attrs: &[Attribute], + ownership: DirectoryOwnership, + dir_path: &Path, +) -> PResult<'a, ModulePathSuccess> { + if let Some(path) = submod_path_from_attr(attrs, dir_path) { + let 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, + }; + return Ok(ModulePathSuccess { ownership, path }); + } + + let relative = match ownership { + DirectoryOwnership::Owned { relative } => relative, + DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None, + }; + let ModulePath { path_exists, name, result } = + default_submod_path(sess, id, relative, dir_path); + match ownership { + DirectoryOwnership::Owned { .. } => Ok(result?), + DirectoryOwnership::UnownedViaBlock => { + let _ = result.map_err(|mut err| err.cancel()); + error_decl_mod_in_block(sess, id.span, path_exists, &name) + } + DirectoryOwnership::UnownedViaMod => { + let _ = result.map_err(|mut err| err.cancel()); + error_cannot_declare_mod_here(sess, id.span, path_exists, &name) + } + } +} + +fn error_decl_mod_in_block<'a, T>( + sess: &'a ParseSess, + id_sp: Span, + path_exists: bool, + name: &str, +) -> PResult<'a, T> { + let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute"; + let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg); + if path_exists { + let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name); + err.span_note(id_sp, &msg); + } + Err(err) +} + +fn error_cannot_declare_mod_here<'a, T>( + sess: &'a ParseSess, + id_sp: Span, + path_exists: bool, + name: &str, +) -> PResult<'a, T> { + let mut err = + sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location"); + if !id_sp.is_dummy() { + if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) { + 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 path_exists { + err.span_note( + id_sp, + &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name), + ); + } + Err(err) +} + +/// Derive a submodule path from the first found `#[path = "path_string"]`. +/// The provided `dir_path` is joined with the `path_string`. +// Public for rustfmt usage. +pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { + // Extract path string from first `#[path = "path_string"]` attribute. + let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?; + let path_string = path_string.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 path_string = path_string.replace("/", "\\"); + + Some(dir_path.join(&*path_string)) +} + +/// Returns a path to a module. +// Public for rustfmt usage. +pub fn default_submod_path<'a>( + sess: &'a ParseSess, + id: ast::Ident, + relative: Option, + dir_path: &Path, +) -> ModulePath<'a> { + // 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.name, path::MAIN_SEPARATOR); + &relative_prefix_string + } else { + "" + }; + + let mod_name = id.name.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 = sess.source_map().file_exists(&default_path); + let secondary_exists = sess.source_map().file_exists(&secondary_path); + + let result = match (default_exists, secondary_exists) { + (true, false) => Ok(ModulePathSuccess { + path: default_path, + ownership: DirectoryOwnership::Owned { relative: Some(id) }, + }), + (false, true) => Ok(ModulePathSuccess { + path: secondary_path, + ownership: DirectoryOwnership::Owned { relative: None }, + }), + (false, false) => { + let mut err = struct_span_err!( + sess.span_diagnostic, + id.span, + E0583, + "file not found for module `{}`", + mod_name, + ); + err.help(&format!( + "to create the module `{}`, create file \"{}\"", + mod_name, + default_path.display(), + )); + Err(err) + } + (true, true) => { + let mut err = struct_span_err!( + sess.span_diagnostic, + id.span, + E0584, + "file for module `{}` found at both {} and {}", + mod_name, + default_path_str, + secondary_path_str, + ); + err.help("delete or rename one of them to remove the ambiguity"); + Err(err) + } + }; + + ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result } +} diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index f4862a6c87b..bb6793d08aa 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -1,8 +1,6 @@ pub mod attr; mod expr; mod item; -pub mod module; -pub use module::{ModulePath, ModulePathSuccess}; mod pat; mod path; mod ty; diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs deleted file mode 100644 index e45a26bd441..00000000000 --- a/src/librustc_parse/parser/module.rs +++ /dev/null @@ -1,305 +0,0 @@ -use crate::new_sub_parser_from_file; - -use rustc_ast::ast::{self, Attribute, Ident, Mod}; -use rustc_ast::{attr, token}; -use rustc_errors::{struct_span_err, PResult}; -use rustc_session::parse::ParseSess; -use rustc_span::source_map::{FileName, Span}; -use rustc_span::symbol::sym; - -use std::path::{self, Path, PathBuf}; - -#[derive(Clone)] -pub struct Directory { - pub path: PathBuf, - pub ownership: DirectoryOwnership, -} - -#[derive(Copy, Clone)] -pub enum DirectoryOwnership { - Owned { - // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`. - relative: Option, - }, - UnownedViaBlock, - UnownedViaMod, -} - -/// Information about the path to a module. -// Public for rustfmt usage. -pub struct ModulePath<'a> { - name: String, - path_exists: bool, - pub result: PResult<'a, ModulePathSuccess>, -} - -// Public for rustfmt usage. -pub struct ModulePathSuccess { - pub path: PathBuf, - pub ownership: DirectoryOwnership, -} - -pub fn parse_external_mod( - sess: &ParseSess, - id: ast::Ident, - Directory { mut ownership, path }: Directory, - attrs: &mut Vec, - pop_mod_stack: &mut bool, -) -> (Mod, Directory) { - // We bail on the first error, but that error does not cause a fatal error... (1) - let result: PResult<'_, _> = try { - // Extract the file path and the new ownership. - let mp = submod_path(sess, id, &attrs, ownership, &path)?; - ownership = mp.ownership; - - // Ensure file paths are acyclic. - let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); - error_on_circular_module(sess, id.span, &mp.path, &included_mod_stack)?; - included_mod_stack.push(mp.path.clone()); - *pop_mod_stack = true; // We have pushed, so notify caller. - drop(included_mod_stack); - - // Actually parse the external file as amodule. - let mut p0 = new_sub_parser_from_file(sess, &mp.path, Some(id.to_string()), id.span); - let mut module = p0.parse_mod(&token::Eof)?; - module.0.inline = false; - module - }; - // (1) ...instead, we return a dummy module. - let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default(); - attrs.append(&mut new_attrs); - - // Extract the directory path for submodules of `module`. - let path = sess.source_map().span_to_unmapped_path(module.inner); - let mut path = match path { - FileName::Real(path) => path, - other => PathBuf::from(other.to_string()), - }; - path.pop(); - - (module, Directory { ownership, path }) -} - -fn error_on_circular_module<'a>( - sess: &'a ParseSess, - span: Span, - path: &Path, - included_mod_stack: &[PathBuf], -) -> PResult<'a, ()> { - if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { - let mut err = String::from("circular modules: "); - for p in &included_mod_stack[i..] { - err.push_str(&p.to_string_lossy()); - err.push_str(" -> "); - } - err.push_str(&path.to_string_lossy()); - return Err(sess.span_diagnostic.struct_span_err(span, &err[..])); - } - Ok(()) -} - -pub fn push_directory( - id: Ident, - attrs: &[Attribute], - Directory { mut ownership, mut path }: Directory, -) -> Directory { - if let Some(filename) = attr::first_attr_value_str_by_name(attrs, sym::path) { - path.push(&*filename.as_str()); - 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 ownership { - if let Some(ident) = relative.take() { - // Remove the relative offset. - path.push(&*ident.as_str()); - } - } - path.push(&*id.as_str()); - } - Directory { ownership, path } -} - -fn submod_path<'a>( - sess: &'a ParseSess, - id: ast::Ident, - attrs: &[Attribute], - ownership: DirectoryOwnership, - dir_path: &Path, -) -> PResult<'a, ModulePathSuccess> { - if let Some(path) = submod_path_from_attr(attrs, dir_path) { - let 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, - }; - return Ok(ModulePathSuccess { ownership, path }); - } - - let relative = match ownership { - DirectoryOwnership::Owned { relative } => relative, - DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None, - }; - let ModulePath { path_exists, name, result } = - default_submod_path(sess, id, relative, dir_path); - match ownership { - DirectoryOwnership::Owned { .. } => Ok(result?), - DirectoryOwnership::UnownedViaBlock => { - let _ = result.map_err(|mut err| err.cancel()); - error_decl_mod_in_block(sess, id.span, path_exists, &name) - } - DirectoryOwnership::UnownedViaMod => { - let _ = result.map_err(|mut err| err.cancel()); - error_cannot_declare_mod_here(sess, id.span, path_exists, &name) - } - } -} - -fn error_decl_mod_in_block<'a, T>( - sess: &'a ParseSess, - id_sp: Span, - path_exists: bool, - name: &str, -) -> PResult<'a, T> { - let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute"; - let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg); - if path_exists { - let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name); - err.span_note(id_sp, &msg); - } - Err(err) -} - -fn error_cannot_declare_mod_here<'a, T>( - sess: &'a ParseSess, - id_sp: Span, - path_exists: bool, - name: &str, -) -> PResult<'a, T> { - let mut err = - sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location"); - if !id_sp.is_dummy() { - if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) { - 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 path_exists { - err.span_note( - id_sp, - &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name), - ); - } - Err(err) -} - -/// Derive a submodule path from the first found `#[path = "path_string"]`. -/// The provided `dir_path` is joined with the `path_string`. -// Public for rustfmt usage. -pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { - // Extract path string from first `#[path = "path_string"]` attribute. - let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?; - let path_string = path_string.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 path_string = path_string.replace("/", "\\"); - - Some(dir_path.join(&*path_string)) -} - -/// Returns a path to a module. -// Public for rustfmt usage. -pub fn default_submod_path<'a>( - sess: &'a ParseSess, - id: ast::Ident, - relative: Option, - dir_path: &Path, -) -> ModulePath<'a> { - // 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.name, path::MAIN_SEPARATOR); - &relative_prefix_string - } else { - "" - }; - - let mod_name = id.name.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 = sess.source_map().file_exists(&default_path); - let secondary_exists = sess.source_map().file_exists(&secondary_path); - - let result = match (default_exists, secondary_exists) { - (true, false) => Ok(ModulePathSuccess { - path: default_path, - ownership: DirectoryOwnership::Owned { relative: Some(id) }, - }), - (false, true) => Ok(ModulePathSuccess { - path: secondary_path, - ownership: DirectoryOwnership::Owned { relative: None }, - }), - (false, false) => { - let mut err = struct_span_err!( - sess.span_diagnostic, - id.span, - E0583, - "file not found for module `{}`", - mod_name, - ); - err.help(&format!( - "to create the module `{}`, create file \"{}\"", - mod_name, - default_path.display(), - )); - Err(err) - } - (true, true) => { - let mut err = struct_span_err!( - sess.span_diagnostic, - id.span, - E0584, - "file for module `{}` found at both {} and {}", - mod_name, - default_path_str, - secondary_path_str, - ); - err.help("delete or rename one of them to remove the ambiguity"); - Err(err) - } - }; - - ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result } -} -- cgit 1.4.1-3-g733a5 From 31ee8e0a4396898929702db7743988b6f9916fe1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Mar 2020 22:32:25 +0100 Subject: {rustc_parse -> rustc_expand}::config --- src/librustc_expand/config.rs | 532 +++++++++++++++++++++++++++++++++++ src/librustc_expand/expand.rs | 2 +- src/librustc_expand/lib.rs | 4 +- src/librustc_parse/config.rs | 540 ------------------------------------ src/librustc_parse/lib.rs | 2 - src/librustc_parse/validate_attr.rs | 2 +- 6 files changed, 537 insertions(+), 545 deletions(-) create mode 100644 src/librustc_expand/config.rs delete mode 100644 src/librustc_parse/config.rs (limited to 'src/librustc_parse') diff --git a/src/librustc_expand/config.rs b/src/librustc_expand/config.rs new file mode 100644 index 00000000000..72c09f35dfa --- /dev/null +++ b/src/librustc_expand/config.rs @@ -0,0 +1,532 @@ +//! Conditional compilation stripping. + +use rustc_ast::ast::{self, AttrItem, Attribute, MetaItem}; +use rustc_ast::attr::HasAttrs; +use rustc_ast::mut_visit::*; +use rustc_ast::ptr::P; +use rustc_ast::util::map_in_place::MapInPlace; +use rustc_attr as attr; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{error_code, struct_span_err, Applicability, Handler}; +use rustc_feature::{Feature, Features, State as FeatureState}; +use rustc_feature::{ + ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES, +}; +use rustc_parse::{parse_in, validate_attr}; +use rustc_session::parse::{feature_err, ParseSess}; +use rustc_span::edition::{Edition, ALL_EDITIONS}; +use rustc_span::symbol::{sym, Symbol}; +use rustc_span::{Span, DUMMY_SP}; + +use smallvec::SmallVec; + +/// A folder that strips out items that do not belong in the current configuration. +pub struct StripUnconfigured<'a> { + pub sess: &'a ParseSess, + pub features: Option<&'a Features>, +} + +fn get_features( + span_handler: &Handler, + krate_attrs: &[ast::Attribute], + crate_edition: Edition, + allow_features: &Option>, +) -> Features { + fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { + let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); + err.span_label(span, "feature has been removed"); + if let Some(reason) = reason { + err.note(reason); + } + err.emit(); + } + + fn active_features_up_to(edition: Edition) -> impl Iterator { + ACTIVE_FEATURES.iter().filter(move |feature| { + if let Some(feature_edition) = feature.edition { + feature_edition <= edition + } else { + false + } + }) + } + + let mut features = Features::default(); + let mut edition_enabled_features = FxHashMap::default(); + + for &edition in ALL_EDITIONS { + if edition <= crate_edition { + // The `crate_edition` implies its respective umbrella feature-gate + // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). + edition_enabled_features.insert(edition.feature_name(), edition); + } + } + + for feature in active_features_up_to(crate_edition) { + feature.set(&mut features, DUMMY_SP); + edition_enabled_features.insert(feature.name, crate_edition); + } + + // Process the edition umbrella feature-gates first, to ensure + // `edition_enabled_features` is completed before it's queried. + for attr in krate_attrs { + if !attr.check_name(sym::feature) { + continue; + } + + let list = match attr.meta_item_list() { + Some(list) => list, + None => continue, + }; + + for mi in list { + if !mi.is_word() { + continue; + } + + let name = mi.name_or_empty(); + + let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied(); + if let Some(edition) = edition { + if edition <= crate_edition { + continue; + } + + for feature in active_features_up_to(edition) { + // FIXME(Manishearth) there is currently no way to set + // lib features by edition + feature.set(&mut features, DUMMY_SP); + edition_enabled_features.insert(feature.name, edition); + } + } + } + } + + for attr in krate_attrs { + if !attr.check_name(sym::feature) { + continue; + } + + let list = match attr.meta_item_list() { + Some(list) => list, + None => continue, + }; + + let bad_input = |span| { + struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") + }; + + for mi in list { + let name = match mi.ident() { + Some(ident) if mi.is_word() => ident.name, + Some(ident) => { + bad_input(mi.span()) + .span_suggestion( + mi.span(), + "expected just one word", + format!("{}", ident.name), + Applicability::MaybeIncorrect, + ) + .emit(); + continue; + } + None => { + bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); + continue; + } + }; + + if let Some(edition) = edition_enabled_features.get(&name) { + let msg = + &format!("the feature `{}` is included in the Rust {} edition", name, edition); + span_handler.struct_span_warn_with_code(mi.span(), msg, error_code!(E0705)).emit(); + continue; + } + + if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) { + // Handled in the separate loop above. + continue; + } + + let removed = REMOVED_FEATURES.iter().find(|f| name == f.name); + let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name); + if let Some(Feature { state, .. }) = removed.or(stable_removed) { + if let FeatureState::Removed { reason } | FeatureState::Stabilized { reason } = + state + { + feature_removed(span_handler, mi.span(), *reason); + continue; + } + } + + if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { + let since = Some(Symbol::intern(since)); + features.declared_lang_features.push((name, mi.span(), since)); + continue; + } + + if let Some(allowed) = allow_features.as_ref() { + if allowed.iter().find(|&f| name.as_str() == *f).is_none() { + struct_span_err!( + span_handler, + mi.span(), + E0725, + "the feature `{}` is not in the list of allowed features", + name + ) + .emit(); + continue; + } + } + + if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) { + f.set(&mut features, mi.span()); + features.declared_lang_features.push((name, mi.span(), None)); + continue; + } + + features.declared_lib_features.push((name, mi.span())); + } + } + + features +} + +// `cfg_attr`-process the crate's attributes and compute the crate's features. +pub fn features( + mut krate: ast::Crate, + sess: &ParseSess, + edition: Edition, + allow_features: &Option>, +) -> (ast::Crate, Features) { + let mut strip_unconfigured = StripUnconfigured { sess, features: None }; + + let unconfigured_attrs = krate.attrs.clone(); + let diag = &sess.span_diagnostic; + let err_count = diag.err_count(); + let features = match strip_unconfigured.configure(krate.attrs) { + None => { + // The entire crate is unconfigured. + krate.attrs = Vec::new(); + krate.module.items = Vec::new(); + Features::default() + } + Some(attrs) => { + krate.attrs = attrs; + let features = get_features(diag, &krate.attrs, edition, allow_features); + if err_count == diag.err_count() { + // Avoid reconfiguring malformed `cfg_attr`s. + strip_unconfigured.features = Some(&features); + strip_unconfigured.configure(unconfigured_attrs); + } + features + } + }; + (krate, features) +} + +#[macro_export] +macro_rules! configure { + ($this:ident, $node:ident) => { + match $this.configure($node) { + Some(node) => node, + None => return Default::default(), + } + }; +} + +const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; +const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ + "; + +impl<'a> StripUnconfigured<'a> { + pub fn configure(&mut self, mut node: T) -> Option { + self.process_cfg_attrs(&mut node); + self.in_cfg(node.attrs()).then_some(node) + } + + /// Parse and expand all `cfg_attr` attributes into a list of attributes + /// that are within each `cfg_attr` that has a true configuration predicate. + /// + /// Gives compiler warnings if any `cfg_attr` does not contain any + /// attributes and is in the original source code. Gives compiler errors if + /// the syntax of any `cfg_attr` is incorrect. + pub fn process_cfg_attrs(&mut self, node: &mut T) { + node.visit_attrs(|attrs| { + attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); + }); + } + + /// Parse and expand a single `cfg_attr` attribute into a list of attributes + /// when the configuration predicate is true, or otherwise expand into an + /// empty list of attributes. + /// + /// Gives a compiler warning when the `cfg_attr` contains no attributes and + /// is in the original source file. Gives a compiler error if the syntax of + /// the attribute is incorrect. + fn process_cfg_attr(&mut self, attr: Attribute) -> Vec { + if !attr.has_name(sym::cfg_attr) { + return vec![attr]; + } + + let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) { + None => return vec![], + Some(r) => r, + }; + + // Lint on zero attributes in source. + if expanded_attrs.is_empty() { + return vec![attr]; + } + + // At this point we know the attribute is considered used. + attr::mark_used(&attr); + + if !attr::cfg_matches(&cfg_predicate, self.sess, self.features) { + return vec![]; + } + + // We call `process_cfg_attr` recursively in case there's a + // `cfg_attr` inside of another `cfg_attr`. E.g. + // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. + expanded_attrs + .into_iter() + .flat_map(|(item, span)| { + let attr = attr::mk_attr_from_item(attr.style, item, span); + self.process_cfg_attr(attr) + }) + .collect() + } + + fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { + match attr.get_normal_item().args { + ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => { + let msg = "wrong `cfg_attr` delimiters"; + validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg); + match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { + Ok(r) => return Some(r), + Err(mut e) => { + e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP)) + .note(CFG_ATTR_NOTE_REF) + .emit(); + } + } + } + _ => self.error_malformed_cfg_attr_missing(attr.span), + } + None + } + + fn error_malformed_cfg_attr_missing(&self, span: Span) { + self.sess + .span_diagnostic + .struct_span_err(span, "malformed `cfg_attr` attribute input") + .span_suggestion( + span, + "missing condition and attribute", + CFG_ATTR_GRAMMAR_HELP.to_string(), + Applicability::HasPlaceholders, + ) + .note(CFG_ATTR_NOTE_REF) + .emit(); + } + + /// Determines if a node with the given attributes should be included in this configuration. + pub fn in_cfg(&self, attrs: &[Attribute]) -> bool { + attrs.iter().all(|attr| { + if !is_cfg(attr) { + return true; + } + let meta_item = match validate_attr::parse_meta(self.sess, attr) { + Ok(meta_item) => meta_item, + Err(mut err) => { + err.emit(); + return true; + } + }; + let error = |span, msg, suggestion: &str| { + let mut err = self.sess.span_diagnostic.struct_span_err(span, msg); + if !suggestion.is_empty() { + err.span_suggestion( + span, + "expected syntax is", + suggestion.into(), + Applicability::MaybeIncorrect, + ); + } + err.emit(); + true + }; + let span = meta_item.span; + match meta_item.meta_item_list() { + None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"), + Some([]) => error(span, "`cfg` predicate is not specified", ""), + Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""), + Some([single]) => match single.meta_item() { + Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features), + None => error(single.span(), "`cfg` predicate key cannot be a literal", ""), + }, + } + }) + } + + /// Visit attributes on expression and statements (but not attributes on items in blocks). + fn visit_expr_attrs(&mut self, attrs: &[Attribute]) { + // flag the offending attributes + for attr in attrs.iter() { + self.maybe_emit_expr_attr_err(attr); + } + } + + /// If attributes are not allowed on expressions, emit an error for `attr` + pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { + if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { + let mut err = feature_err( + self.sess, + sym::stmt_expr_attributes, + attr.span, + "attributes on expressions are experimental", + ); + + if attr.is_doc_comment() { + err.help("`///` is for documentation comments. For a plain comment, use `//`."); + } + + err.emit(); + } + } + + pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { + let ast::ForeignMod { abi: _, items } = foreign_mod; + items.flat_map_in_place(|item| self.configure(item)); + } + + pub fn configure_generic_params(&mut self, params: &mut Vec) { + params.flat_map_in_place(|param| self.configure(param)); + } + + fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) { + match vdata { + ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) => { + fields.flat_map_in_place(|field| self.configure(field)) + } + ast::VariantData::Unit(_) => {} + } + } + + pub fn configure_item_kind(&mut self, item: &mut ast::ItemKind) { + match item { + ast::ItemKind::Struct(def, _generics) | ast::ItemKind::Union(def, _generics) => { + self.configure_variant_data(def) + } + ast::ItemKind::Enum(ast::EnumDef { variants }, _generics) => { + variants.flat_map_in_place(|variant| self.configure(variant)); + for variant in variants { + self.configure_variant_data(&mut variant.data); + } + } + _ => {} + } + } + + pub fn configure_expr_kind(&mut self, expr_kind: &mut ast::ExprKind) { + match expr_kind { + ast::ExprKind::Match(_m, arms) => { + arms.flat_map_in_place(|arm| self.configure(arm)); + } + ast::ExprKind::Struct(_path, fields, _base) => { + fields.flat_map_in_place(|field| self.configure(field)); + } + _ => {} + } + } + + pub fn configure_expr(&mut self, expr: &mut P) { + self.visit_expr_attrs(expr.attrs()); + + // If an expr is valid to cfg away it will have been removed by the + // outer stmt or expression folder before descending in here. + // Anything else is always required, and thus has to error out + // in case of a cfg attr. + // + // N.B., this is intentionally not part of the visit_expr() function + // in order for filter_map_expr() to be able to avoid this check + if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { + let msg = "removing an expression is not supported in this position"; + self.sess.span_diagnostic.span_err(attr.span, msg); + } + + self.process_cfg_attrs(expr) + } + + pub fn configure_pat(&mut self, pat: &mut P) { + if let ast::PatKind::Struct(_path, fields, _etc) = &mut pat.kind { + fields.flat_map_in_place(|field| self.configure(field)); + } + } + + pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) { + fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg)); + } +} + +impl<'a> MutVisitor for StripUnconfigured<'a> { + fn visit_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { + self.configure_foreign_mod(foreign_mod); + noop_visit_foreign_mod(foreign_mod, self); + } + + fn visit_item_kind(&mut self, item: &mut ast::ItemKind) { + self.configure_item_kind(item); + noop_visit_item_kind(item, self); + } + + fn visit_expr(&mut self, expr: &mut P) { + self.configure_expr(expr); + self.configure_expr_kind(&mut expr.kind); + noop_visit_expr(expr, self); + } + + fn filter_map_expr(&mut self, expr: P) -> Option> { + let mut expr = configure!(self, expr); + self.configure_expr_kind(&mut expr.kind); + noop_visit_expr(&mut expr, self); + Some(expr) + } + + fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { + noop_flat_map_stmt(configure!(self, stmt), self) + } + + fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { + noop_flat_map_item(configure!(self, item), self) + } + + fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { + noop_flat_map_assoc_item(configure!(self, item), self) + } + + fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { + noop_flat_map_assoc_item(configure!(self, item), self) + } + + fn visit_mac(&mut self, _mac: &mut ast::MacCall) { + // Don't configure interpolated AST (cf. issue #34171). + // Interpolated AST will get configured once the surrounding tokens are parsed. + } + + fn visit_pat(&mut self, pat: &mut P) { + self.configure_pat(pat); + noop_visit_pat(pat, self) + } + + fn visit_fn_decl(&mut self, mut fn_decl: &mut P) { + self.configure_fn_decl(&mut fn_decl); + noop_visit_fn_decl(fn_decl, self); + } +} + +fn is_cfg(attr: &Attribute) -> bool { + attr.check_name(sym::cfg) +} diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 8e83e13fa8a..db6a64b3b35 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -1,5 +1,6 @@ use crate::base::*; use crate::config::StripUnconfigured; +use crate::configure; use crate::hygiene::{ExpnData, ExpnId, ExpnKind, SyntaxContext}; use crate::mbe::macro_rules::annotate_err_with_kind; use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership}; @@ -18,7 +19,6 @@ use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; -use rustc_parse::configure; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; diff --git a/src/librustc_expand/lib.rs b/src/librustc_expand/lib.rs index 98d644eb77a..0320a275e5d 100644 --- a/src/librustc_expand/lib.rs +++ b/src/librustc_expand/lib.rs @@ -1,3 +1,4 @@ +#![feature(bool_to_option)] #![feature(cow_is_borrowed)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] @@ -34,9 +35,10 @@ pub use mbe::macro_rules::compile_declarative_macro; crate use rustc_span::hygiene; pub mod base; pub mod build; +#[macro_use] +pub mod config; pub mod expand; pub mod module; -pub use rustc_parse::config; pub mod proc_macro; crate mod mbe; diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs deleted file mode 100644 index c611f249420..00000000000 --- a/src/librustc_parse/config.rs +++ /dev/null @@ -1,540 +0,0 @@ -//! Process the potential `cfg` attributes on a module. -//! Also determine if the module should be included in this configuration. -//! -//! This module properly belongs in rustc_expand, but for now it's tied into -//! parsing, so we leave it here to avoid complicated out-of-line dependencies. -//! -//! A principled solution to this wrong location would be to implement [#64197]. -//! -//! [#64197]: https://github.com/rust-lang/rust/issues/64197 - -use crate::{parse_in, validate_attr}; -use rustc_ast::ast::{self, AttrItem, Attribute, MetaItem}; -use rustc_ast::attr::HasAttrs; -use rustc_ast::mut_visit::*; -use rustc_ast::ptr::P; -use rustc_ast::util::map_in_place::MapInPlace; -use rustc_attr as attr; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{error_code, struct_span_err, Applicability, Handler}; -use rustc_feature::{Feature, Features, State as FeatureState}; -use rustc_feature::{ - ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES, -}; -use rustc_session::parse::{feature_err, ParseSess}; -use rustc_span::edition::{Edition, ALL_EDITIONS}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{Span, DUMMY_SP}; - -use smallvec::SmallVec; - -/// A folder that strips out items that do not belong in the current configuration. -pub struct StripUnconfigured<'a> { - pub sess: &'a ParseSess, - pub features: Option<&'a Features>, -} - -fn get_features( - span_handler: &Handler, - krate_attrs: &[ast::Attribute], - crate_edition: Edition, - allow_features: &Option>, -) -> Features { - fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { - let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); - err.span_label(span, "feature has been removed"); - if let Some(reason) = reason { - err.note(reason); - } - err.emit(); - } - - fn active_features_up_to(edition: Edition) -> impl Iterator { - ACTIVE_FEATURES.iter().filter(move |feature| { - if let Some(feature_edition) = feature.edition { - feature_edition <= edition - } else { - false - } - }) - } - - let mut features = Features::default(); - let mut edition_enabled_features = FxHashMap::default(); - - for &edition in ALL_EDITIONS { - if edition <= crate_edition { - // The `crate_edition` implies its respective umbrella feature-gate - // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). - edition_enabled_features.insert(edition.feature_name(), edition); - } - } - - for feature in active_features_up_to(crate_edition) { - feature.set(&mut features, DUMMY_SP); - edition_enabled_features.insert(feature.name, crate_edition); - } - - // Process the edition umbrella feature-gates first, to ensure - // `edition_enabled_features` is completed before it's queried. - for attr in krate_attrs { - if !attr.check_name(sym::feature) { - continue; - } - - let list = match attr.meta_item_list() { - Some(list) => list, - None => continue, - }; - - for mi in list { - if !mi.is_word() { - continue; - } - - let name = mi.name_or_empty(); - - let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied(); - if let Some(edition) = edition { - if edition <= crate_edition { - continue; - } - - for feature in active_features_up_to(edition) { - // FIXME(Manishearth) there is currently no way to set - // lib features by edition - feature.set(&mut features, DUMMY_SP); - edition_enabled_features.insert(feature.name, edition); - } - } - } - } - - for attr in krate_attrs { - if !attr.check_name(sym::feature) { - continue; - } - - let list = match attr.meta_item_list() { - Some(list) => list, - None => continue, - }; - - let bad_input = |span| { - struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") - }; - - for mi in list { - let name = match mi.ident() { - Some(ident) if mi.is_word() => ident.name, - Some(ident) => { - bad_input(mi.span()) - .span_suggestion( - mi.span(), - "expected just one word", - format!("{}", ident.name), - Applicability::MaybeIncorrect, - ) - .emit(); - continue; - } - None => { - bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); - continue; - } - }; - - if let Some(edition) = edition_enabled_features.get(&name) { - let msg = - &format!("the feature `{}` is included in the Rust {} edition", name, edition); - span_handler.struct_span_warn_with_code(mi.span(), msg, error_code!(E0705)).emit(); - continue; - } - - if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) { - // Handled in the separate loop above. - continue; - } - - let removed = REMOVED_FEATURES.iter().find(|f| name == f.name); - let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name); - if let Some(Feature { state, .. }) = removed.or(stable_removed) { - if let FeatureState::Removed { reason } | FeatureState::Stabilized { reason } = - state - { - feature_removed(span_handler, mi.span(), *reason); - continue; - } - } - - if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { - let since = Some(Symbol::intern(since)); - features.declared_lang_features.push((name, mi.span(), since)); - continue; - } - - if let Some(allowed) = allow_features.as_ref() { - if allowed.iter().find(|&f| name.as_str() == *f).is_none() { - struct_span_err!( - span_handler, - mi.span(), - E0725, - "the feature `{}` is not in the list of allowed features", - name - ) - .emit(); - continue; - } - } - - if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) { - f.set(&mut features, mi.span()); - features.declared_lang_features.push((name, mi.span(), None)); - continue; - } - - features.declared_lib_features.push((name, mi.span())); - } - } - - features -} - -// `cfg_attr`-process the crate's attributes and compute the crate's features. -pub fn features( - mut krate: ast::Crate, - sess: &ParseSess, - edition: Edition, - allow_features: &Option>, -) -> (ast::Crate, Features) { - let mut strip_unconfigured = StripUnconfigured { sess, features: None }; - - let unconfigured_attrs = krate.attrs.clone(); - let diag = &sess.span_diagnostic; - let err_count = diag.err_count(); - let features = match strip_unconfigured.configure(krate.attrs) { - None => { - // The entire crate is unconfigured. - krate.attrs = Vec::new(); - krate.module.items = Vec::new(); - Features::default() - } - Some(attrs) => { - krate.attrs = attrs; - let features = get_features(diag, &krate.attrs, edition, allow_features); - if err_count == diag.err_count() { - // Avoid reconfiguring malformed `cfg_attr`s. - strip_unconfigured.features = Some(&features); - strip_unconfigured.configure(unconfigured_attrs); - } - features - } - }; - (krate, features) -} - -#[macro_export] -macro_rules! configure { - ($this:ident, $node:ident) => { - match $this.configure($node) { - Some(node) => node, - None => return Default::default(), - } - }; -} - -const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; -const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ - "; - -impl<'a> StripUnconfigured<'a> { - pub fn configure(&mut self, mut node: T) -> Option { - self.process_cfg_attrs(&mut node); - self.in_cfg(node.attrs()).then_some(node) - } - - /// Parse and expand all `cfg_attr` attributes into a list of attributes - /// that are within each `cfg_attr` that has a true configuration predicate. - /// - /// Gives compiler warnings if any `cfg_attr` does not contain any - /// attributes and is in the original source code. Gives compiler errors if - /// the syntax of any `cfg_attr` is incorrect. - pub fn process_cfg_attrs(&mut self, node: &mut T) { - node.visit_attrs(|attrs| { - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); - }); - } - - /// Parse and expand a single `cfg_attr` attribute into a list of attributes - /// when the configuration predicate is true, or otherwise expand into an - /// empty list of attributes. - /// - /// Gives a compiler warning when the `cfg_attr` contains no attributes and - /// is in the original source file. Gives a compiler error if the syntax of - /// the attribute is incorrect. - fn process_cfg_attr(&mut self, attr: Attribute) -> Vec { - if !attr.has_name(sym::cfg_attr) { - return vec![attr]; - } - - let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) { - None => return vec![], - Some(r) => r, - }; - - // Lint on zero attributes in source. - if expanded_attrs.is_empty() { - return vec![attr]; - } - - // At this point we know the attribute is considered used. - attr::mark_used(&attr); - - if !attr::cfg_matches(&cfg_predicate, self.sess, self.features) { - return vec![]; - } - - // We call `process_cfg_attr` recursively in case there's a - // `cfg_attr` inside of another `cfg_attr`. E.g. - // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. - expanded_attrs - .into_iter() - .flat_map(|(item, span)| { - let attr = attr::mk_attr_from_item(attr.style, item, span); - self.process_cfg_attr(attr) - }) - .collect() - } - - fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { - match attr.get_normal_item().args { - ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => { - let msg = "wrong `cfg_attr` delimiters"; - validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg); - match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { - Ok(r) => return Some(r), - Err(mut e) => { - e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP)) - .note(CFG_ATTR_NOTE_REF) - .emit(); - } - } - } - _ => self.error_malformed_cfg_attr_missing(attr.span), - } - None - } - - fn error_malformed_cfg_attr_missing(&self, span: Span) { - self.sess - .span_diagnostic - .struct_span_err(span, "malformed `cfg_attr` attribute input") - .span_suggestion( - span, - "missing condition and attribute", - CFG_ATTR_GRAMMAR_HELP.to_string(), - Applicability::HasPlaceholders, - ) - .note(CFG_ATTR_NOTE_REF) - .emit(); - } - - /// Determines if a node with the given attributes should be included in this configuration. - pub fn in_cfg(&self, attrs: &[Attribute]) -> bool { - attrs.iter().all(|attr| { - if !is_cfg(attr) { - return true; - } - let meta_item = match validate_attr::parse_meta(self.sess, attr) { - Ok(meta_item) => meta_item, - Err(mut err) => { - err.emit(); - return true; - } - }; - let error = |span, msg, suggestion: &str| { - let mut err = self.sess.span_diagnostic.struct_span_err(span, msg); - if !suggestion.is_empty() { - err.span_suggestion( - span, - "expected syntax is", - suggestion.into(), - Applicability::MaybeIncorrect, - ); - } - err.emit(); - true - }; - let span = meta_item.span; - match meta_item.meta_item_list() { - None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"), - Some([]) => error(span, "`cfg` predicate is not specified", ""), - Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""), - Some([single]) => match single.meta_item() { - Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features), - None => error(single.span(), "`cfg` predicate key cannot be a literal", ""), - }, - } - }) - } - - /// Visit attributes on expression and statements (but not attributes on items in blocks). - fn visit_expr_attrs(&mut self, attrs: &[Attribute]) { - // flag the offending attributes - for attr in attrs.iter() { - self.maybe_emit_expr_attr_err(attr); - } - } - - /// If attributes are not allowed on expressions, emit an error for `attr` - pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { - if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { - let mut err = feature_err( - self.sess, - sym::stmt_expr_attributes, - attr.span, - "attributes on expressions are experimental", - ); - - if attr.is_doc_comment() { - err.help("`///` is for documentation comments. For a plain comment, use `//`."); - } - - err.emit(); - } - } - - pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { - let ast::ForeignMod { abi: _, items } = foreign_mod; - items.flat_map_in_place(|item| self.configure(item)); - } - - pub fn configure_generic_params(&mut self, params: &mut Vec) { - params.flat_map_in_place(|param| self.configure(param)); - } - - fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) { - match vdata { - ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) => { - fields.flat_map_in_place(|field| self.configure(field)) - } - ast::VariantData::Unit(_) => {} - } - } - - pub fn configure_item_kind(&mut self, item: &mut ast::ItemKind) { - match item { - ast::ItemKind::Struct(def, _generics) | ast::ItemKind::Union(def, _generics) => { - self.configure_variant_data(def) - } - ast::ItemKind::Enum(ast::EnumDef { variants }, _generics) => { - variants.flat_map_in_place(|variant| self.configure(variant)); - for variant in variants { - self.configure_variant_data(&mut variant.data); - } - } - _ => {} - } - } - - pub fn configure_expr_kind(&mut self, expr_kind: &mut ast::ExprKind) { - match expr_kind { - ast::ExprKind::Match(_m, arms) => { - arms.flat_map_in_place(|arm| self.configure(arm)); - } - ast::ExprKind::Struct(_path, fields, _base) => { - fields.flat_map_in_place(|field| self.configure(field)); - } - _ => {} - } - } - - pub fn configure_expr(&mut self, expr: &mut P) { - self.visit_expr_attrs(expr.attrs()); - - // If an expr is valid to cfg away it will have been removed by the - // outer stmt or expression folder before descending in here. - // Anything else is always required, and thus has to error out - // in case of a cfg attr. - // - // N.B., this is intentionally not part of the visit_expr() function - // in order for filter_map_expr() to be able to avoid this check - if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { - let msg = "removing an expression is not supported in this position"; - self.sess.span_diagnostic.span_err(attr.span, msg); - } - - self.process_cfg_attrs(expr) - } - - pub fn configure_pat(&mut self, pat: &mut P) { - if let ast::PatKind::Struct(_path, fields, _etc) = &mut pat.kind { - fields.flat_map_in_place(|field| self.configure(field)); - } - } - - pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) { - fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg)); - } -} - -impl<'a> MutVisitor for StripUnconfigured<'a> { - fn visit_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { - self.configure_foreign_mod(foreign_mod); - noop_visit_foreign_mod(foreign_mod, self); - } - - fn visit_item_kind(&mut self, item: &mut ast::ItemKind) { - self.configure_item_kind(item); - noop_visit_item_kind(item, self); - } - - fn visit_expr(&mut self, expr: &mut P) { - self.configure_expr(expr); - self.configure_expr_kind(&mut expr.kind); - noop_visit_expr(expr, self); - } - - fn filter_map_expr(&mut self, expr: P) -> Option> { - let mut expr = configure!(self, expr); - self.configure_expr_kind(&mut expr.kind); - noop_visit_expr(&mut expr, self); - Some(expr) - } - - fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { - noop_flat_map_stmt(configure!(self, stmt), self) - } - - fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { - noop_flat_map_item(configure!(self, item), self) - } - - fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { - noop_flat_map_assoc_item(configure!(self, item), self) - } - - fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { - noop_flat_map_assoc_item(configure!(self, item), self) - } - - fn visit_mac(&mut self, _mac: &mut ast::MacCall) { - // Don't configure interpolated AST (cf. issue #34171). - // Interpolated AST will get configured once the surrounding tokens are parsed. - } - - fn visit_pat(&mut self, pat: &mut P) { - self.configure_pat(pat); - noop_visit_pat(pat, self) - } - - fn visit_fn_decl(&mut self, mut fn_decl: &mut P) { - self.configure_fn_decl(&mut fn_decl); - noop_visit_fn_decl(fn_decl, self); - } -} - -fn is_cfg(attr: &Attribute) -> bool { - attr.check_name(sym::cfg) -} diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 70aa8c0074a..a23f74a8894 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -26,8 +26,6 @@ pub mod parser; use parser::{emit_unclosed_delims, make_unclosed_delims_error, Parser}; pub mod lexer; pub mod validate_attr; -#[macro_use] -pub mod config; // A bunch of utility functions of the form `parse__from_` // where includes crate, expr, item, stmt, tts, and one that diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs index 029aa5ed2ba..2512878ec65 100644 --- a/src/librustc_parse/validate_attr.rs +++ b/src/librustc_parse/validate_attr.rs @@ -57,7 +57,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta }) } -crate fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) { +pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) { if let ast::MacDelimiter::Parenthesis = delim { return; } -- cgit 1.4.1-3-g733a5 From 7d0e5bbb67f5c1d30b8c23bbfdaa6ed3cc281786 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 9 Mar 2020 10:35:35 +0100 Subject: parser/expand: minor cleanup --- src/librustc_expand/mbe/macro_rules.rs | 4 ++-- src/librustc_parse/lib.rs | 15 --------------- 2 files changed, 2 insertions(+), 17 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 1628d8bfdbc..3de2169f114 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -258,7 +258,7 @@ fn generic_extension<'cx>( trace_macros_note(&mut cx.expansions, sp, msg); } - let mut p = Parser::new(cx.parse_sess(), tts, false, None); + let mut p = Parser::new(sess, tts, false, None); p.root_module_name = cx.current_expansion.module.mod_path.last().map(|id| id.to_string()); p.last_type_ascription = cx.current_expansion.prior_type_ascription; @@ -1204,7 +1204,7 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { } } -fn parser_from_cx<'cx>(sess: &'cx ParseSess, tts: TokenStream) -> Parser<'cx> { +fn parser_from_cx(sess: &ParseSess, tts: TokenStream) -> Parser<'_> { Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS) } diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index a23f74a8894..c31cc1b4c9f 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -238,21 +238,6 @@ pub fn stream_to_parser<'a>( Parser::new(sess, stream, false, subparser_name) } -/// Given a stream, the `ParseSess` and the base directory, produces a parser. -/// -/// Use this function when you are creating a parser from the token stream -/// and also care about the current working directory of the parser (e.g., -/// you are trying to resolve modules defined inside a macro invocation). -/// -/// # Note -/// -/// The main usage of this function is outside of rustc, for those who uses -/// librustc_ast as a library. Please do not remove this function while refactoring -/// just because it is not used in rustc codebase! -pub fn stream_to_parser_with_base_dir(sess: &ParseSess, stream: TokenStream) -> Parser<'_> { - Parser::new(sess, stream, false, None) -} - /// Runs the given subparser `f` on the tokens of the given `attr`'s item. pub fn parse_in<'a, T>( sess: &'a ParseSess, -- cgit 1.4.1-3-g733a5 From fe713420911b6f0d7816ba5254f364557cfc8284 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 9 Mar 2020 11:16:00 +0100 Subject: tweak outline module parsing spans --- src/librustc_expand/expand.rs | 9 +++-- src/librustc_expand/module.rs | 40 ++++++++++++---------- src/librustc_parse/parser/item.rs | 2 +- .../ui/directory_ownership/macro-expanded-mod.rs | 4 +-- .../directory_ownership/macro-expanded-mod.stderr | 9 +++-- .../non-inline-mod-restriction.stderr | 4 +-- src/test/ui/error-codes/E0583.stderr | 4 +-- .../invalid-module-declaration.stderr | 4 +-- .../missing_non_modrs_mod.stderr | 4 +-- .../missing_non_modrs_mod_inline.stderr | 4 +-- src/test/ui/mod/mod_file_disambig.stderr | 4 +-- src/test/ui/parser/circular_modules_main.stderr | 4 +-- src/test/ui/parser/issue-5806.stderr | 4 +-- src/test/ui/parser/mod_file_not_exist.stderr | 4 +-- src/test/ui/parser/mod_file_with_path_attr.stderr | 4 +-- 15 files changed, 55 insertions(+), 49 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index db6a64b3b35..834febceb1e 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -1429,6 +1429,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck. let ident = item.ident; + let span = item.span; match item.kind { ast::ItemKind::MacCall(..) => { @@ -1436,10 +1437,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.check_attributes(&item.attrs); item.and_then(|item| match item.kind { ItemKind::MacCall(mac) => self - .collect( - AstFragmentKind::Items, - InvocationKind::Bang { mac, span: item.span }, - ) + .collect(AstFragmentKind::Items, InvocationKind::Bang { mac, span }) .make_items(), _ => unreachable!(), }) @@ -1457,7 +1455,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { push_directory(ident, &item.attrs, dir) } else { // We have an outline `mod foo;` so we need to parse the file. - let (new_mod, dir) = parse_external_mod(sess, ident, dir, &mut attrs, pushed); + let (new_mod, dir) = + parse_external_mod(sess, ident, span, dir, &mut attrs, pushed); *old_mod = new_mod; item.attrs = attrs; // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure. diff --git a/src/librustc_expand/module.rs b/src/librustc_expand/module.rs index 1d4c767b84f..2d5e4d4e889 100644 --- a/src/librustc_expand/module.rs +++ b/src/librustc_expand/module.rs @@ -41,6 +41,7 @@ pub struct ModulePathSuccess { crate fn parse_external_mod( sess: &ParseSess, id: ast::Ident, + span: Span, // The span to blame on errors. Directory { mut ownership, path }: Directory, attrs: &mut Vec, pop_mod_stack: &mut bool, @@ -48,18 +49,18 @@ crate fn parse_external_mod( // We bail on the first error, but that error does not cause a fatal error... (1) let result: PResult<'_, _> = try { // Extract the file path and the new ownership. - let mp = submod_path(sess, id, &attrs, ownership, &path)?; + let mp = submod_path(sess, id, span, &attrs, ownership, &path)?; ownership = mp.ownership; // Ensure file paths are acyclic. let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); - error_on_circular_module(sess, id.span, &mp.path, &included_mod_stack)?; + error_on_circular_module(sess, span, &mp.path, &included_mod_stack)?; included_mod_stack.push(mp.path.clone()); *pop_mod_stack = true; // We have pushed, so notify caller. drop(included_mod_stack); // Actually parse the external file as amodule. - let mut p0 = new_sub_parser_from_file(sess, &mp.path, Some(id.to_string()), id.span); + let mut p0 = new_sub_parser_from_file(sess, &mp.path, Some(id.to_string()), span); let mut module = p0.parse_mod(&token::Eof)?; module.0.inline = false; module @@ -126,6 +127,7 @@ crate fn push_directory( fn submod_path<'a>( sess: &'a ParseSess, id: ast::Ident, + span: Span, attrs: &[Attribute], ownership: DirectoryOwnership, dir_path: &Path, @@ -150,54 +152,53 @@ fn submod_path<'a>( DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None, }; let ModulePath { path_exists, name, result } = - default_submod_path(sess, id, relative, dir_path); + default_submod_path(sess, id, span, relative, dir_path); match ownership { DirectoryOwnership::Owned { .. } => Ok(result?), DirectoryOwnership::UnownedViaBlock => { let _ = result.map_err(|mut err| err.cancel()); - error_decl_mod_in_block(sess, id.span, path_exists, &name) + error_decl_mod_in_block(sess, span, path_exists, &name) } DirectoryOwnership::UnownedViaMod => { let _ = result.map_err(|mut err| err.cancel()); - error_cannot_declare_mod_here(sess, id.span, path_exists, &name) + error_cannot_declare_mod_here(sess, span, path_exists, &name) } } } fn error_decl_mod_in_block<'a, T>( sess: &'a ParseSess, - id_sp: Span, + span: Span, path_exists: bool, name: &str, ) -> PResult<'a, T> { let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute"; - let mut err = sess.span_diagnostic.struct_span_err(id_sp, msg); + let mut err = sess.span_diagnostic.struct_span_err(span, msg); if path_exists { let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name); - err.span_note(id_sp, &msg); + err.span_note(span, &msg); } Err(err) } fn error_cannot_declare_mod_here<'a, T>( sess: &'a ParseSess, - id_sp: Span, + span: Span, path_exists: bool, name: &str, ) -> PResult<'a, T> { let mut err = - sess.span_diagnostic.struct_span_err(id_sp, "cannot declare a new module at this location"); - if !id_sp.is_dummy() { - if let FileName::Real(src_path) = sess.source_map().span_to_filename(id_sp) { + sess.span_diagnostic.struct_span_err(span, "cannot declare a new module at this location"); + if !span.is_dummy() { + if let FileName::Real(src_path) = sess.source_map().span_to_filename(span) { 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, + span, &format!( - "maybe move this module `{}` to its own \ - directory via `{}`", + "maybe move this module `{}` to its own directory via `{}`", src_path.display(), dest_path.display() ), @@ -207,7 +208,7 @@ fn error_cannot_declare_mod_here<'a, T>( } if path_exists { err.span_note( - id_sp, + span, &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name), ); } @@ -237,6 +238,7 @@ pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option( sess: &'a ParseSess, id: ast::Ident, + span: Span, relative: Option, dir_path: &Path, ) -> ModulePath<'a> { @@ -273,7 +275,7 @@ pub fn default_submod_path<'a>( (false, false) => { let mut err = struct_span_err!( sess.span_diagnostic, - id.span, + span, E0583, "file not found for module `{}`", mod_name, @@ -288,7 +290,7 @@ pub fn default_submod_path<'a>( (true, true) => { let mut err = struct_span_err!( sess.span_diagnostic, - id.span, + span, E0584, "file for module `{}` found at both {} and {}", mod_name, diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index d0da8e6c7c1..873b7e93c6f 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -38,7 +38,7 @@ impl<'a> Parser<'a> { } /// Parses a `mod { ... }` or `mod ;` item. - pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { let id = self.parse_ident()?; let (module, mut inner_attrs) = if self.eat(&token::Semi) { Default::default() diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.rs b/src/test/ui/directory_ownership/macro-expanded-mod.rs index 1066a2ba712..9cb159603a8 100644 --- a/src/test/ui/directory_ownership/macro-expanded-mod.rs +++ b/src/test/ui/directory_ownership/macro-expanded-mod.rs @@ -2,7 +2,7 @@ macro_rules! mod_decl { ($i:ident) => { - mod $i; + mod $i; //~ ERROR Cannot declare a non-inline module inside a block }; } @@ -11,5 +11,5 @@ mod macro_expanded_mod_helper { } fn main() { - mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block + mod_decl!(foo); } diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.stderr b/src/test/ui/directory_ownership/macro-expanded-mod.stderr index d9d8a8ffed7..f90419247c9 100644 --- a/src/test/ui/directory_ownership/macro-expanded-mod.stderr +++ b/src/test/ui/directory_ownership/macro-expanded-mod.stderr @@ -1,8 +1,13 @@ error: Cannot declare a non-inline module inside a block unless it has a path attribute - --> $DIR/macro-expanded-mod.rs:14:15 + --> $DIR/macro-expanded-mod.rs:5:9 | +LL | mod $i; + | ^^^^^^^ +... LL | mod_decl!(foo); - | ^^^ + | --------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr b/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr index 46acc7e66d8..d034942ca5d 100644 --- a/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr +++ b/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr @@ -1,8 +1,8 @@ error: Cannot declare a non-inline module inside a block unless it has a path attribute - --> $DIR/non-inline-mod-restriction.rs:4:9 + --> $DIR/non-inline-mod-restriction.rs:4:5 | LL | mod foo; - | ^^^ + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0583.stderr b/src/test/ui/error-codes/E0583.stderr index 5d47b633e78..dbe70035595 100644 --- a/src/test/ui/error-codes/E0583.stderr +++ b/src/test/ui/error-codes/E0583.stderr @@ -1,8 +1,8 @@ error[E0583]: file not found for module `module_that_doesnt_exist` - --> $DIR/E0583.rs:1:5 + --> $DIR/E0583.rs:1:1 | LL | mod module_that_doesnt_exist; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs" diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr index 5d2cdaef1a7..52296042eb4 100644 --- a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr +++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr @@ -1,8 +1,8 @@ error[E0583]: file not found for module `baz` - --> $DIR/auxiliary/foo/bar.rs:1:9 + --> $DIR/auxiliary/foo/bar.rs:1:1 | LL | pub mod baz; - | ^^^ + | ^^^^^^^^^^^^ | = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr index e8d997e6de0..91b3fe15c4b 100644 --- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr @@ -1,8 +1,8 @@ error[E0583]: file not found for module `missing` - --> $DIR/foo.rs:4:5 + --> $DIR/foo.rs:4:1 | LL | mod missing; - | ^^^^^^^ + | ^^^^^^^^^^^^ | = help: to create the module `missing`, create file "$DIR/foo/missing.rs" diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr index b2b0f8b466a..f519de46c76 100644 --- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr @@ -1,8 +1,8 @@ error[E0583]: file not found for module `missing` - --> $DIR/foo_inline.rs:4:9 + --> $DIR/foo_inline.rs:4:5 | LL | mod missing; - | ^^^^^^^ + | ^^^^^^^^^^^^ | = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs" diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 230bfa79916..490633a3fb0 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -1,8 +1,8 @@ error[E0584]: file for module `mod_file_disambig_aux` found at both mod_file_disambig_aux.rs and mod_file_disambig_aux/mod.rs - --> $DIR/mod_file_disambig.rs:1:5 + --> $DIR/mod_file_disambig.rs:1:1 | LL | mod mod_file_disambig_aux; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: delete or rename one of them to remove the ambiguity diff --git a/src/test/ui/parser/circular_modules_main.stderr b/src/test/ui/parser/circular_modules_main.stderr index ca84f2d2854..90f81c64835 100644 --- a/src/test/ui/parser/circular_modules_main.stderr +++ b/src/test/ui/parser/circular_modules_main.stderr @@ -1,8 +1,8 @@ error: circular modules: $DIR/circular_modules_hello.rs -> $DIR/circular_modules_main.rs -> $DIR/circular_modules_hello.rs - --> $DIR/circular_modules_main.rs:2:5 + --> $DIR/circular_modules_main.rs:2:1 | LL | mod circular_modules_hello; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `say_hello` in module `circular_modules_hello` --> $DIR/circular_modules_main.rs:9:29 diff --git a/src/test/ui/parser/issue-5806.stderr b/src/test/ui/parser/issue-5806.stderr index 6cf902ca86e..bdb5c91ff91 100644 --- a/src/test/ui/parser/issue-5806.stderr +++ b/src/test/ui/parser/issue-5806.stderr @@ -1,8 +1,8 @@ error: couldn't read $DIR/../parser: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) - --> $DIR/issue-5806.rs:5:5 + --> $DIR/issue-5806.rs:5:1 | LL | mod foo; - | ^^^ + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index c298c51c4f8..087ae9fe3e0 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -1,8 +1,8 @@ error[E0583]: file not found for module `not_a_real_file` - --> $DIR/mod_file_not_exist.rs:3:5 + --> $DIR/mod_file_not_exist.rs:3:1 | LL | mod not_a_real_file; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" diff --git a/src/test/ui/parser/mod_file_with_path_attr.stderr b/src/test/ui/parser/mod_file_with_path_attr.stderr index 004b5d7963a..cd1add73d58 100644 --- a/src/test/ui/parser/mod_file_with_path_attr.stderr +++ b/src/test/ui/parser/mod_file_with_path_attr.stderr @@ -1,8 +1,8 @@ error: couldn't read $DIR/not_a_real_file.rs: $FILE_NOT_FOUND_MSG (os error 2) - --> $DIR/mod_file_with_path_attr.rs:4:5 + --> $DIR/mod_file_with_path_attr.rs:4:1 | LL | mod m; - | ^ + | ^^^^^^ error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From e301291cb6523b415e0a64ea61cb4728b9ca2c0a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 16 Mar 2020 00:56:27 +0100 Subject: fix rebase fallout --- src/librustc_parse/parser/item.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'src/librustc_parse') diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 873b7e93c6f..9d70f606f3e 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -6,14 +6,11 @@ use crate::maybe_whole; use rustc_ast::ast::{self, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind, Mod}; -use rustc_ast::ast::{ - Async, Const, Defaultness, IsAuto, PathSegment, Unsafe, UseTree, UseTreeKind, -}; -use rustc_ast::ast::{ - BindingMode, Block, FnDecl, FnSig, MacArgs, MacCall, MacDelimiter, Param, SelfKind, -}; +use rustc_ast::ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; +use rustc_ast::ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind}; use rustc_ast::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; -use rustc_ast::ast::{FnHeader, ForeignItem, Mutability, SelfKind, Visibility, VisibilityKind}; +use rustc_ast::ast::{FnHeader, ForeignItem, PathSegment, Visibility, VisibilityKind}; +use rustc_ast::ast::{MacArgs, MacCall, MacDelimiter}; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; -- cgit 1.4.1-3-g733a5