Change:
These are all legal, and somewhat strange, since they're not really following the file-system analogy that modules are typically explained with. I expect this behaviour is just whatever happens to fall out of the current implementation strategy, so let's make a more explicit decision one way or another. As one might expect, each of these is a distinct instance of (which can be verified by placing in : the compiler will greet you 3 times). Noticed in .
This seems weird to me. I think the intention is that the out-of-line syntax () should only work at the top-level.
I'd vote for allowing non-inline modules only at the top-level, to retain a clear mapping to the file system.
(Or nested inside modules.)
triage: P-medium Backwards incompatible, but ... kind of a curiousity.
Found one more mod aliasing scenario. It involves several files, and is semi officially allowed by the reference. The layout The files The copy module will be aliased. The problem is that although and are not directory owners, their inner modules are.
Upon reflecting more about this, I think that there are two questions here. should non inline modules be allowed (syntactically) inside items? should module aliasing (the same file representing two modules in the crate) be allowed? The questions are independent because you can use attribute to create module aliasing manually. I would prefer if the answer to the second question is not. I'm contributing to the Rust plugin for IntelliJ IDEA, and one of the tasks there is mapping files to modules (for example, to go to the parent module). I would much prefer just to highlight module aliasing as an error, rather then to deal with non one-to-one mapping between files and modules. As a side note, if a user does want aliasing for some reason, she can always use symbolic link for the same effect.
I tend to believe it is fine to have aliasing if you write the yourself (you asked for it...), and that it would be ok to put a non-inline module inside an non-module, if you specify the path yourself, but that we should error out otherwise. However, there has definitely been confusion in the past about the role of as a declaration and not a , and disallowing aliasing would prevent that confusion from leading to incorrect trees. however is disconcerting, and suggests that perhaps the code has a slightly different model in mind than I do in my head. :) That is, I strongly expect to (by default) be found at . What happens if you don't have the , but just place in ?
It is forbidden because is not a directory owner.
Just in case here is a repository with the example: I don't see a reason to allow user to shoot himself in the leg. What if you accidentelly have identical attributes (copy paste problem)? My main concern though is that non injective file to module mapping may complicate the implementation of some rust tools. Here is another hypothetical example of this. Suppose you implement incremental compilation for rustc. You will need a mapping from files to modules. If mod aliasing is alowed, then you will need a multimapping. So you end up with more complex code which is used only in a tiny fraction of projects and because of this probably contains some bugs.
Ah, I see. So it seems to me that the problem is that should not be allowed in contexts where would be illegal. In other words, an inline module should only be considered a "directory owner" if it is located within a directory owner. A compromise might be Yet Another Lint Warning. ;) I agree with you about preventing people from shooting themselves in the leg, but I guess I think people don't use lightly or frequently, so this seems unlikely to be a major source of confusion.
I totally agree that this curiosity is insignificant for users. But I still worry more about the implementation side of the issue, and a lint warning does not help here.

Discussion:
macro_rules! supported_targets { ( $(($triple:expr, $module:ident)),+ ) => ( <ins> $(mod $module;)* </ins> /// List of supported targets pub const TARGETS: &'static [&'static str] = &[$($triple),*]; // this would use a match if stringify! were allowed in pattern position fn load_specific(target: &str) -> Option<Target> { <del> $(mod $module;)* </del> let target = target.replace("-", "_"); if false { } $(

flags Restrictions: u8 { const RESTRICTION_STMT_EXPR         = 1 << 0, const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1, <ins> const NO_NONINLINE_MOD  = 1 << 2, </ins> } }

/// Evaluate the closure with restrictions in place. /// /// After the closure is evaluated, restrictions are reset. <del> pub fn with_res<F>(&mut self, r: Restrictions, f: F) -> PResult<'a, P<Expr>> where F: FnOnce(&mut Self) -> PResult<'a,  P<Expr>> </del> <ins> pub fn with_res<F, T>(&mut self, r: Restrictions, f: F) -> T where F: FnOnce(&mut Self) -> T </ins> { let old = self.restrictions; self.restrictions = r;

} } else { // FIXME: Bad copy of attrs <del> match try!(self.parse_item_(attrs.clone(), false, true)) { </del> <ins> let restrictions = self.restrictions | Restrictions::NO_NONINLINE_MOD; match try!(self.with_res(restrictions, |this| this.parse_item_(attrs.clone(), false, true))) { </ins> Some(i) => { let hi = i.span.hi; let decl = P(spanned(lo, hi, DeclKind::Item(i)));

self.push_mod_path(id, outer_attrs); try!(self.expect(&token::OpenDelim(token::Brace))); let mod_inner_lo = self.span.lo; <del> let old_owns_directory = self.owns_directory; self.owns_directory = true; </del> let attrs = try!(self.parse_inner_attributes()); let m = try!(self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)); <del> self.owns_directory = old_owns_directory; </del> self.pop_mod_path(); Ok((id, ItemKind::Mod(m), Some(attrs))) }

let paths = Parser::default_submod_path(id, &dir_path, self.sess.codemap()); <del> if !self.owns_directory { </del> <ins> if self.restrictions.contains(Restrictions::NO_NONINLINE_MOD) { let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute"; let mut err = self.diagnostic().struct_span_err(id_sp, msg); if paths.path_exists { let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", paths.name); err.span_note(id_sp, &msg); } return Err(err); } else if !self.owns_directory { </ins> let mut err = self.diagnostic().struct_span_err(id_sp, "cannot declare a new module at this location"); let this_module = match self.mod_path_stack.last() {

<ins> // Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. // Test that non-inline modules are not allowed inside blocks. fn main() { mod foo; //~ ERROR Cannot declare a non-inline module inside a block } </ins>