1
Fork 0

expand: Resolve and expand inner attributes on out-of-line modules

This commit is contained in:
Vadim Petrochenkov 2021-02-21 16:32:38 +03:00
parent 84c08f82b4
commit a4cc3cae04
12 changed files with 230 additions and 32 deletions

View file

@ -2297,7 +2297,7 @@ impl FnRetTy {
}
}
#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
pub enum Inline {
Yes,
No,

View file

@ -1282,16 +1282,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
let (file_path, dir_path, dir_ownership) = match mod_kind {
ModKind::Loaded(_, inline, _) => {
// Inline `mod foo { ... }`, but we still need to push directories.
assert!(
*inline == Inline::Yes,
"`mod` item is loaded from a file for the second time"
);
let (dir_path, dir_ownership) = mod_dir_path(
&self.cx.sess,
ident,
&attrs,
&self.cx.current_expansion.module,
self.cx.current_expansion.dir_ownership,
*inline,
);
item.attrs = attrs;
(None, dir_path, dir_ownership)
@ -1322,10 +1319,19 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
item.attrs = attrs;
if item.attrs.len() > old_attrs_len {
// If we loaded an out-of-line module and added some inner attributes,
// then we need to re-configure it.
// FIXME: Attributes also need to be recollected
// for resolution and expansion.
// then we need to re-configure it and re-collect attributes for
// resolution and expansion.
item = configure!(self, item);
if let Some(attr) = self.take_first_attr(&mut item) {
return self
.collect_attr(
attr,
Annotatable::Item(item),
AstFragmentKind::Items,
)
.make_items();
}
}
(Some(file_path), dir_path, dir_ownership)
}

View file

@ -1,6 +1,6 @@
use crate::base::ModuleData;
use rustc_ast::ptr::P;
use rustc_ast::{token, Attribute, Item};
use rustc_ast::{token, Attribute, Inline, Item};
use rustc_errors::{struct_span_err, DiagnosticBuilder};
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
@ -83,29 +83,49 @@ crate fn mod_dir_path(
attrs: &[Attribute],
module: &ModuleData,
mut dir_ownership: DirOwnership,
inline: Inline,
) -> (PathBuf, DirOwnership) {
if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) {
// For inline modules file path from `#[path]` is actually the directory path
// for historical reasons, so we don't pop the last segment here.
return (file_path, DirOwnership::Owned { relative: None });
}
match inline {
Inline::Yes => {
if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) {
// For inline modules file path from `#[path]` is actually the directory path
// for historical reasons, so we don't pop the last segment here.
return (file_path, DirOwnership::Owned { relative: None });
}
// 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`.
let mut dir_path = module.dir_path.clone();
if let DirOwnership::Owned { relative } = &mut dir_ownership {
if let Some(ident) = relative.take() {
// Remove the relative offset.
// 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`.
let mut dir_path = module.dir_path.clone();
if let DirOwnership::Owned { relative } = &mut dir_ownership {
if let Some(ident) = relative.take() {
// Remove the relative offset.
dir_path.push(&*ident.as_str());
}
}
dir_path.push(&*ident.as_str());
(dir_path, dir_ownership)
}
Inline::No => {
// FIXME: This is a subset of `parse_external_mod` without actual parsing,
// check whether the logic for unloaded, loaded and inline modules can be unified.
let file_path = mod_file_path(sess, ident, &attrs, &module.dir_path, dir_ownership)
.map(|mp| {
dir_ownership = mp.dir_ownership;
mp.file_path
})
.unwrap_or_default();
// Extract the directory path for submodules of the module.
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
(dir_path, dir_ownership)
}
}
dir_path.push(&*ident.as_str());
(dir_path, dir_ownership)
}
fn mod_file_path<'a>(

View file

@ -6,7 +6,7 @@ use crate::Namespace::*;
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy};
use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::{self as ast, NodeId};
use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust;
use rustc_attr::StabilityLevel;
@ -14,6 +14,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::ptr_key::PtrKey;
use rustc_data_structures::sync::Lrc;
use rustc_errors::struct_span_err;
use rustc_expand::base::Annotatable;
use rustc_expand::base::{Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
@ -153,6 +154,26 @@ crate fn registered_attrs_and_tools(
(registered_attrs, registered_tools)
}
// Some feature gates for inner attributes are reported as lints for backward compatibility.
fn soft_custom_inner_attributes_gate(path: &ast::Path, invoc: &Invocation) -> bool {
match &path.segments[..] {
// `#![test]`
[seg] if seg.ident.name == sym::test => return true,
// `#![rustfmt::skip]` on out-of-line modules
[seg1, seg2] if seg1.ident.name == sym::rustfmt && seg2.ident.name == sym::skip => {
if let InvocationKind::Attr { item, .. } = &invoc.kind {
if let Annotatable::Item(item) = item {
if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _)) = item.kind {
return true;
}
}
}
}
_ => {}
}
false
}
impl<'a> ResolverExpand for Resolver<'a> {
fn next_node_id(&mut self) -> NodeId {
self.next_node_id()
@ -267,6 +288,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
parent_scope,
node_id,
force,
soft_custom_inner_attributes_gate(path, invoc),
)?;
let span = invoc.span();
@ -440,6 +462,7 @@ impl<'a> Resolver<'a> {
parent_scope: &ParentScope<'a>,
node_id: NodeId,
force: bool,
soft_custom_inner_attributes_gate: bool,
) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
{
@ -507,7 +530,7 @@ impl<'a> Resolver<'a> {
Res::NonMacroAttr(..) => "custom inner attributes are unstable",
_ => unreachable!(),
};
if path == &sym::test {
if soft_custom_inner_attributes_gate {
self.session.parse_sess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
} else {
feature_err(&self.session.parse_sess, sym::custom_inner_attributes, path.span, msg)

View file

@ -1111,6 +1111,7 @@ symbols! {
size_of,
size_of_val,
sized,
skip,
slice,
slice_alloc,
slice_patterns,