expand: Resolve and expand inner attributes on out-of-line modules
This commit is contained in:
parent
84c08f82b4
commit
a4cc3cae04
|
@ -4774,7 +4774,7 @@ version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
|
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"semver-parser 0.10.1",
|
"semver-parser 0.10.2",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4786,9 +4786,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver-parser"
|
name = "semver-parser"
|
||||||
version = "0.10.1"
|
version = "0.10.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428"
|
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pest",
|
"pest",
|
||||||
]
|
]
|
||||||
|
|
|
@ -2297,7 +2297,7 @@ impl FnRetTy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
|
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
|
||||||
pub enum Inline {
|
pub enum Inline {
|
||||||
Yes,
|
Yes,
|
||||||
No,
|
No,
|
||||||
|
|
|
@ -1282,16 +1282,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
||||||
let (file_path, dir_path, dir_ownership) = match mod_kind {
|
let (file_path, dir_path, dir_ownership) = match mod_kind {
|
||||||
ModKind::Loaded(_, inline, _) => {
|
ModKind::Loaded(_, inline, _) => {
|
||||||
// Inline `mod foo { ... }`, but we still need to push directories.
|
// 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(
|
let (dir_path, dir_ownership) = mod_dir_path(
|
||||||
&self.cx.sess,
|
&self.cx.sess,
|
||||||
ident,
|
ident,
|
||||||
&attrs,
|
&attrs,
|
||||||
&self.cx.current_expansion.module,
|
&self.cx.current_expansion.module,
|
||||||
self.cx.current_expansion.dir_ownership,
|
self.cx.current_expansion.dir_ownership,
|
||||||
|
*inline,
|
||||||
);
|
);
|
||||||
item.attrs = attrs;
|
item.attrs = attrs;
|
||||||
(None, dir_path, dir_ownership)
|
(None, dir_path, dir_ownership)
|
||||||
|
@ -1322,10 +1319,19 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
||||||
item.attrs = attrs;
|
item.attrs = attrs;
|
||||||
if item.attrs.len() > old_attrs_len {
|
if item.attrs.len() > old_attrs_len {
|
||||||
// If we loaded an out-of-line module and added some inner attributes,
|
// If we loaded an out-of-line module and added some inner attributes,
|
||||||
// then we need to re-configure it.
|
// then we need to re-configure it and re-collect attributes for
|
||||||
// FIXME: Attributes also need to be recollected
|
// resolution and expansion.
|
||||||
// for resolution and expansion.
|
|
||||||
item = configure!(self, item);
|
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)
|
(Some(file_path), dir_path, dir_ownership)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::base::ModuleData;
|
use crate::base::ModuleData;
|
||||||
use rustc_ast::ptr::P;
|
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_errors::{struct_span_err, DiagnosticBuilder};
|
||||||
use rustc_parse::new_parser_from_file;
|
use rustc_parse::new_parser_from_file;
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
|
@ -83,29 +83,49 @@ crate fn mod_dir_path(
|
||||||
attrs: &[Attribute],
|
attrs: &[Attribute],
|
||||||
module: &ModuleData,
|
module: &ModuleData,
|
||||||
mut dir_ownership: DirOwnership,
|
mut dir_ownership: DirOwnership,
|
||||||
|
inline: Inline,
|
||||||
) -> (PathBuf, DirOwnership) {
|
) -> (PathBuf, DirOwnership) {
|
||||||
if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) {
|
match inline {
|
||||||
// For inline modules file path from `#[path]` is actually the directory path
|
Inline::Yes => {
|
||||||
// for historical reasons, so we don't pop the last segment here.
|
if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) {
|
||||||
return (file_path, DirOwnership::Owned { relative: None });
|
// 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
|
// 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
|
||||||
// `mod x { ... }` come after the relative extension.
|
// `mod x { ... }` come after the relative extension.
|
||||||
//
|
//
|
||||||
// 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`.
|
||||||
let mut dir_path = module.dir_path.clone();
|
let mut dir_path = module.dir_path.clone();
|
||||||
if let DirOwnership::Owned { relative } = &mut dir_ownership {
|
if let DirOwnership::Owned { relative } = &mut dir_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());
|
||||||
|
}
|
||||||
|
}
|
||||||
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>(
|
fn mod_file_path<'a>(
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::Namespace::*;
|
||||||
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy};
|
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy};
|
||||||
use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
|
use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
|
||||||
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
|
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_lowering::ResolverAstLowering;
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_attr::StabilityLevel;
|
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::ptr_key::PtrKey;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::struct_span_err;
|
||||||
|
use rustc_expand::base::Annotatable;
|
||||||
use rustc_expand::base::{Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
|
use rustc_expand::base::{Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
|
||||||
use rustc_expand::compile_declarative_macro;
|
use rustc_expand::compile_declarative_macro;
|
||||||
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
|
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
|
||||||
|
@ -153,6 +154,26 @@ crate fn registered_attrs_and_tools(
|
||||||
(registered_attrs, registered_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> {
|
impl<'a> ResolverExpand for Resolver<'a> {
|
||||||
fn next_node_id(&mut self) -> NodeId {
|
fn next_node_id(&mut self) -> NodeId {
|
||||||
self.next_node_id()
|
self.next_node_id()
|
||||||
|
@ -267,6 +288,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
||||||
parent_scope,
|
parent_scope,
|
||||||
node_id,
|
node_id,
|
||||||
force,
|
force,
|
||||||
|
soft_custom_inner_attributes_gate(path, invoc),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let span = invoc.span();
|
let span = invoc.span();
|
||||||
|
@ -440,6 +462,7 @@ impl<'a> Resolver<'a> {
|
||||||
parent_scope: &ParentScope<'a>,
|
parent_scope: &ParentScope<'a>,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
force: bool,
|
force: bool,
|
||||||
|
soft_custom_inner_attributes_gate: bool,
|
||||||
) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
|
) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
|
||||||
let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
|
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",
|
Res::NonMacroAttr(..) => "custom inner attributes are unstable",
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
if path == &sym::test {
|
if soft_custom_inner_attributes_gate {
|
||||||
self.session.parse_sess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
|
self.session.parse_sess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
|
||||||
} else {
|
} else {
|
||||||
feature_err(&self.session.parse_sess, sym::custom_inner_attributes, path.span, msg)
|
feature_err(&self.session.parse_sess, sym::custom_inner_attributes, path.span, msg)
|
||||||
|
|
|
@ -1111,6 +1111,7 @@ symbols! {
|
||||||
size_of,
|
size_of,
|
||||||
size_of_val,
|
size_of_val,
|
||||||
sized,
|
sized,
|
||||||
|
skip,
|
||||||
slice,
|
slice,
|
||||||
slice_alloc,
|
slice_alloc,
|
||||||
slice_patterns,
|
slice_patterns,
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
mod module_with_cfg;
|
||||||
|
|
||||||
|
mod module_with_cfg {} // Ok, the module above is configured away by an inner attribute.
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,3 @@
|
||||||
|
// ignore-test
|
||||||
|
|
||||||
|
#![cfg_attr(all(), cfg(FALSE))]
|
|
@ -0,0 +1,18 @@
|
||||||
|
// compile-flags: -Z span-debug
|
||||||
|
// error-pattern:custom inner attributes are unstable
|
||||||
|
// error-pattern:inner macro attributes are unstable
|
||||||
|
// error-pattern:this was previously accepted
|
||||||
|
// aux-build:test-macros.rs
|
||||||
|
|
||||||
|
#![no_std] // Don't load unnecessary hygiene information from std
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate test_macros;
|
||||||
|
|
||||||
|
#[deny(unused_attributes)]
|
||||||
|
mod module_with_attrs;
|
||||||
|
//~^ ERROR non-inline modules in proc macro input are unstable
|
||||||
|
//~| ERROR custom inner attributes are unstable
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,40 @@
|
||||||
|
error[E0658]: inner macro attributes are unstable
|
||||||
|
--> $DIR/module_with_attrs.rs:4:4
|
||||||
|
|
|
||||||
|
LL | #![print_attr]
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
|
||||||
|
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: non-inline modules in proc macro input are unstable
|
||||||
|
--> $DIR/inner-attr-non-inline-mod.rs:14:1
|
||||||
|
|
|
||||||
|
LL | mod module_with_attrs;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #54727 <https://github.com/rust-lang/rust/issues/54727> for more information
|
||||||
|
= help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: custom inner attributes are unstable
|
||||||
|
--> $DIR/inner-attr-non-inline-mod.rs:14:1
|
||||||
|
|
|
||||||
|
LL | mod module_with_attrs;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
|
||||||
|
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: custom inner attributes are unstable
|
||||||
|
--> $DIR/module_with_attrs.rs:3:4
|
||||||
|
|
|
||||||
|
LL | #![rustfmt::skip]
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[deny(soft_unstable)]` on by default
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266>
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
|
@ -0,0 +1,76 @@
|
||||||
|
PRINT-ATTR INPUT (DISPLAY): #[deny(unused_attributes)] mod module_with_attrs { # ! [rustfmt :: skip] }
|
||||||
|
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||||
|
Punct {
|
||||||
|
ch: '#',
|
||||||
|
spacing: Alone,
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Bracket,
|
||||||
|
stream: TokenStream [
|
||||||
|
Ident {
|
||||||
|
ident: "deny",
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Parenthesis,
|
||||||
|
stream: TokenStream [
|
||||||
|
Ident {
|
||||||
|
ident: "unused_attributes",
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "mod",
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "module_with_attrs",
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Brace,
|
||||||
|
stream: TokenStream [
|
||||||
|
Punct {
|
||||||
|
ch: '#',
|
||||||
|
spacing: Joint,
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
Punct {
|
||||||
|
ch: '!',
|
||||||
|
spacing: Alone,
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Bracket,
|
||||||
|
stream: TokenStream [
|
||||||
|
Ident {
|
||||||
|
ident: "rustfmt",
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
Punct {
|
||||||
|
ch: ':',
|
||||||
|
spacing: Joint,
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
Punct {
|
||||||
|
ch: ':',
|
||||||
|
spacing: Alone,
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "skip",
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0),
|
||||||
|
},
|
||||||
|
]
|
|
@ -0,0 +1,4 @@
|
||||||
|
// ignore-test
|
||||||
|
|
||||||
|
#![rustfmt::skip]
|
||||||
|
#![print_attr]
|
Loading…
Reference in New Issue