Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 6 pull requests #69884

Closed
wants to merge 59 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
cbf5f7d
Use TypeRelating for instantiating query responses
matthewjasper Feb 29, 2020
f2cbe30
submod_path_from_attr: simplify & document
Centril Mar 7, 2020
9b3364f
extract error_cannot_declare_mod_here
Centril Mar 7, 2020
6cb04d9
extract error_decl_mod_in_block
Centril Mar 7, 2020
024af0b
simplify submod_path
Centril Mar 7, 2020
9855b34
submod_path: use id.span
Centril Mar 7, 2020
3eb86cf
extract parse_mod
Centril Mar 7, 2020
cbcb550
extract error_on_circular_module
Centril Mar 7, 2020
996449b
detach submod_path from Parser
Centril Mar 8, 2020
81b3500
decouple push_directory from Parser
Centril Mar 8, 2020
f284eb3
decouple eval_src_mod from Parser
Centril Mar 8, 2020
aff35c4
expand: use push_directory
Centril Mar 8, 2020
75ad1b8
de-fatalize outline module parsing
Centril Mar 8, 2020
e0d001e
extract parse_external_module
Centril Mar 8, 2020
df3792c
extract error_on_circular_module
Centril Mar 8, 2020
a9fd977
outline modules: parse -> expand.
Centril Mar 8, 2020
e994922
parse: module parsing -> item.rs
Centril Mar 8, 2020
65d072d
move Directory -> parser::module
Centril Mar 8, 2020
1b527ae
{rustc_parse::parser -> rustc_expand}::module
Centril Mar 8, 2020
adc3451
{rustc_parse -> rustc_expand}::config
Centril Mar 8, 2020
d171e59
add test for stripped nested outline module
Centril Mar 8, 2020
ad0b078
parser/expand: minor cleanup
Centril Mar 9, 2020
3ba89e8
Remove quotes around unknown fn placeholder in backtrace
dtolnay Feb 13, 2020
db75b6a
Add quotes around filename in Backtrace debug
dtolnay Feb 13, 2020
1f1ca87
Change disabled and unsupported backtraces to print using placeholder…
dtolnay Feb 13, 2020
a9cc010
Make it possible to instantiate hardcoded Backtrace from test
dtolnay Feb 13, 2020
33600e4
Add test of Debug representation of Backtrace
dtolnay Feb 13, 2020
a2364dc
Write backtrace fmt test using relative paths
dtolnay Mar 9, 2020
8fba7fb
Use smaller discriminants for generators
jonas-schievink Mar 9, 2020
b16d659
Add a test for generator discriminants
jonas-schievink Mar 9, 2020
906bb8d
fix #62456
contrun Mar 9, 2020
0a0c850
fix test failure due to earlier emitted error
contrun Mar 10, 2020
7df5868
tweak outline module parsing spans
Centril Mar 9, 2020
42ab820
use pretty-compare-only in a test
Centril Mar 10, 2020
9596dc2
parse_labeled_expr: simplify
Centril Mar 5, 2020
c303c44
use error_block_no_opening_brace more
Centril Mar 5, 2020
883e90d
simplify parse_inner_attributes
Centril Mar 5, 2020
8ee220c
more reuse in block parsing & improve diagnostics.
Centril Mar 5, 2020
055733f
parse: recover on `&'lt $expr` / `'lt $expr`.
Centril Mar 5, 2020
379f318
parse: simplify parse_fn_body
Centril Mar 5, 2020
be86b2d
parse: recover on `fn foo() = expr;`
Centril Mar 5, 2020
addbc5b
unify/improve/simplify attribute parsing
Centril Mar 5, 2020
fe848b4
parse_block_tail: reduce visibility
Centril Mar 5, 2020
e72df7e
parse_labeled_expr: add a suggestion on missing colon.
Centril Mar 6, 2020
83be689
parser/attr: adjust indentation.
Centril Mar 7, 2020
65b7ba5
parser: add note for `'label expr`.
Centril Mar 7, 2020
c01b3e6
block-no-opening-brace: add another statement
Centril Mar 7, 2020
09997e7
error_block_no_opening_brace: handle closures better
Centril Mar 7, 2020
25cd01b
issue 68890: add more minimal repro
Centril Mar 7, 2020
c0b073b
simplify & improve parse_ty_tuple_or_parens
Centril Mar 7, 2020
d1822b3
use check_path more
Centril Mar 7, 2020
ba3ae46
trait-object-lifetime-parens: improve recovery.
Centril Mar 7, 2020
458383d
parse_if_expr: recover on attributes
Centril Mar 7, 2020
b6df42a
Rollup merge of #69122 - dtolnay:backtrace, r=cramertj
Centril Mar 10, 2020
5bacc26
Rollup merge of #69591 - matthewjasper:query-response-relate, r=nikom…
Centril Mar 10, 2020
66cac64
Rollup merge of #69760 - Centril:parse-expr-improve, r=estebank
Centril Mar 10, 2020
c64771e
Rollup merge of #69837 - jonas-schievink:gen-discr-opt, r=tmandry
Centril Mar 10, 2020
7dbdd72
Rollup merge of #69838 - Centril:expand-module, r=petrochenkov,eddyb
Centril Mar 10, 2020
5d10555
Rollup merge of #69859 - contrun:fix-62456, r=matthewjasper
Centril Mar 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
outline modules: parse -> expand.
Centril committed Mar 8, 2020
commit a9fd977a41b0b9e91ff0d30e9b5eb17fc82c5e7a
5 changes: 2 additions & 3 deletions src/librustc_builtin_macros/source_util.rs
Original file line number Diff line number Diff line change
@@ -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>,
77 changes: 46 additions & 31 deletions src/librustc_expand/expand.rs
Original file line number Diff line number Diff line change
@@ -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};
@@ -1360,8 +1360,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::Mac(..) => {
item.attrs = attrs;
self.check_attributes(&item.attrs);
item.and_then(|item| match item.kind {
ItemKind::Mac(mac) => self
@@ -1373,45 +1377,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)
}
}
}

37 changes: 12 additions & 25 deletions src/librustc_expand/mbe/macro_rules.rs
Original file line number Diff line number Diff line change
@@ -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<dyn MacResult + 'cx> {
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
9 changes: 0 additions & 9 deletions src/librustc_parse/config.rs
Original file line number Diff line number Diff line change
@@ -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<Attribute>) -> 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)
}
20 changes: 6 additions & 14 deletions src/librustc_parse/lib.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(try_blocks)]

use rustc_ast::ast;
use rustc_ast::token::{self, Nonterminal, Token};
@@ -118,10 +119,7 @@ pub fn maybe_new_parser_from_source_str(
name: FileName,
source: String,
) -> Result<Parser<'_>, Vec<Diagnostic>> {
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.
@@ -145,12 +143,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<String>,
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<'a>(
sess: &'a ParseSess,
stream: TokenStream,
base_dir: Directory,
) -> Parser<'a> {
Parser::new(sess, stream, Some(base_dir), true, false, None)
pub fn stream_to_parser_with_base_dir<'a>(sess: &'a ParseSess, stream: TokenStream) -> Parser<'a> {
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()?;
33 changes: 1 addition & 32 deletions src/librustc_parse/parser/mod.rs
Original file line number Diff line number Diff line change
@@ -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! {
@@ -104,21 +101,13 @@ pub struct Parser<'a> {
/// this also includes edition checks for edition-specific keyword identifiers.
pub normalized_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.
pub root_module_name: Option<String>,
expected_tokens: Vec<TokenType>,
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.
@@ -366,8 +355,6 @@ impl<'a> Parser<'a> {
pub fn new(
sess: &'a ParseSess,
tokens: TokenStream,
directory: Option<Directory>,
recurse_into_file_modules: bool,
desugar_doc_comments: bool,
subparser_name: Option<&'static str>,
) -> Self {
@@ -378,19 +365,13 @@ impl<'a> Parser<'a> {
prev_token: Token::dummy(),
normalized_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 {
frame: TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, &tokens),
stack: Vec::new(),
},
desugar_doc_comments,
cfg_mods: true,
unmatched_angle_bracket_count: 0,
max_angle_bracket_count: 0,
unclosed_delims: Vec::new(),
@@ -402,18 +383,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
}

105 changes: 48 additions & 57 deletions src/librustc_parse/parser/module.rs
Original file line number Diff line number Diff line change
@@ -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 <foo> { ... }` or `mod <foo>;` item.
pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> 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<Attribute>) {
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<Attribute>)> {
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<Attribute>,
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,27 +144,27 @@ 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
// `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 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>(
10 changes: 1 addition & 9 deletions src/librustc_parse/parser/stmt.rs
Original file line number Diff line number Diff line change
@@ -4,7 +4,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, Mac, MacStmtStyle};
@@ -56,7 +55,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) {
@@ -74,13 +73,6 @@ impl<'a> Parser<'a> {
Ok(Some(stmt))
}

fn parse_stmt_item(&mut self, attrs: Vec<Attribute>) -> PResult<'a, Option<ast::Item>> {
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<Attribute>) -> PResult<'a, Stmt> {
let path = self.parse_path(PathStyle::Expr)?;