about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorTaylor Cramer <cramertj@google.com>2017-11-27 18:14:24 -0800
committerTaylor Cramer <cramertj@google.com>2017-12-19 14:58:51 -0800
commit07f51fb8684e1ea0a3859234d360814093d891bd (patch)
tree2ba4570ab672999453ebbf0d15610392a086d044 /src/libsyntax/parse
parentb39c4bc12358078f77ddd01288b24252f757f37d (diff)
downloadrust-07f51fb8684e1ea0a3859234d360814093d891bd.tar.gz
rust-07f51fb8684e1ea0a3859234d360814093d891bd.zip
Implement non-mod.rs mod statements
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/lexer/mod.rs1
-rw-r--r--src/libsyntax/parse/mod.rs9
-rw-r--r--src/libsyntax/parse/parser.rs132
3 files changed, 99 insertions, 43 deletions
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 1e84fb98a66..9828995362a 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -1754,6 +1754,7 @@ mod tests {
             included_mod_stack: RefCell::new(Vec::new()),
             code_map: cm,
             missing_fragment_specifiers: RefCell::new(HashSet::new()),
+            non_modrs_mods: RefCell::new(vec![]),
         }
     }
 
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 4d435665d3c..89a54989f96 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -47,6 +47,9 @@ pub struct ParseSess {
     pub unstable_features: UnstableFeatures,
     pub config: CrateConfig,
     pub missing_fragment_specifiers: RefCell<HashSet<Span>>,
+    // Spans where a `mod foo;` statement was included in a non-mod.rs file.
+    // These are used to issue errors if the non_modrs_mods feature is not enabled.
+    pub non_modrs_mods: RefCell<Vec<(ast::Ident, Span)>>,
     /// Used to determine and report recursive mod inclusions
     included_mod_stack: RefCell<Vec<PathBuf>>,
     code_map: Rc<CodeMap>,
@@ -70,6 +73,7 @@ impl ParseSess {
             missing_fragment_specifiers: RefCell::new(HashSet::new()),
             included_mod_stack: RefCell::new(vec![]),
             code_map,
+            non_modrs_mods: RefCell::new(vec![]),
         }
     }
 
@@ -86,7 +90,10 @@ pub struct Directory {
 
 #[derive(Copy, Clone)]
 pub enum DirectoryOwnership {
-    Owned,
+    Owned {
+        // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`
+        relative: Option<ast::Ident>,
+    },
     UnownedViaBlock,
     UnownedViaMod(bool /* legacy warnings? */),
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c3dd17e8775..d6f09cd85d7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -514,7 +514,10 @@ impl<'a> Parser<'a> {
             restrictions: Restrictions::empty(),
             obsolete_set: HashSet::new(),
             recurse_into_file_modules,
-            directory: Directory { path: PathBuf::new(), ownership: DirectoryOwnership::Owned },
+            directory: Directory {
+                path: PathBuf::new(),
+                ownership: DirectoryOwnership::Owned { relative: None }
+            },
             root_module_name: None,
             expected_tokens: Vec::new(),
             token_cursor: TokenCursor {
@@ -5731,7 +5734,7 @@ impl<'a> Parser<'a> {
     fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
         if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") {
             self.directory.path.push(&path.as_str());
-            self.directory.ownership = DirectoryOwnership::Owned;
+            self.directory.ownership = DirectoryOwnership::Owned { relative: None };
         } else {
             self.directory.path.push(&id.name.as_str());
         }
@@ -5742,10 +5745,28 @@ impl<'a> Parser<'a> {
     }
 
     /// Returns either a path to a module, or .
-    pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -> ModulePath {
+    pub fn default_submod_path(
+        id: ast::Ident,
+        relative: Option<ast::Ident>,
+        dir_path: &Path,
+        codemap: &CodeMap) -> ModulePath
+    {
+        // If we're in a foo.rs file instead of a mod.rs file,
+        // we need to look for submodules in
+        // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
+        // `./<id>.rs` and `./<id>/mod.rs`.
+        let relative_prefix_string;
+        let relative_prefix = if let Some(ident) = relative {
+            relative_prefix_string = format!("{}{}", ident.name.as_str(), path::MAIN_SEPARATOR);
+            &relative_prefix_string
+        } else {
+            ""
+        };
+
         let mod_name = id.to_string();
-        let default_path_str = format!("{}.rs", mod_name);
-        let secondary_path_str = format!("{}{}mod.rs", mod_name, path::MAIN_SEPARATOR);
+        let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
+        let secondary_path_str = format!("{}{}{}mod.rs",
+                                         relative_prefix, mod_name, path::MAIN_SEPARATOR);
         let default_path = dir_path.join(&default_path_str);
         let secondary_path = dir_path.join(&secondary_path_str);
         let default_exists = codemap.file_exists(&default_path);
@@ -5754,12 +5775,16 @@ impl<'a> Parser<'a> {
         let result = match (default_exists, secondary_exists) {
             (true, false) => Ok(ModulePathSuccess {
                 path: default_path,
-                directory_ownership: DirectoryOwnership::UnownedViaMod(false),
+                directory_ownership: DirectoryOwnership::Owned {
+                    relative: Some(id),
+                },
                 warn: false,
             }),
             (false, true) => Ok(ModulePathSuccess {
                 path: secondary_path,
-                directory_ownership: DirectoryOwnership::Owned,
+                directory_ownership: DirectoryOwnership::Owned {
+                    relative: None,
+                },
                 warn: false,
             }),
             (false, false) => Err(Error::FileNotFoundForModule {
@@ -5790,7 +5815,10 @@ impl<'a> Parser<'a> {
         if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
             return Ok(ModulePathSuccess {
                 directory_ownership: match path.file_name().and_then(|s| s.to_str()) {
-                    Some("mod.rs") => DirectoryOwnership::Owned,
+                    Some("mod.rs") => DirectoryOwnership::Owned { relative: None },
+                    Some(_) => {
+                        DirectoryOwnership::Owned { relative: Some(id) }
+                    }
                     _ => DirectoryOwnership::UnownedViaMod(true),
                 },
                 path,
@@ -5798,49 +5826,69 @@ impl<'a> Parser<'a> {
             });
         }
 
-        let paths = Parser::default_submod_path(id, &self.directory.path, self.sess.codemap());
+        let relative = match self.directory.ownership {
+            DirectoryOwnership::Owned { relative } => {
+                // Push the usage onto the list of non-mod.rs mod uses.
+                // This is used later for feature-gate error reporting.
+                if let Some(cur_file_ident) = relative {
+                    self.sess
+                        .non_modrs_mods.borrow_mut()
+                        .push((cur_file_ident, id_sp));
+                }
+                relative
+            },
+            DirectoryOwnership::UnownedViaBlock |
+            DirectoryOwnership::UnownedViaMod(_) => None,
+        };
+        let paths = Parser::default_submod_path(
+                        id, relative, &self.directory.path, self.sess.codemap());
 
-        if let DirectoryOwnership::UnownedViaBlock = self.directory.ownership {
-            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);
-            }
-            Err(err)
-        } else if let DirectoryOwnership::UnownedViaMod(warn) = self.directory.ownership {
-            if warn {
-                if let Ok(result) = paths.result {
-                    return Ok(ModulePathSuccess { warn: true, ..result });
+        match self.directory.ownership {
+            DirectoryOwnership::Owned { .. } => {
+                paths.result.map_err(|err| self.span_fatal_err(id_sp, err))
+            },
+            DirectoryOwnership::UnownedViaBlock => {
+                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);
                 }
+                Err(err)
             }
-            let mut err = self.diagnostic().struct_span_err(id_sp,
-                "cannot declare a new module at this location");
-            if id_sp != syntax_pos::DUMMY_SP {
-                let src_path = self.sess.codemap().span_to_filename(id_sp);
-                if let FileName::Real(src_path) = src_path {
-                    if let Some(stem) = src_path.file_stem() {
-                        let mut dest_path = src_path.clone();
-                        dest_path.set_file_name(stem);
-                        dest_path.push("mod.rs");
-                        err.span_note(id_sp,
+            DirectoryOwnership::UnownedViaMod(warn) => {
+                if warn {
+                    if let Ok(result) = paths.result {
+                        return Ok(ModulePathSuccess { warn: true, ..result });
+                    }
+                }
+                let mut err = self.diagnostic().struct_span_err(id_sp,
+                    "cannot declare a new module at this location");
+                if id_sp != syntax_pos::DUMMY_SP {
+                    let src_path = self.sess.codemap().span_to_filename(id_sp);
+                    if let FileName::Real(src_path) = src_path {
+                        if let Some(stem) = src_path.file_stem() {
+                            let mut dest_path = src_path.clone();
+                            dest_path.set_file_name(stem);
+                            dest_path.push("mod.rs");
+                            err.span_note(id_sp,
                                     &format!("maybe move this module `{}` to its own \
                                                 directory via `{}`", src_path.display(),
                                             dest_path.display()));
+                        }
                     }
                 }
+                if paths.path_exists {
+                    err.span_note(id_sp,
+                                  &format!("... or maybe `use` the module `{}` instead \
+                                            of possibly redeclaring it",
+                                           paths.name));
+                }
+                Err(err)
             }
-            if paths.path_exists {
-                err.span_note(id_sp,
-                              &format!("... or maybe `use` the module `{}` instead \
-                                        of possibly redeclaring it",
-                                       paths.name));
-            }
-            Err(err)
-        } else {
-            paths.result.map_err(|err| self.span_fatal_err(id_sp, err))
         }
     }