Rollup merge of #36789 - jseyfried:non_inline_mod_in_block, r=nikomatsakis
Allow more non-inline modules in blocks
Currently, non-inline modules without a `#[path]` attribute are not allowed in blocks.
This PR allows non-inline modules that have an ancestor module with a `#[path]` attribute, provided there is not a nearer ancestor block.
For example,
```rust
fn main() {
#[path = "..."] mod foo {
mod bar; //< allowed by this PR
fn f() {
mod bar; //< still an error
}
}
}
```
Fixes #36772.
r? @nikomatsakis
This commit is contained in:
commit
f1ea5cc273
5 changed files with 40 additions and 18 deletions
|
|
@ -557,7 +557,9 @@ pub struct ExpansionData {
|
|||
pub depth: usize,
|
||||
pub backtrace: ExpnId,
|
||||
pub module: Rc<ModuleData>,
|
||||
pub in_block: bool,
|
||||
|
||||
// True if non-inline modules without a `#[path]` are forbidden at the root of this expansion.
|
||||
pub no_noninline_mod: bool,
|
||||
}
|
||||
|
||||
/// One of these is made during expansion and incrementally updated as we go;
|
||||
|
|
@ -590,7 +592,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
depth: 0,
|
||||
backtrace: NO_EXPANSION,
|
||||
module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
|
||||
in_block: false,
|
||||
no_noninline_mod: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -667,9 +667,9 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
|||
}
|
||||
|
||||
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
|
||||
let orig_in_block = mem::replace(&mut self.cx.current_expansion.in_block, true);
|
||||
let no_noninline_mod = mem::replace(&mut self.cx.current_expansion.no_noninline_mod, true);
|
||||
let result = noop_fold_block(block, self);
|
||||
self.cx.current_expansion.in_block = orig_in_block;
|
||||
self.cx.current_expansion.no_noninline_mod = no_noninline_mod;
|
||||
result
|
||||
}
|
||||
|
||||
|
|
@ -708,6 +708,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
|||
return noop_fold_item(item, self);
|
||||
}
|
||||
|
||||
let orig_no_noninline_mod = self.cx.current_expansion.no_noninline_mod;
|
||||
let mut module = (*self.cx.current_expansion.module).clone();
|
||||
module.mod_path.push(item.ident);
|
||||
|
||||
|
|
@ -717,11 +718,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
|||
let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP;
|
||||
|
||||
if inline_module {
|
||||
module.directory.push(&*{
|
||||
::attr::first_attr_value_str_by_name(&item.attrs, "path")
|
||||
.unwrap_or(item.ident.name.as_str())
|
||||
});
|
||||
if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
|
||||
self.cx.current_expansion.no_noninline_mod = false;
|
||||
module.directory.push(&*path);
|
||||
} else {
|
||||
module.directory.push(&*item.ident.name.as_str());
|
||||
}
|
||||
} else {
|
||||
self.cx.current_expansion.no_noninline_mod = false;
|
||||
module.directory =
|
||||
PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
|
||||
module.directory.pop();
|
||||
|
|
@ -731,6 +735,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
|||
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
|
||||
let result = noop_fold_item(item, self);
|
||||
self.cx.current_expansion.module = orig_module;
|
||||
self.cx.current_expansion.no_noninline_mod = orig_no_noninline_mod;
|
||||
return result;
|
||||
}
|
||||
// Ensure that test functions are accessible from the test harness.
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
|||
rhs);
|
||||
let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
|
||||
p.directory = cx.current_expansion.module.directory.clone();
|
||||
p.restrictions = match cx.current_expansion.in_block {
|
||||
p.restrictions = match cx.current_expansion.no_noninline_mod {
|
||||
true => Restrictions::NO_NONINLINE_MOD,
|
||||
false => Restrictions::empty(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5274,23 +5274,27 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
} else {
|
||||
let directory = self.directory.clone();
|
||||
self.push_directory(id, &outer_attrs);
|
||||
let restrictions = self.push_directory(id, &outer_attrs);
|
||||
self.expect(&token::OpenDelim(token::Brace))?;
|
||||
let mod_inner_lo = self.span.lo;
|
||||
let attrs = self.parse_inner_attributes()?;
|
||||
let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
|
||||
let m = self.with_res(restrictions, |this| {
|
||||
this.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)
|
||||
})?;
|
||||
self.directory = directory;
|
||||
Ok((id, ItemKind::Mod(m), Some(attrs)))
|
||||
}
|
||||
}
|
||||
|
||||
fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
|
||||
let default_path = self.id_to_interned_str(id);
|
||||
let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") {
|
||||
Some(d) => d,
|
||||
None => default_path,
|
||||
};
|
||||
self.directory.push(&*file_path)
|
||||
fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) -> Restrictions {
|
||||
if let Some(path) = ::attr::first_attr_value_str_by_name(attrs, "path") {
|
||||
self.directory.push(&*path);
|
||||
self.restrictions - Restrictions::NO_NONINLINE_MOD
|
||||
} else {
|
||||
let default_path = self.id_to_interned_str(id);
|
||||
self.directory.push(&*default_path);
|
||||
self.restrictions
|
||||
}
|
||||
}
|
||||
|
||||
pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option<PathBuf> {
|
||||
|
|
|
|||
|
|
@ -17,4 +17,15 @@ mod mod_dir_simple {
|
|||
|
||||
pub fn main() {
|
||||
assert_eq!(mod_dir_simple::syrup::foo(), 10);
|
||||
|
||||
#[path = "auxiliary"]
|
||||
mod foo {
|
||||
mod two_macros;
|
||||
}
|
||||
|
||||
#[path = "auxiliary"]
|
||||
mod bar {
|
||||
macro_rules! m { () => { mod two_macros; } }
|
||||
m!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue