about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2018-04-28 21:56:38 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2018-05-07 12:44:03 +0200
commit3ba7c00f94cd4ba046777a3cdbcb5fad17c1f6cf (patch)
treefb36c7df2c353fa839e43420d788b9581921c745
parentff65726ebf1d7d732e24175a41381e53f39ee892 (diff)
downloadrust-3ba7c00f94cd4ba046777a3cdbcb5fad17c1f6cf.tar.gz
rust-3ba7c00f94cd4ba046777a3cdbcb5fad17c1f6cf.zip
Prevent infinite recursion of modules
-rw-r--r--src/librustdoc/clean/inline.rs16
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/test/rustdoc/auxiliary/mod-stackoverflow.rs21
-rw-r--r--src/test/rustdoc/mod-stackoverflow.rs16
4 files changed, 47 insertions, 9 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 23e0c2625ee..a8f4848bf89 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -38,7 +38,7 @@ use super::Clean;
 ///
 /// The returned value is `None` if the definition could not be inlined,
 /// and `Some` of a vector of items if it was successfully expanded.
-pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name)
+pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHashSet<DefId>)
                   -> Option<Vec<clean::Item>> {
     if def == Def::Err { return None }
     let did = def.def_id();
@@ -87,7 +87,7 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name)
         Def::StructCtor(..) => return Some(Vec::new()),
         Def::Mod(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Module);
-            clean::ModuleItem(build_module(cx, did))
+            clean::ModuleItem(build_module(cx, did, visited))
         }
         Def::Static(did, mtbl) => {
             record_extern_fqn(cx, did, clean::TypeKind::Static);
@@ -385,24 +385,24 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
     });
 }
 
-fn build_module(cx: &DocContext, did: DefId) -> clean::Module {
+fn build_module(cx: &DocContext, did: DefId, visited: &mut FxHashSet<DefId>) -> clean::Module {
     let mut items = Vec::new();
-    fill_in(cx, did, &mut items);
+    fill_in(cx, did, &mut items, visited);
     return clean::Module {
         items,
         is_crate: false,
     };
 
-    fn fill_in(cx: &DocContext, did: DefId, items: &mut Vec<clean::Item>) {
+    fn fill_in(cx: &DocContext, did: DefId, items: &mut Vec<clean::Item>,
+               visited: &mut FxHashSet<DefId>) {
         // If we're re-exporting a re-export it may actually re-export something in
         // two namespaces, so the target may be listed twice. Make sure we only
         // visit each node at most once.
-        let mut visited = FxHashSet();
         for &item in cx.tcx.item_children(did).iter() {
             let def_id = item.def.def_id();
             if item.vis == ty::Visibility::Public {
-                if !visited.insert(def_id) { continue }
-                if let Some(i) = try_inline(cx, item.def, item.ident.name) {
+                if did == def_id || !visited.insert(def_id) { continue }
+                if let Some(i) = try_inline(cx, item.def, item.ident.name, visited) {
                     items.extend(i)
                 }
             }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 6623d5ab3c2..a7d32664f13 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -3673,7 +3673,8 @@ impl Clean<Vec<Item>> for doctree::Import {
         } else {
             let name = self.name;
             if !denied {
-                if let Some(items) = inline::try_inline(cx, path.def, name) {
+                let mut visited = FxHashSet();
+                if let Some(items) = inline::try_inline(cx, path.def, name, &mut visited) {
                     return items;
                 }
             }
diff --git a/src/test/rustdoc/auxiliary/mod-stackoverflow.rs b/src/test/rustdoc/auxiliary/mod-stackoverflow.rs
new file mode 100644
index 00000000000..f03593dbee6
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/mod-stackoverflow.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 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.
+
+// compile-flags: -Cmetadata=aux
+
+pub mod tree {
+    pub use tree;
+}
+
+pub mod tree2 {
+    pub mod prelude {
+        pub use tree2;
+    }
+}
diff --git a/src/test/rustdoc/mod-stackoverflow.rs b/src/test/rustdoc/mod-stackoverflow.rs
new file mode 100644
index 00000000000..1e2f6dbe780
--- /dev/null
+++ b/src/test/rustdoc/mod-stackoverflow.rs
@@ -0,0 +1,16 @@
+// Copyright 2018 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.
+
+// aux-build:mod-stackoverflow.rs
+// ignore-cross-compile
+
+extern crate mod_stackoverflow;
+pub use mod_stackoverflow::tree;
+pub use mod_stackoverflow::tree2;