Skip to content

Commit df78eea

Browse files
committed
expand: Resolve and expand inner attributes on out-of-line modules
1 parent fe1bf8e commit df78eea

File tree

9 files changed

+226
-32
lines changed

9 files changed

+226
-32
lines changed

compiler/rustc_ast/src/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2299,7 +2299,7 @@ impl FnRetTy {
22992299
}
23002300
}
23012301

2302-
#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
2302+
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
23032303
pub enum Inline {
23042304
Yes,
23052305
No,

compiler/rustc_expand/src/expand.rs

+41-15
Original file line numberDiff line numberDiff line change
@@ -1278,16 +1278,24 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
12781278
let pushed = &mut false; // Record `parse_external_mod` pushing so we can pop.
12791279
let dir = Directory { ownership: orig_ownership, path: module.directory };
12801280
let Directory { ownership, path } = match mod_kind {
1281-
ModKind::Loaded(_, Inline::Yes, _) => {
1282-
// Inline `mod foo { ... }`, but we still need to push directories.
1281+
ModKind::Loaded(_, inline, inner_span) => {
1282+
// Inline `mod foo { ... }` or previously loaded `mod foo;`,
1283+
// we still need to push directories.
1284+
let dir = push_directory(
1285+
&self.cx.sess,
1286+
ident,
1287+
&attrs,
1288+
dir,
1289+
*inline,
1290+
*inner_span,
1291+
span,
1292+
);
12831293
item.attrs = attrs;
1284-
push_directory(&self.cx.sess, ident, &item.attrs, dir)
1285-
}
1286-
ModKind::Loaded(_, Inline::No, _) => {
1287-
panic!("`mod` item is loaded from a file for the second time")
1294+
dir
12881295
}
12891296
ModKind::Unloaded => {
12901297
// We have an outline `mod foo;` so we need to parse the file.
1298+
let old_attrs_len = attrs.len();
12911299
let (items, inner_span, dir) =
12921300
parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);
12931301

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

13001308
*mod_kind = ModKind::Loaded(krate.items, Inline::No, inner_span);
13011309
item.attrs = krate.attrs;
1302-
// File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
1303-
item = match self.configure(item) {
1304-
Some(node) => node,
1305-
None => {
1306-
if *pushed {
1307-
sess.included_mod_stack.borrow_mut().pop();
1308-
}
1309-
return Default::default();
1310+
1311+
if item.attrs.len() > old_attrs_len {
1312+
// If we loaded an out-of-line module and added some inner attributes,
1313+
// then we need to re-configure it and re-collect attributes for
1314+
// resolution and expansion.
1315+
let file_path = if *pushed {
1316+
sess.included_mod_stack.borrow_mut().pop()
1317+
} else {
1318+
None
1319+
};
1320+
1321+
item = configure!(self, item);
1322+
1323+
if let Some(attr) = self.take_first_attr(&mut item) {
1324+
return self
1325+
.collect_attr(
1326+
attr,
1327+
Annotatable::Item(item),
1328+
AstFragmentKind::Items,
1329+
)
1330+
.make_items();
13101331
}
1311-
};
1332+
1333+
if let Some(file_path) = file_path {
1334+
sess.included_mod_stack.borrow_mut().push(file_path);
1335+
}
1336+
}
1337+
13121338
dir
13131339
}
13141340
};

compiler/rustc_expand/src/module.rs

+38-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_ast::ptr::P;
2-
use rustc_ast::{token, Attribute, Item};
2+
use rustc_ast::{token, Attribute, Inline, Item};
33
use rustc_errors::{struct_span_err, PResult};
44
use rustc_parse::new_parser_from_file;
55
use rustc_session::parse::ParseSess;
@@ -103,25 +103,47 @@ crate fn push_directory(
103103
id: Ident,
104104
attrs: &[Attribute],
105105
Directory { mut ownership, mut path }: Directory,
106+
inline: Inline,
107+
inner_span: Span,
108+
span: Span, // The span to blame on errors.
106109
) -> Directory {
107-
if let Some(filename) = sess.first_attr_value_str_by_name(attrs, sym::path) {
108-
path.push(&*filename.as_str());
109-
ownership = DirectoryOwnership::Owned { relative: None };
110-
} else {
111-
// We have to push on the current module name in the case of relative
112-
// paths in order to ensure that any additional module paths from inline
113-
// `mod x { ... }` come after the relative extension.
114-
//
115-
// For example, a `mod z { ... }` inside `x/y.rs` should set the current
116-
// directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
117-
if let DirectoryOwnership::Owned { relative } = &mut ownership {
118-
if let Some(ident) = relative.take() {
119-
// Remove the relative offset.
120-
path.push(&*ident.as_str());
110+
match inline {
111+
Inline::Yes => {
112+
if let Some(filename) = sess.first_attr_value_str_by_name(attrs, sym::path) {
113+
path.push(&*filename.as_str());
114+
ownership = DirectoryOwnership::Owned { relative: None };
115+
} else {
116+
// We have to push on the current module name in the case of relative
117+
// paths in order to ensure that any additional module paths from inline
118+
// `mod x { ... }` come after the relative extension.
119+
//
120+
// For example, a `mod z { ... }` inside `x/y.rs` should set the current
121+
// directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
122+
if let DirectoryOwnership::Owned { relative } = &mut ownership {
123+
if let Some(ident) = relative.take() {
124+
// Remove the relative offset.
125+
path.push(&*ident.as_str());
126+
}
127+
}
128+
path.push(&*id.as_str());
129+
}
130+
}
131+
Inline::No => {
132+
// FIXME: This is a subset of `parse_external_mod` without actual parsing,
133+
// check whether the logic for unloaded, loaded and inline modules can be unified.
134+
if let Ok(mp) = submod_path(sess, id, span, &attrs, ownership, &path) {
135+
ownership = mp.ownership;
121136
}
137+
138+
// Extract the directory path for submodules of the module.
139+
path = match sess.source_map().span_to_unmapped_path(inner_span) {
140+
FileName::Real(name) => name.into_local_path(),
141+
other => PathBuf::from(other.to_string()),
142+
};
143+
path.pop();
122144
}
123-
path.push(&*id.as_str());
124145
}
146+
125147
Directory { ownership, path }
126148
}
127149

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// check-pass
2+
3+
mod module_with_cfg;
4+
5+
mod module_with_cfg {} // Ok, the module above is configured away by an inner attribute.
6+
7+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// ignore-test
2+
3+
#![cfg_attr(all(), cfg(FALSE))]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// compile-flags: -Z span-debug
2+
// error-pattern:custom inner attributes are unstable
3+
// error-pattern:inner macro attributes are unstable
4+
// aux-build:test-macros.rs
5+
6+
#![no_std] // Don't load unnecessary hygiene information from std
7+
extern crate std;
8+
9+
#[macro_use]
10+
extern crate test_macros;
11+
12+
#[deny(unused_attributes)]
13+
mod module_with_attrs;
14+
//~^ ERROR non-inline modules in proc macro input are unstable
15+
//~| ERROR custom inner attributes are unstable
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error[E0658]: custom inner attributes are unstable
2+
--> $DIR/module_with_attrs.rs:3:4
3+
|
4+
LL | #![rustfmt::skip]
5+
| ^^^^^^^^^^^^^
6+
|
7+
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
8+
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
9+
10+
error[E0658]: inner macro attributes are unstable
11+
--> $DIR/module_with_attrs.rs:4:4
12+
|
13+
LL | #![print_attr]
14+
| ^^^^^^^^^^
15+
|
16+
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
17+
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
18+
19+
error[E0658]: non-inline modules in proc macro input are unstable
20+
--> $DIR/inner-attr-non-inline-mod.rs:13:1
21+
|
22+
LL | mod module_with_attrs;
23+
| ^^^^^^^^^^^^^^^^^^^^^^
24+
|
25+
= note: see issue #54727 <https://github.com/rust-lang/rust/issues/54727> for more information
26+
= help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
27+
28+
error[E0658]: custom inner attributes are unstable
29+
--> $DIR/inner-attr-non-inline-mod.rs:13:1
30+
|
31+
LL | mod module_with_attrs;
32+
| ^^^^^^^^^^^^^^^^^^^^^^
33+
|
34+
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
35+
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
36+
37+
error: aborting due to 4 previous errors
38+
39+
For more information about this error, try `rustc --explain E0658`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
PRINT-ATTR INPUT (DISPLAY): #[deny(unused_attributes)] mod module_with_attrs { # ! [rustfmt :: skip] }
2+
PRINT-ATTR INPUT (DEBUG): TokenStream [
3+
Punct {
4+
ch: '#',
5+
spacing: Alone,
6+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
7+
},
8+
Group {
9+
delimiter: Bracket,
10+
stream: TokenStream [
11+
Ident {
12+
ident: "deny",
13+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
14+
},
15+
Group {
16+
delimiter: Parenthesis,
17+
stream: TokenStream [
18+
Ident {
19+
ident: "unused_attributes",
20+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
21+
},
22+
],
23+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
24+
},
25+
],
26+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
27+
},
28+
Ident {
29+
ident: "mod",
30+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
31+
},
32+
Ident {
33+
ident: "module_with_attrs",
34+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
35+
},
36+
Group {
37+
delimiter: Brace,
38+
stream: TokenStream [
39+
Punct {
40+
ch: '#',
41+
spacing: Joint,
42+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
43+
},
44+
Punct {
45+
ch: '!',
46+
spacing: Alone,
47+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
48+
},
49+
Group {
50+
delimiter: Bracket,
51+
stream: TokenStream [
52+
Ident {
53+
ident: "rustfmt",
54+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
55+
},
56+
Punct {
57+
ch: ':',
58+
spacing: Joint,
59+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
60+
},
61+
Punct {
62+
ch: ':',
63+
spacing: Alone,
64+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
65+
},
66+
Ident {
67+
ident: "skip",
68+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
69+
},
70+
],
71+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
72+
},
73+
],
74+
span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0),
75+
},
76+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// ignore-test
2+
3+
#![rustfmt::skip]
4+
#![print_attr]

0 commit comments

Comments
 (0)