Skip to content

Commit 1c11ea3

Browse files
authored
Auto merge of #37602 - jseyfried:directory_ownership, r=nikomatsakis
parser: simplify directory ownership semantics This PR simplifies the semantics of "directory ownership". After this PR, - a non-inline module without a `#[path]` attribute (e.g. `mod foo;`) is allowed iff its parent module/block (whichever is nearer) is a directory owner, - an non-inline module is a directory owner iff its corresponding file is named `mod.rs` (c.f. [comment](#32401 (comment))), - a block is never a directory owner (c.f. #31534), and - an inline module is a directory owner iff either - its parent module/block is a directory owner (again, c.f. #31534), or - it has a `#[path]` attribute (c.f. #36789). These semantics differ from today's in three orthogonal ways: - `#[path = "foo.rs"] mod foo;` is no longer a directory owner. This is a [breaking-change]. - #36789 is generalized to apply to modules that are not directory owners in addition to blocks. - A macro-expanded non-inline module is only allowed where an ordinary non-inline module would be allowed. Today, we incorrectly allow macro-expanded non-inline modules in modules that are not directory owners (but not in blocks). This is a [breaking-change]. Fixes #32401. r? @nikomatsakis
2 parents 82d8833 + fa8c53b commit 1c11ea3

20 files changed

+199
-88
lines changed

src/librustc/lint/builtin.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ declare_lint! {
204204
"detects extra requirements in impls that were erroneously allowed"
205205
}
206206

207+
declare_lint! {
208+
pub LEGACY_DIRECTORY_OWNERSHIP,
209+
Warn,
210+
"non-inline, non-`#[path]` modules (e.g. `mod foo;`) were erroneously allowed in some files \
211+
not named `mod.rs`"
212+
}
213+
207214
/// Does nothing as a lint pass, but registers some `Lint`s
208215
/// which are used by other parts of the compiler.
209216
#[derive(Copy, Clone)]
@@ -242,7 +249,8 @@ impl LintPass for HardwiredLints {
242249
LIFETIME_UNDERSCORE,
243250
SAFE_EXTERN_STATICS,
244251
PATTERNS_IN_FNS_WITHOUT_BODY,
245-
EXTRA_REQUIREMENT_IN_IMPL
252+
EXTRA_REQUIREMENT_IN_IMPL,
253+
LEGACY_DIRECTORY_OWNERSHIP
246254
)
247255
}
248256
}

src/librustc_lint/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
232232
id: LintId::of(EXTRA_REQUIREMENT_IN_IMPL),
233233
reference: "issue #37166 <https://github.com/rust-lang/rust/issues/37166>",
234234
},
235+
FutureIncompatibleInfo {
236+
id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP),
237+
reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
238+
},
235239
]);
236240

237241
// Register renamed and removed lints

src/librustc_passes/ast_validation.rs

+7
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,13 @@ impl<'a> Visitor for AstValidator<'a> {
207207
ItemKind::Mod(_) => {
208208
// Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
209209
attr::first_attr_value_str_by_name(&item.attrs, "path");
210+
if let Some(attr) =
211+
item.attrs.iter().find(|attr| attr.name() == "warn_directory_ownership") {
212+
let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP;
213+
let msg = "cannot declare a new module at this location";
214+
self.session.add_lint(lint, item.id, item.span, msg.to_string());
215+
attr::mark_used(attr);
216+
}
210217
}
211218
ItemKind::Union(ref vdata, _) => {
212219
if !vdata.is_struct() {

src/libsyntax/ext/base.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use errors::DiagnosticBuilder;
1818
use ext::expand::{self, Expansion};
1919
use ext::hygiene::Mark;
2020
use fold::{self, Folder};
21-
use parse::{self, parser};
21+
use parse::{self, parser, DirectoryOwnership};
2222
use parse::token;
2323
use ptr::P;
2424
use symbol::Symbol;
@@ -568,9 +568,7 @@ pub struct ExpansionData {
568568
pub depth: usize,
569569
pub backtrace: ExpnId,
570570
pub module: Rc<ModuleData>,
571-
572-
// True if non-inline modules without a `#[path]` are forbidden at the root of this expansion.
573-
pub no_noninline_mod: bool,
571+
pub directory_ownership: DirectoryOwnership,
574572
}
575573

576574
/// One of these is made during expansion and incrementally updated as we go;
@@ -601,7 +599,7 @@ impl<'a> ExtCtxt<'a> {
601599
depth: 0,
602600
backtrace: NO_EXPANSION,
603601
module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
604-
no_noninline_mod: false,
602+
directory_ownership: DirectoryOwnership::Owned,
605603
},
606604
}
607605
}

src/libsyntax/ext/expand.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use ext::base::*;
2121
use feature_gate::{self, Features};
2222
use fold;
2323
use fold::*;
24-
use parse::{ParseSess, PResult, lexer};
24+
use parse::{ParseSess, DirectoryOwnership, PResult, lexer};
2525
use parse::parser::Parser;
2626
use parse::token;
2727
use print::pprust;
@@ -727,9 +727,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
727727
}
728728

729729
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
730-
let no_noninline_mod = mem::replace(&mut self.cx.current_expansion.no_noninline_mod, true);
730+
let old_directory_ownership = self.cx.current_expansion.directory_ownership;
731+
self.cx.current_expansion.directory_ownership = DirectoryOwnership::UnownedViaBlock;
731732
let result = noop_fold_block(block, self);
732-
self.cx.current_expansion.no_noninline_mod = no_noninline_mod;
733+
self.cx.current_expansion.directory_ownership = old_directory_ownership;
733734
result
734735
}
735736

@@ -768,7 +769,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
768769
return noop_fold_item(item, self);
769770
}
770771

771-
let orig_no_noninline_mod = self.cx.current_expansion.no_noninline_mod;
772+
let orig_directory_ownership = self.cx.current_expansion.directory_ownership;
772773
let mut module = (*self.cx.current_expansion.module).clone();
773774
module.mod_path.push(item.ident);
774775

@@ -779,23 +780,28 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
779780

780781
if inline_module {
781782
if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
782-
self.cx.current_expansion.no_noninline_mod = false;
783+
self.cx.current_expansion.directory_ownership = DirectoryOwnership::Owned;
783784
module.directory.push(&*path.as_str());
784785
} else {
785786
module.directory.push(&*item.ident.name.as_str());
786787
}
787788
} else {
788-
self.cx.current_expansion.no_noninline_mod = false;
789-
module.directory =
789+
let mut path =
790790
PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
791-
module.directory.pop();
791+
let directory_ownership = match path.file_name().unwrap().to_str() {
792+
Some("mod.rs") => DirectoryOwnership::Owned,
793+
_ => DirectoryOwnership::UnownedViaMod(false),
794+
};
795+
path.pop();
796+
module.directory = path;
797+
self.cx.current_expansion.directory_ownership = directory_ownership;
792798
}
793799

794800
let orig_module =
795801
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
796802
let result = noop_fold_item(item, self);
797803
self.cx.current_expansion.module = orig_module;
798-
self.cx.current_expansion.no_noninline_mod = orig_no_noninline_mod;
804+
self.cx.current_expansion.directory_ownership = orig_directory_ownership;
799805
return result;
800806
}
801807
// Ensure that test functions are accessible from the test harness.

src/libsyntax/ext/source_util.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use syntax_pos::{self, Pos, Span};
1313
use ext::base::*;
1414
use ext::base;
1515
use ext::build::AstBuilder;
16-
use parse::token;
16+
use parse::{token, DirectoryOwnership};
1717
use parse;
1818
use print::pprust;
1919
use ptr::P;
@@ -90,7 +90,8 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::T
9090
};
9191
// The file will be added to the code map by the parser
9292
let path = res_rel_file(cx, sp, Path::new(&file));
93-
let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, true, None, sp);
93+
let directory_ownership = DirectoryOwnership::Owned;
94+
let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, directory_ownership, None, sp);
9495

9596
struct ExpandResult<'a> {
9697
p: parse::parser::Parser<'a>,

src/libsyntax/ext/tt/macro_rules.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
1919
use ext::tt::macro_parser::{parse, parse_failure_msg};
2020
use parse::ParseSess;
2121
use parse::lexer::new_tt_reader;
22-
use parse::parser::{Parser, Restrictions};
22+
use parse::parser::Parser;
2323
use parse::token::{self, NtTT, Token};
2424
use parse::token::Token::*;
2525
use print;
@@ -117,11 +117,12 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
117117
let trncbr =
118118
new_tt_reader(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs);
119119
let mut p = Parser::new(cx.parse_sess(), Box::new(trncbr));
120-
p.directory = cx.current_expansion.module.directory.clone();
121-
p.restrictions = match cx.current_expansion.no_noninline_mod {
122-
true => Restrictions::NO_NONINLINE_MOD,
123-
false => Restrictions::empty(),
124-
};
120+
let module = &cx.current_expansion.module;
121+
p.directory.path = module.directory.clone();
122+
p.directory.ownership = cx.current_expansion.directory_ownership;
123+
p.root_module_name =
124+
module.mod_path.last().map(|id| (*id.name.as_str()).to_owned());
125+
125126
p.check_unknown_macro_variable();
126127
// Let the context choose how to interpret the result.
127128
// Weird, but useful for X-macros.

src/libsyntax/parse/mod.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,19 @@ impl ParseSess {
7676
}
7777
}
7878

79+
#[derive(Clone)]
80+
pub struct Directory {
81+
pub path: PathBuf,
82+
pub ownership: DirectoryOwnership,
83+
}
84+
85+
#[derive(Copy, Clone)]
86+
pub enum DirectoryOwnership {
87+
Owned,
88+
UnownedViaBlock,
89+
UnownedViaMod(bool /* legacy warnings? */),
90+
}
91+
7992
// a bunch of utility functions of the form parse_<thing>_from_<source>
8093
// where <thing> includes crate, expr, item, stmt, tts, and one that
8194
// uses a HOF to parse anything, and <source> includes file and
@@ -152,11 +165,11 @@ pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) -> Parser<'a>
152165
/// On an error, use the given span as the source of the problem.
153166
pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess,
154167
path: &Path,
155-
owns_directory: bool,
168+
directory_ownership: DirectoryOwnership,
156169
module_name: Option<String>,
157170
sp: Span) -> Parser<'a> {
158171
let mut p = filemap_to_parser(sess, file_to_filemap(sess, path, Some(sp)));
159-
p.owns_directory = owns_directory;
172+
p.directory.ownership = directory_ownership;
160173
p.root_module_name = module_name;
161174
p
162175
}

0 commit comments

Comments
 (0)