Skip to content

Commit

Permalink
expand: Resolve and expand inner attributes on out-of-line modules
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Feb 23, 2021
1 parent fe1bf8e commit df78eea
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 32 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2299,7 +2299,7 @@ impl FnRetTy {
}
}

#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
pub enum Inline {
Yes,
No,
Expand Down
56 changes: 41 additions & 15 deletions compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1278,16 +1278,24 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
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 } = match mod_kind {
ModKind::Loaded(_, Inline::Yes, _) => {
// Inline `mod foo { ... }`, but we still need to push directories.
ModKind::Loaded(_, inline, inner_span) => {
// Inline `mod foo { ... }` or previously loaded `mod foo;`,
// we still need to push directories.
let dir = push_directory(
&self.cx.sess,
ident,
&attrs,
dir,
*inline,
*inner_span,
span,
);
item.attrs = attrs;
push_directory(&self.cx.sess, ident, &item.attrs, dir)
}
ModKind::Loaded(_, Inline::No, _) => {
panic!("`mod` item is loaded from a file for the second time")
dir
}
ModKind::Unloaded => {
// We have an outline `mod foo;` so we need to parse the file.
let old_attrs_len = attrs.len();
let (items, inner_span, dir) =
parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);

Expand All @@ -1299,16 +1307,34 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {

*mod_kind = ModKind::Loaded(krate.items, Inline::No, inner_span);
item.attrs = krate.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();

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 and re-collect attributes for
// resolution and expansion.
let file_path = if *pushed {
sess.included_mod_stack.borrow_mut().pop()
} else {
None
};

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();
}
};

if let Some(file_path) = file_path {
sess.included_mod_stack.borrow_mut().push(file_path);
}
}

dir
}
};
Expand Down
54 changes: 38 additions & 16 deletions compiler/rustc_expand/src/module.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use rustc_ast::ptr::P;
use rustc_ast::{token, Attribute, Item};
use rustc_ast::{token, Attribute, Inline, Item};
use rustc_errors::{struct_span_err, PResult};
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
Expand Down Expand Up @@ -103,25 +103,47 @@ crate fn push_directory(
id: Ident,
attrs: &[Attribute],
Directory { mut ownership, mut path }: Directory,
inline: Inline,
inner_span: Span,
span: Span, // The span to blame on errors.
) -> Directory {
if let Some(filename) = sess.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());
match inline {
Inline::Yes => {
if let Some(filename) = sess.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());
}
}
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.
if let Ok(mp) = submod_path(sess, id, span, &attrs, ownership, &path) {
ownership = mp.ownership;
}

// Extract the directory path for submodules of the module.
path = match sess.source_map().span_to_unmapped_path(inner_span) {
FileName::Real(name) => name.into_local_path(),
other => PathBuf::from(other.to_string()),
};
path.pop();
}
path.push(&*id.as_str());
}

Directory { ownership, path }
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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() {}
3 changes: 3 additions & 0 deletions src/test/ui/conditional-compilation/module_with_cfg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// ignore-test

#![cfg_attr(all(), cfg(FALSE))]
17 changes: 17 additions & 0 deletions src/test/ui/proc-macro/inner-attr-non-inline-mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// compile-flags: -Z span-debug
// error-pattern:custom inner attributes are unstable
// error-pattern:inner macro attributes are unstable
// 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() {}
39 changes: 39 additions & 0 deletions src/test/ui/proc-macro/inner-attr-non-inline-mod.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
error[E0658]: custom inner attributes are unstable
--> $DIR/module_with_attrs.rs:3:4
|
LL | #![rustfmt::skip]
| ^^^^^^^^^^^^^
|
= 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]: 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:13: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:13: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: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0658`.
76 changes: 76 additions & 0 deletions src/test/ui/proc-macro/inner-attr-non-inline-mod.stdout
Original file line number Diff line number Diff line change
@@ -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:13:1: 13:23 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "deny",
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "unused_attributes",
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
],
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
],
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
Ident {
ident: "mod",
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
Ident {
ident: "module_with_attrs",
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Punct {
ch: '#',
spacing: Joint,
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
Punct {
ch: '!',
spacing: Alone,
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "rustfmt",
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
Punct {
ch: ':',
spacing: Joint,
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
Punct {
ch: ':',
spacing: Alone,
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
Ident {
ident: "skip",
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
],
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
],
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
},
]
4 changes: 4 additions & 0 deletions src/test/ui/proc-macro/module_with_attrs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// ignore-test

#![rustfmt::skip]
#![print_attr]

0 comments on commit df78eea

Please sign in to comment.