mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
outline modules: parse -> expand.
This commit is contained in:
parent
59bf8a07f9
commit
83a757a9ca
@ -5,7 +5,7 @@ use rustc_ast::tokenstream::TokenStream;
|
|||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_expand::base::{self, *};
|
use rustc_expand::base::{self, *};
|
||||||
use rustc_expand::panictry;
|
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_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::{self, Pos, Span};
|
use rustc_span::{self, Pos, Span};
|
||||||
@ -108,8 +108,7 @@ pub fn expand_include<'cx>(
|
|||||||
return DummyResult::any(sp);
|
return DummyResult::any(sp);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let directory_ownership = DirectoryOwnership::Owned { relative: None };
|
let p = new_sub_parser_from_file(cx.parse_sess(), &file, None, sp);
|
||||||
let p = new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp);
|
|
||||||
|
|
||||||
struct ExpandResult<'a> {
|
struct ExpandResult<'a> {
|
||||||
p: Parser<'a>,
|
p: Parser<'a>,
|
||||||
|
@ -18,10 +18,10 @@ use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
|
|||||||
use rustc_errors::{Applicability, FatalError, PResult};
|
use rustc_errors::{Applicability, FatalError, PResult};
|
||||||
use rustc_feature::Features;
|
use rustc_feature::Features;
|
||||||
use rustc_parse::configure;
|
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::parser::Parser;
|
||||||
use rustc_parse::validate_attr;
|
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::builtin::UNUSED_DOC_COMMENTS;
|
||||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||||
use rustc_session::parse::{feature_err, ParseSess};
|
use rustc_session::parse::{feature_err, ParseSess};
|
||||||
@ -1428,8 +1428,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||||||
.make_items();
|
.make_items();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck.
|
||||||
|
let ident = item.ident;
|
||||||
|
|
||||||
match item.kind {
|
match item.kind {
|
||||||
ast::ItemKind::MacCall(..) => {
|
ast::ItemKind::MacCall(..) => {
|
||||||
|
item.attrs = attrs;
|
||||||
self.check_attributes(&item.attrs);
|
self.check_attributes(&item.attrs);
|
||||||
item.and_then(|item| match item.kind {
|
item.and_then(|item| match item.kind {
|
||||||
ItemKind::MacCall(mac) => self
|
ItemKind::MacCall(mac) => self
|
||||||
@ -1441,45 +1445,56 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ast::ItemKind::Mod(ast::Mod { inner, inline, .. })
|
ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => {
|
||||||
if item.ident != Ident::invalid() =>
|
let sess = self.cx.parse_sess;
|
||||||
{
|
let orig_ownership = self.cx.current_expansion.directory_ownership;
|
||||||
let orig_directory_ownership = self.cx.current_expansion.directory_ownership;
|
|
||||||
let mut module = (*self.cx.current_expansion.module).clone();
|
let mut module = (*self.cx.current_expansion.module).clone();
|
||||||
module.mod_path.push(item.ident);
|
|
||||||
|
|
||||||
if inline {
|
let pushed = &mut false; // Record `parse_external_mod` pushing so we can pop.
|
||||||
module::push_directory(
|
let dir = Directory { ownership: orig_ownership, path: module.directory };
|
||||||
item.ident,
|
let Directory { ownership, path } = if old_mod.inline {
|
||||||
&item.attrs,
|
// Inline `mod foo { ... }`, but we still need to push directories.
|
||||||
&mut self.cx.current_expansion.directory_ownership,
|
item.attrs = attrs;
|
||||||
&mut module.directory,
|
push_directory(ident, &item.attrs, dir)
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
let path = self.cx.parse_sess.source_map().span_to_unmapped_path(inner);
|
// We have an outline `mod foo;` so we need to parse the file.
|
||||||
let mut path = match path {
|
let (new_mod, dir) = parse_external_mod(sess, ident, dir, &mut attrs, pushed);
|
||||||
FileName::Real(path) => path,
|
*old_mod = new_mod;
|
||||||
other => PathBuf::from(other.to_string()),
|
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();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let directory_ownership = match path.file_name().unwrap().to_str() {
|
dir
|
||||||
Some("mod.rs") => DirectoryOwnership::Owned { relative: None },
|
};
|
||||||
Some(_) => DirectoryOwnership::Owned { relative: Some(item.ident) },
|
|
||||||
None => DirectoryOwnership::UnownedViaMod,
|
|
||||||
};
|
|
||||||
path.pop();
|
|
||||||
module.directory = path;
|
|
||||||
self.cx.current_expansion.directory_ownership = directory_ownership;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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 =
|
let orig_module =
|
||||||
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
|
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
|
||||||
|
|
||||||
let result = noop_flat_map_item(item, self);
|
let result = noop_flat_map_item(item, self);
|
||||||
|
|
||||||
|
// Restore the module info.
|
||||||
self.cx.current_expansion.module = orig_module;
|
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
|
result
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
_ => noop_flat_map_item(item, self),
|
item.attrs = attrs;
|
||||||
|
noop_flat_map_item(item, self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||||
use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind};
|
use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind};
|
||||||
use crate::mbe;
|
use crate::mbe;
|
||||||
@ -18,7 +18,6 @@ use rustc_data_structures::sync::Lrc;
|
|||||||
use rustc_errors::{Applicability, DiagnosticBuilder, FatalError};
|
use rustc_errors::{Applicability, DiagnosticBuilder, FatalError};
|
||||||
use rustc_feature::Features;
|
use rustc_feature::Features;
|
||||||
use rustc_parse::parser::Parser;
|
use rustc_parse::parser::Parser;
|
||||||
use rustc_parse::Directory;
|
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::hygiene::Transparency;
|
use rustc_span::hygiene::Transparency;
|
||||||
@ -182,6 +181,8 @@ fn generic_extension<'cx>(
|
|||||||
lhses: &[mbe::TokenTree],
|
lhses: &[mbe::TokenTree],
|
||||||
rhses: &[mbe::TokenTree],
|
rhses: &[mbe::TokenTree],
|
||||||
) -> Box<dyn MacResult + 'cx> {
|
) -> Box<dyn MacResult + 'cx> {
|
||||||
|
let sess = cx.parse_sess;
|
||||||
|
|
||||||
if cx.trace_macros() {
|
if cx.trace_macros() {
|
||||||
let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone()));
|
let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone()));
|
||||||
trace_macros_note(&mut cx.expansions, sp, msg);
|
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
|
// hacky, but speeds up the `html5ever` benchmark significantly. (Issue
|
||||||
// 68836 suggests a more comprehensive but more complex change to deal with
|
// 68836 suggests a more comprehensive but more complex change to deal with
|
||||||
// this situation.)
|
// 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() {
|
for (i, lhs) in lhses.iter().enumerate() {
|
||||||
// try each arm's matchers
|
// 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,
|
// This is used so that if a matcher is not `Success(..)`ful,
|
||||||
// then the spans which became gated when parsing the unsuccessful matcher
|
// then the spans which became gated when parsing the unsuccessful matcher
|
||||||
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
|
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
|
||||||
let mut gated_spans_snapshot =
|
let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut());
|
||||||
mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut());
|
|
||||||
|
|
||||||
match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) {
|
match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) {
|
||||||
Success(named_matches) => {
|
Success(named_matches) => {
|
||||||
// The matcher was `Success(..)`ful.
|
// The matcher was `Success(..)`ful.
|
||||||
// Merge the gated spans from parsing the matcher with the pre-existing ones.
|
// 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] {
|
let rhs = match rhses[i] {
|
||||||
// ignore delimiters
|
// ignore delimiters
|
||||||
@ -258,11 +258,7 @@ fn generic_extension<'cx>(
|
|||||||
trace_macros_note(&mut cx.expansions, sp, msg);
|
trace_macros_note(&mut cx.expansions, sp, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let directory = Directory {
|
let mut p = Parser::new(cx.parse_sess(), tts, false, None);
|
||||||
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);
|
|
||||||
p.root_module_name =
|
p.root_module_name =
|
||||||
cx.current_expansion.module.mod_path.last().map(|id| id.to_string());
|
cx.current_expansion.module.mod_path.last().map(|id| id.to_string());
|
||||||
p.last_type_ascription = cx.current_expansion.prior_type_ascription;
|
p.last_type_ascription = cx.current_expansion.prior_type_ascription;
|
||||||
@ -289,7 +285,7 @@ fn generic_extension<'cx>(
|
|||||||
|
|
||||||
// The matcher was not `Success(..)`ful.
|
// The matcher was not `Success(..)`ful.
|
||||||
// Restore to the state before snapshotting and maybe try again.
|
// 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);
|
drop(parser);
|
||||||
|
|
||||||
@ -309,8 +305,7 @@ fn generic_extension<'cx>(
|
|||||||
mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
|
mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
let parser = parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone());
|
match parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt) {
|
||||||
match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) {
|
|
||||||
Success(_) => {
|
Success(_) => {
|
||||||
if comma_span.is_dummy() {
|
if comma_span.is_dummy() {
|
||||||
err.note("you might be missing a comma");
|
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) {
|
let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
|
||||||
Success(m) => m,
|
Success(m) => m,
|
||||||
Failure(token, msg) => {
|
Failure(token, msg) => {
|
||||||
@ -1209,16 +1204,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parser_from_cx<'cx>(
|
fn parser_from_cx<'cx>(sess: &'cx ParseSess, tts: TokenStream) -> Parser<'cx> {
|
||||||
current_expansion: &'cx ExpansionData,
|
Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
|
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
|
||||||
|
@ -538,12 +538,3 @@ impl<'a> MutVisitor for StripUnconfigured<'a> {
|
|||||||
fn is_cfg(attr: &Attribute) -> bool {
|
fn is_cfg(attr: &Attribute) -> bool {
|
||||||
attr.check_name(sym::cfg)
|
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)
|
|
||||||
}
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#![feature(bool_to_option)]
|
#![feature(bool_to_option)]
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
#![feature(bindings_after_at)]
|
#![feature(bindings_after_at)]
|
||||||
|
#![feature(try_blocks)]
|
||||||
|
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_ast::token::{self, Nonterminal};
|
use rustc_ast::token::{self, Nonterminal};
|
||||||
@ -119,10 +120,7 @@ pub fn maybe_new_parser_from_source_str(
|
|||||||
name: FileName,
|
name: FileName,
|
||||||
source: String,
|
source: String,
|
||||||
) -> Result<Parser<'_>, Vec<Diagnostic>> {
|
) -> Result<Parser<'_>, Vec<Diagnostic>> {
|
||||||
let mut parser =
|
maybe_source_file_to_parser(sess, sess.source_map().new_source_file(name, source))
|
||||||
maybe_source_file_to_parser(sess, sess.source_map().new_source_file(name, source))?;
|
|
||||||
parser.recurse_into_file_modules = false;
|
|
||||||
Ok(parser)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new parser, handling errors as appropriate if the file doesn't exist.
|
/// 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>(
|
pub fn new_sub_parser_from_file<'a>(
|
||||||
sess: &'a ParseSess,
|
sess: &'a ParseSess,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
directory_ownership: DirectoryOwnership,
|
|
||||||
module_name: Option<String>,
|
module_name: Option<String>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
) -> Parser<'a> {
|
) -> Parser<'a> {
|
||||||
let mut p = source_file_to_parser(sess, file_to_source_file(sess, path, Some(sp)));
|
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.root_module_name = module_name;
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
@ -257,7 +253,7 @@ pub fn stream_to_parser<'a>(
|
|||||||
stream: TokenStream,
|
stream: TokenStream,
|
||||||
subparser_name: Option<&'static str>,
|
subparser_name: Option<&'static str>,
|
||||||
) -> Parser<'a> {
|
) -> 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.
|
/// 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
|
/// 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
|
/// librustc_ast as a library. Please do not remove this function while refactoring
|
||||||
/// just because it is not used in rustc codebase!
|
/// just because it is not used in rustc codebase!
|
||||||
pub fn stream_to_parser_with_base_dir(
|
pub fn stream_to_parser_with_base_dir(sess: &ParseSess, stream: TokenStream) -> Parser<'_> {
|
||||||
sess: &ParseSess,
|
Parser::new(sess, stream, false, None)
|
||||||
stream: TokenStream,
|
|
||||||
base_dir: Directory,
|
|
||||||
) -> Parser<'_> {
|
|
||||||
Parser::new(sess, stream, Some(base_dir), true, false, None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the given subparser `f` on the tokens of the given `attr`'s item.
|
/// 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,
|
name: &'static str,
|
||||||
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||||
) -> 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)?;
|
let result = f(&mut parser)?;
|
||||||
if parser.token != token::Eof {
|
if parser.token != token::Eof {
|
||||||
parser.unexpected()?;
|
parser.unexpected()?;
|
||||||
|
@ -13,7 +13,6 @@ mod stmt;
|
|||||||
use diagnostics::Error;
|
use diagnostics::Error;
|
||||||
|
|
||||||
use crate::lexer::UnmatchedBrace;
|
use crate::lexer::UnmatchedBrace;
|
||||||
use crate::{Directory, DirectoryOwnership};
|
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rustc_ast::ast::DUMMY_NODE_ID;
|
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_ast_pretty::pprust;
|
||||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult};
|
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult};
|
||||||
use rustc_session::parse::ParseSess;
|
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::symbol::{kw, sym, Symbol};
|
||||||
use rustc_span::{FileName, Span, DUMMY_SP};
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::{cmp, mem, slice};
|
use std::{cmp, mem, slice};
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
@ -93,11 +90,6 @@ pub struct Parser<'a> {
|
|||||||
/// The previous token.
|
/// The previous token.
|
||||||
pub prev_token: Token,
|
pub prev_token: Token,
|
||||||
restrictions: Restrictions,
|
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 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
|
/// name is not known. This does not change while the parser is descending
|
||||||
/// into modules, and sub-parsers have new values for this name.
|
/// into modules, and sub-parsers have new values for this name.
|
||||||
@ -105,9 +97,6 @@ pub struct Parser<'a> {
|
|||||||
expected_tokens: Vec<TokenType>,
|
expected_tokens: Vec<TokenType>,
|
||||||
token_cursor: TokenCursor,
|
token_cursor: TokenCursor,
|
||||||
desugar_doc_comments: bool,
|
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
|
/// 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
|
/// required in order to detect extra leading left angle brackets (`<` characters) and error
|
||||||
/// appropriately.
|
/// appropriately.
|
||||||
@ -355,8 +344,6 @@ impl<'a> Parser<'a> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
sess: &'a ParseSess,
|
sess: &'a ParseSess,
|
||||||
tokens: TokenStream,
|
tokens: TokenStream,
|
||||||
directory: Option<Directory>,
|
|
||||||
recurse_into_file_modules: bool,
|
|
||||||
desugar_doc_comments: bool,
|
desugar_doc_comments: bool,
|
||||||
subparser_name: Option<&'static str>,
|
subparser_name: Option<&'static str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -365,11 +352,6 @@ impl<'a> Parser<'a> {
|
|||||||
token: Token::dummy(),
|
token: Token::dummy(),
|
||||||
prev_token: Token::dummy(),
|
prev_token: Token::dummy(),
|
||||||
restrictions: Restrictions::empty(),
|
restrictions: Restrictions::empty(),
|
||||||
recurse_into_file_modules,
|
|
||||||
directory: Directory {
|
|
||||||
path: PathBuf::new(),
|
|
||||||
ownership: DirectoryOwnership::Owned { relative: None },
|
|
||||||
},
|
|
||||||
root_module_name: None,
|
root_module_name: None,
|
||||||
expected_tokens: Vec::new(),
|
expected_tokens: Vec::new(),
|
||||||
token_cursor: TokenCursor {
|
token_cursor: TokenCursor {
|
||||||
@ -377,7 +359,6 @@ impl<'a> Parser<'a> {
|
|||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
},
|
},
|
||||||
desugar_doc_comments,
|
desugar_doc_comments,
|
||||||
cfg_mods: true,
|
|
||||||
unmatched_angle_bracket_count: 0,
|
unmatched_angle_bracket_count: 0,
|
||||||
max_angle_bracket_count: 0,
|
max_angle_bracket_count: 0,
|
||||||
unclosed_delims: Vec::new(),
|
unclosed_delims: Vec::new(),
|
||||||
@ -389,18 +370,6 @@ impl<'a> Parser<'a> {
|
|||||||
// Make parser point to the first token.
|
// Make parser point to the first token.
|
||||||
parser.bump();
|
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
|
parser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::item::ItemInfo;
|
use super::item::ItemInfo;
|
||||||
use super::Parser;
|
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::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
|
||||||
use rustc_ast::attr;
|
use rustc_ast::attr;
|
||||||
@ -39,25 +39,12 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
|
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
|
||||||
pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
|
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 id = self.parse_ident()?;
|
||||||
let (module, mut inner_attrs) = if self.eat(&token::Semi) {
|
let (module, mut inner_attrs) = if self.eat(&token::Semi) {
|
||||||
if in_cfg && self.recurse_into_file_modules {
|
Default::default()
|
||||||
let dir = &self.directory;
|
|
||||||
parse_external_module(self.sess, self.cfg_mods, id, dir.ownership, &dir.path, attrs)
|
|
||||||
} else {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
} else {
|
} 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))?;
|
self.expect(&token::OpenDelim(token::Brace))?;
|
||||||
let module = self.parse_mod(&token::CloseDelim(token::Brace))?;
|
self.parse_mod(&token::CloseDelim(token::Brace))?
|
||||||
|
|
||||||
self.directory = old_directory;
|
|
||||||
module
|
|
||||||
};
|
};
|
||||||
attrs.append(&mut inner_attrs);
|
attrs.append(&mut inner_attrs);
|
||||||
Ok((id, ItemKind::Mod(module)))
|
Ok((id, ItemKind::Mod(module)))
|
||||||
@ -95,41 +82,45 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_external_module(
|
pub fn parse_external_mod(
|
||||||
sess: &ParseSess,
|
sess: &ParseSess,
|
||||||
cfg_mods: bool,
|
|
||||||
id: ast::Ident,
|
id: ast::Ident,
|
||||||
ownership: DirectoryOwnership,
|
Directory { mut ownership, path }: Directory,
|
||||||
dir_path: &Path,
|
attrs: &mut Vec<Attribute>,
|
||||||
attrs: &[Attribute],
|
pop_mod_stack: &mut bool,
|
||||||
) -> (Mod, Vec<Attribute>) {
|
) -> (Mod, Directory) {
|
||||||
submod_path(sess, id, &attrs, ownership, dir_path)
|
// We bail on the first error, but that error does not cause a fatal error... (1)
|
||||||
.and_then(|r| eval_src_mod(sess, cfg_mods, r.path, r.ownership, id))
|
let result: PResult<'_, _> = try {
|
||||||
.map_err(|mut err| err.emit())
|
// Extract the file path and the new ownership.
|
||||||
.unwrap_or_default()
|
let mp = submod_path(sess, id, &attrs, ownership, &path)?;
|
||||||
}
|
ownership = mp.ownership;
|
||||||
|
|
||||||
/// Reads a module from a source file.
|
// Ensure file paths are acyclic.
|
||||||
fn eval_src_mod<'a>(
|
let mut included_mod_stack = sess.included_mod_stack.borrow_mut();
|
||||||
sess: &'a ParseSess,
|
error_on_circular_module(sess, id.span, &mp.path, &included_mod_stack)?;
|
||||||
cfg_mods: bool,
|
included_mod_stack.push(mp.path.clone());
|
||||||
path: PathBuf,
|
*pop_mod_stack = true; // We have pushed, so notify caller.
|
||||||
dir_ownership: DirectoryOwnership,
|
drop(included_mod_stack);
|
||||||
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 =
|
// Actually parse the external file as amodule.
|
||||||
new_sub_parser_from_file(sess, &path, dir_ownership, Some(id.to_string()), id.span);
|
let mut p0 = new_sub_parser_from_file(sess, &mp.path, Some(id.to_string()), id.span);
|
||||||
p0.cfg_mods = cfg_mods;
|
let mut module = p0.parse_mod(&token::Eof)?;
|
||||||
let mut module = p0.parse_mod(&token::Eof)?;
|
module.0.inline = false;
|
||||||
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);
|
||||||
|
|
||||||
sess.included_mod_stack.borrow_mut().pop();
|
// Extract the directory path for submodules of `module`.
|
||||||
Ok(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>(
|
fn error_on_circular_module<'a>(
|
||||||
@ -153,12 +144,11 @@ fn error_on_circular_module<'a>(
|
|||||||
pub fn push_directory(
|
pub fn push_directory(
|
||||||
id: Ident,
|
id: Ident,
|
||||||
attrs: &[Attribute],
|
attrs: &[Attribute],
|
||||||
dir_ownership: &mut DirectoryOwnership,
|
Directory { mut ownership, mut path }: Directory,
|
||||||
dir_path: &mut PathBuf,
|
) -> Directory {
|
||||||
) {
|
if let Some(filename) = attr::first_attr_value_str_by_name(attrs, sym::path) {
|
||||||
if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
|
path.push(&*filename.as_str());
|
||||||
dir_path.push(&*path.as_str());
|
ownership = DirectoryOwnership::Owned { relative: None };
|
||||||
*dir_ownership = DirectoryOwnership::Owned { relative: None };
|
|
||||||
} else {
|
} else {
|
||||||
// We have to push on the current module name in the case of relative
|
// 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
|
// 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
|
// 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`.
|
// 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() {
|
if let Some(ident) = relative.take() {
|
||||||
// Remove the relative offset.
|
// 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>(
|
fn submod_path<'a>(
|
||||||
|
@ -5,7 +5,6 @@ use super::pat::GateOr;
|
|||||||
use super::path::PathStyle;
|
use super::path::PathStyle;
|
||||||
use super::{BlockMode, Parser, Restrictions, SemiColonMode};
|
use super::{BlockMode, Parser, Restrictions, SemiColonMode};
|
||||||
use crate::maybe_whole;
|
use crate::maybe_whole;
|
||||||
use crate::DirectoryOwnership;
|
|
||||||
|
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_ast::ast::{AttrStyle, AttrVec, Attribute, MacCall, MacStmtStyle};
|
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.
|
// that starts like a path (1 token), but it fact not a path.
|
||||||
// Also, we avoid stealing syntax from `parse_item_`.
|
// Also, we avoid stealing syntax from `parse_item_`.
|
||||||
self.parse_stmt_path_start(lo, attrs)?
|
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
|
// FIXME: Bad copy of attrs
|
||||||
self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
|
self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
|
||||||
} else if self.eat(&token::Semi) {
|
} else if self.eat(&token::Semi) {
|
||||||
@ -72,13 +71,6 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(Some(stmt))
|
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> {
|
fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec<Attribute>) -> PResult<'a, Stmt> {
|
||||||
let path = self.parse_path(PathStyle::Expr)?;
|
let path = self.parse_path(PathStyle::Expr)?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user