about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-06-17 09:48:10 +0000
committerbors <bors@rust-lang.org>2018-06-17 09:48:10 +0000
commit594b05dd9786c09c916745c1b1c281a3c54cdbd1 (patch)
tree2b277ef34c86f1d97de5494eb492218c26fa5c25
parentaec00f97e1cdcea2b079e209a7e759201ba6ca7c (diff)
parent903e2c8afe6907b8828202345f2677a8e14f78fa (diff)
downloadrust-594b05dd9786c09c916745c1b1c281a3c54cdbd1.tar.gz
rust-594b05dd9786c09c916745c1b1c281a3c54cdbd1.zip
Auto merge of #51425 - QuietMisdreavus:thats-def-a-namespace-there, r=petrochenkov
refactor: create multiple HIR items for imports

When lowering `use` statements into HIR, they get a `Def` of the thing they're pointing at. This is great for things that need to know what was just pulled into scope. However, this is a bit misleading, because a `use` statement can pull things from multiple namespaces if their names collide. This is a problem for rustdoc, because if there are a module and a function with the same name (for example) then it will only document the module import, because that's that the lowered `use` statement points to.

The current version of this PR does the following:

* Whenever the resolver comes across a `use` statement, it loads the definitions into a new `import_map` instead of the existing `def_map`. This keeps the resolutions per-namespace so that all the target definitions are available.
* When lowering `use` statements, it looks up the resolutions in the `import_map` and creates multiple `Item`s if there is more than one resolution.
* To ensure the `NodeId`s are properly tracked in the lowered module, they need to be created in the AST, and pulled out as needed if multiple resolutions are available.

Fixes https://github.com/rust-lang/rust/issues/34843
-rw-r--r--src/librustc/hir/def.rs72
-rw-r--r--src/librustc/hir/lowering.rs95
-rw-r--r--src/librustc_lint/unused.rs2
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs2
-rw-r--r--src/librustc_resolve/lib.rs51
-rw-r--r--src/librustc_resolve/resolve_imports.rs3
-rw-r--r--src/librustdoc/visit_ast.rs5
-rw-r--r--src/libsyntax/ast.rs9
-rw-r--r--src/libsyntax/ext/build.rs4
-rw-r--r--src/libsyntax/feature_gate.rs2
-rw-r--r--src/libsyntax/fold.rs5
-rw-r--r--src/libsyntax/parse/parser.rs2
-rw-r--r--src/libsyntax/print/pprust.rs2
-rw-r--r--src/libsyntax/test.rs4
-rw-r--r--src/libsyntax/visit.rs3
-rw-r--r--src/test/rustdoc/namespaces.rs26
16 files changed, 220 insertions, 67 deletions
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 0adbdbe9933..fd14be592be 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -16,6 +16,8 @@ use syntax_pos::Span;
 use hir;
 use ty;
 
+use self::Namespace::*;
+
 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum CtorKind {
     /// Constructor function automatically created by a tuple struct/variant.
@@ -116,6 +118,72 @@ impl PathResolution {
     }
 }
 
+/// Different kinds of symbols don't influence each other.
+///
+/// Therefore, they have a separate universe (namespace).
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum Namespace {
+    TypeNS,
+    ValueNS,
+    MacroNS,
+}
+
+/// Just a helper ‒ separate structure for each namespace.
+#[derive(Copy, Clone, Default, Debug)]
+pub struct PerNS<T> {
+    pub value_ns: T,
+    pub type_ns: T,
+    pub macro_ns: T,
+}
+
+impl<T> PerNS<T> {
+    pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> PerNS<U> {
+        PerNS {
+            value_ns: f(self.value_ns),
+            type_ns: f(self.type_ns),
+            macro_ns: f(self.macro_ns),
+        }
+    }
+}
+
+impl<T> ::std::ops::Index<Namespace> for PerNS<T> {
+    type Output = T;
+    fn index(&self, ns: Namespace) -> &T {
+        match ns {
+            ValueNS => &self.value_ns,
+            TypeNS => &self.type_ns,
+            MacroNS => &self.macro_ns,
+        }
+    }
+}
+
+impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
+    fn index_mut(&mut self, ns: Namespace) -> &mut T {
+        match ns {
+            ValueNS => &mut self.value_ns,
+            TypeNS => &mut self.type_ns,
+            MacroNS => &mut self.macro_ns,
+        }
+    }
+}
+
+impl<T> PerNS<Option<T>> {
+    /// Returns whether all the items in this collection are `None`.
+    pub fn is_empty(&self) -> bool {
+        self.type_ns.is_none() && self.value_ns.is_none() && self.macro_ns.is_none()
+    }
+
+    /// Returns an iterator over the items which are `Some`.
+    pub fn present_items(self) -> impl Iterator<Item=T> {
+        use std::iter::once;
+
+        once(self.type_ns)
+            .chain(once(self.value_ns))
+            .chain(once(self.macro_ns))
+            .filter_map(|it| it)
+    }
+}
+
 /// Definition mapping
 pub type DefMap = NodeMap<PathResolution>;
 
@@ -123,6 +191,10 @@ pub type DefMap = NodeMap<PathResolution>;
 /// within.
 pub type ExportMap = DefIdMap<Vec<Export>>;
 
+/// Map used to track the `use` statements within a scope, matching it with all the items in every
+/// namespace.
+pub type ImportMap = NodeMap<PerNS<Option<PathResolution>>>;
+
 #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct Export {
     /// The name of the target.
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 35d580d1c15..f31af7785a5 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -45,7 +45,7 @@ use hir;
 use hir::HirVec;
 use hir::map::{DefKey, DefPathData, Definitions};
 use hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX};
-use hir::def::{Def, PathResolution};
+use hir::def::{Def, PathResolution, PerNS};
 use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
 use middle::cstore::CrateStore;
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -152,6 +152,9 @@ pub trait Resolver {
     /// Obtain the resolution for a node id
     fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution>;
 
+    /// Obtain the possible resolutions for the given `use` statement.
+    fn get_import(&mut self, id: NodeId) -> PerNS<Option<PathResolution>>;
+
     /// We must keep the set of definitions up to date as we add nodes that weren't in the AST.
     /// This should only return `None` during testing.
     fn definitions(&mut self) -> &mut Definitions;
@@ -571,6 +574,15 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
+    fn expect_full_def_from_use(&mut self, id: NodeId) -> impl Iterator<Item=Def> {
+        self.resolver.get_import(id).present_items().map(|pr| {
+            if pr.unresolved_segments() != 0 {
+                bug!("path not fully resolved: {:?}", pr);
+            }
+            pr.base_def()
+        })
+    }
+
     fn diagnostic(&self) -> &errors::Handler {
         self.sess.diagnostic()
     }
@@ -1532,13 +1544,13 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_path_extra(
         &mut self,
-        id: NodeId,
+        def: Def,
         p: &Path,
         name: Option<Name>,
         param_mode: ParamMode,
     ) -> hir::Path {
         hir::Path {
-            def: self.expect_full_def(id),
+            def,
             segments: p.segments
                 .iter()
                 .map(|segment| {
@@ -1558,7 +1570,8 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path {
-        self.lower_path_extra(id, p, None, param_mode)
+        let def = self.expect_full_def(id);
+        self.lower_path_extra(def, p, None, param_mode)
     }
 
     fn lower_path_segment(
@@ -2363,7 +2376,7 @@ impl<'a> LoweringContext<'a> {
         let path = &tree.prefix;
 
         match tree.kind {
-            UseTreeKind::Simple(rename) => {
+            UseTreeKind::Simple(rename, id1, id2) => {
                 *name = tree.ident().name;
 
                 // First apply the prefix to the path
@@ -2387,7 +2400,58 @@ impl<'a> LoweringContext<'a> {
                     }
                 }
 
-                let path = P(self.lower_path(id, &path, ParamMode::Explicit));
+                let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
+                let mut defs = self.expect_full_def_from_use(id);
+                // we want to return *something* from this function, so hang onto the first item
+                // for later
+                let mut ret_def = defs.next().unwrap_or(Def::Err);
+
+                for (def, &new_node_id) in defs.zip([id1, id2].iter()) {
+                    let vis = vis.clone();
+                    let name = name.clone();
+                    let span = path.span;
+                    self.resolver.definitions().create_def_with_parent(
+                        parent_def_index,
+                        new_node_id,
+                        DefPathData::Misc,
+                        DefIndexAddressSpace::High,
+                        Mark::root(),
+                        span);
+                    self.allocate_hir_id_counter(new_node_id, &path);
+
+                    self.with_hir_id_owner(new_node_id, |this| {
+                        let new_id = this.lower_node_id(new_node_id);
+                        let path = this.lower_path_extra(def, &path, None, ParamMode::Explicit);
+                        let item = hir::ItemUse(P(path), hir::UseKind::Single);
+                        let vis = match vis {
+                            hir::Visibility::Public => hir::Visibility::Public,
+                            hir::Visibility::Crate(sugar) => hir::Visibility::Crate(sugar),
+                            hir::Visibility::Inherited => hir::Visibility::Inherited,
+                            hir::Visibility::Restricted { ref path, id: _ } => {
+                                hir::Visibility::Restricted {
+                                    path: path.clone(),
+                                    // We are allocating a new NodeId here
+                                    id: this.next_id().node_id,
+                                }
+                            }
+                        };
+
+                        this.items.insert(
+                            new_id.node_id,
+                            hir::Item {
+                                id: new_id.node_id,
+                                hir_id: new_id.hir_id,
+                                name: name,
+                                attrs: attrs.clone(),
+                                node: item,
+                                vis,
+                                span,
+                            },
+                        );
+                    });
+                }
+
+                let path = P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit));
                 hir::ItemUse(path, hir::UseKind::Single)
             }
             UseTreeKind::Glob => {
@@ -2654,7 +2718,7 @@ impl<'a> LoweringContext<'a> {
         match i.node {
             ItemKind::Use(ref use_tree) => {
                 let mut vec = SmallVector::one(hir::ItemId { id: i.id });
-                self.lower_item_id_use_tree(use_tree, &mut vec);
+                self.lower_item_id_use_tree(use_tree, i.id, &mut vec);
                 return vec;
             }
             ItemKind::MacroDef(..) => return SmallVector::new(),
@@ -2663,14 +2727,25 @@ impl<'a> LoweringContext<'a> {
         SmallVector::one(hir::ItemId { id: i.id })
     }
 
-    fn lower_item_id_use_tree(&self, tree: &UseTree, vec: &mut SmallVector<hir::ItemId>) {
+    fn lower_item_id_use_tree(&mut self,
+                              tree: &UseTree,
+                              base_id: NodeId,
+                              vec: &mut SmallVector<hir::ItemId>)
+    {
         match tree.kind {
             UseTreeKind::Nested(ref nested_vec) => for &(ref nested, id) in nested_vec {
                 vec.push(hir::ItemId { id });
-                self.lower_item_id_use_tree(nested, vec);
+                self.lower_item_id_use_tree(nested, id, vec);
             },
             UseTreeKind::Glob => {}
-            UseTreeKind::Simple(..) => {}
+            UseTreeKind::Simple(_, id1, id2) => {
+                for (_, &id) in self.expect_full_def_from_use(base_id)
+                                    .skip(1)
+                                    .zip([id1, id2].iter())
+                {
+                    vec.push(hir::ItemId { id });
+                }
+            },
         }
     }
 
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 845c964b986..81b4ae3f6e8 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -393,7 +393,7 @@ impl UnusedImportBraces {
             // Trigger the lint if the nested item is a non-self single item
             let node_ident;
             match items[0].0.kind {
-                ast::UseTreeKind::Simple(rename) => {
+                ast::UseTreeKind::Simple(rename, ..) => {
                     let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
                     if orig_ident.name == keywords::SelfValue.name() {
                         return;
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 2683a9982ac..af7678aa06f 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -118,7 +118,7 @@ impl<'a> Resolver<'a> {
             .collect();
 
         match use_tree.kind {
-            ast::UseTreeKind::Simple(rename) => {
+            ast::UseTreeKind::Simple(rename, ..) => {
                 let mut ident = use_tree.ident();
                 let mut source = module_path.pop().unwrap();
                 let mut type_ns_only = false;
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 8ff250dfa5c..2471430798e 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -27,7 +27,8 @@ extern crate arena;
 extern crate rustc;
 extern crate rustc_data_structures;
 
-use self::Namespace::*;
+pub use rustc::hir::def::{Namespace, PerNS};
+
 use self::TypeParameters::*;
 use self::RibKind::*;
 
@@ -37,6 +38,7 @@ use rustc::middle::cstore::{CrateStore, CrateLoader};
 use rustc::session::Session;
 use rustc::lint;
 use rustc::hir::def::*;
+use rustc::hir::def::Namespace::*;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
 use rustc::ty;
 use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
@@ -614,45 +616,6 @@ impl<'a> PathSource<'a> {
     }
 }
 
-/// Different kinds of symbols don't influence each other.
-///
-/// Therefore, they have a separate universe (namespace).
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-pub enum Namespace {
-    TypeNS,
-    ValueNS,
-    MacroNS,
-}
-
-/// Just a helper ‒ separate structure for each namespace.
-#[derive(Clone, Default, Debug)]
-pub struct PerNS<T> {
-    value_ns: T,
-    type_ns: T,
-    macro_ns: T,
-}
-
-impl<T> ::std::ops::Index<Namespace> for PerNS<T> {
-    type Output = T;
-    fn index(&self, ns: Namespace) -> &T {
-        match ns {
-            ValueNS => &self.value_ns,
-            TypeNS => &self.type_ns,
-            MacroNS => &self.macro_ns,
-        }
-    }
-}
-
-impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
-    fn index_mut(&mut self, ns: Namespace) -> &mut T {
-        match ns {
-            ValueNS => &mut self.value_ns,
-            TypeNS => &mut self.type_ns,
-            MacroNS => &mut self.macro_ns,
-        }
-    }
-}
-
 struct UsePlacementFinder {
     target_module: NodeId,
     span: Option<Span>,
@@ -1346,6 +1309,7 @@ pub struct Resolver<'a> {
     primitive_type_table: PrimitiveTypeTable,
 
     def_map: DefMap,
+    import_map: ImportMap,
     pub freevars: FreevarMap,
     freevars_seen: NodeMap<NodeMap<usize>>,
     pub export_map: ExportMap,
@@ -1518,6 +1482,10 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
         self.def_map.get(&id).cloned()
     }
 
+    fn get_import(&mut self, id: NodeId) -> PerNS<Option<PathResolution>> {
+        self.import_map.get(&id).cloned().unwrap_or_default()
+    }
+
     fn definitions(&mut self) -> &mut Definitions {
         &mut self.definitions
     }
@@ -1665,6 +1633,7 @@ impl<'a> Resolver<'a> {
             primitive_type_table: PrimitiveTypeTable::new(),
 
             def_map: NodeMap(),
+            import_map: NodeMap(),
             freevars: NodeMap(),
             freevars_seen: NodeMap(),
             export_map: FxHashMap(),
@@ -2215,7 +2184,7 @@ impl<'a> Resolver<'a> {
                     }
                 }
             }
-            ast::UseTreeKind::Simple(_) => {},
+            ast::UseTreeKind::Simple(..) => {},
             ast::UseTreeKind::Glob => {},
         }
     }
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 3fdac8f6afd..8ac5e248dad 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -918,7 +918,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         // this may resolve to either a value or a type, but for documentation
         // purposes it's good enough to just favor one over the other.
         self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() {
-            this.def_map.entry(directive.id).or_insert(PathResolution::new(binding.def()));
+            let mut import = this.import_map.entry(directive.id).or_default();
+            import[ns] = Some(PathResolution::new(binding.def()));
         });
 
         debug!("(resolving single import) successfully resolved import");
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index f05cbbfd7a2..44b41439511 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -365,6 +365,11 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
                 });
                 true
             }
+            hir_map::NodeStructCtor(_) if !glob => {
+                // struct constructors always show up alongside their struct definitions, we've
+                // already processed that so just discard this
+                true
+            }
             _ => false,
         };
         self.view_item_stack.remove(&def_node_id);
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index df7d4807c5c..76fa463a631 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1860,7 +1860,10 @@ pub type Variant = Spanned<Variant_>;
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum UseTreeKind {
     /// `use prefix` or `use prefix as rename`
-    Simple(Option<Ident>),
+    ///
+    /// The extra `NodeId`s are for HIR lowering, when additional statements are created for each
+    /// namespace.
+    Simple(Option<Ident>, NodeId, NodeId),
     /// `use prefix::{...}`
     Nested(Vec<(UseTree, NodeId)>),
     /// `use prefix::*`
@@ -1879,8 +1882,8 @@ pub struct UseTree {
 impl UseTree {
     pub fn ident(&self) -> Ident {
         match self.kind {
-            UseTreeKind::Simple(Some(rename)) => rename,
-            UseTreeKind::Simple(None) =>
+            UseTreeKind::Simple(Some(rename), ..) => rename,
+            UseTreeKind::Simple(None, ..) =>
                 self.prefix.segments.last().expect("empty prefix in a simple import").ident,
             _ => panic!("`UseTree::ident` can only be used on a simple import"),
         }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 6664c0a5982..4a6f06dcc17 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -1175,7 +1175,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.item_use(sp, vis, P(ast::UseTree {
             span: sp,
             prefix: path,
-            kind: ast::UseTreeKind::Simple(rename),
+            kind: ast::UseTreeKind::Simple(rename, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID),
         }))
     }
 
@@ -1185,7 +1185,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
             (ast::UseTree {
                 span: sp,
                 prefix: self.path(sp, vec![*id]),
-                kind: ast::UseTreeKind::Simple(None),
+                kind: ast::UseTreeKind::Simple(None, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID),
             }, ast::DUMMY_NODE_ID)
         }).collect();
 
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 9f370672cb2..a2ea6a21484 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -1545,7 +1545,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     }
 
     fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: NodeId, _nested: bool) {
-        if let ast::UseTreeKind::Simple(Some(ident)) = use_tree.kind {
+        if let ast::UseTreeKind::Simple(Some(ident), ..) = use_tree.kind {
             if ident.name == "_" {
                 gate_feature_post!(&self, underscore_imports, use_tree.span,
                                    "renaming imports with `_` is unstable");
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 1056b3dad17..8544ef330dc 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -315,8 +315,9 @@ pub fn noop_fold_use_tree<T: Folder>(use_tree: UseTree, fld: &mut T) -> UseTree
         span: fld.new_span(use_tree.span),
         prefix: fld.fold_path(use_tree.prefix),
         kind: match use_tree.kind {
-            UseTreeKind::Simple(rename) =>
-                UseTreeKind::Simple(rename.map(|ident| fld.fold_ident(ident))),
+            UseTreeKind::Simple(rename, id1, id2) =>
+                UseTreeKind::Simple(rename.map(|ident| fld.fold_ident(ident)),
+                                    fld.new_id(id1), fld.new_id(id2)),
             UseTreeKind::Glob => UseTreeKind::Glob,
             UseTreeKind::Nested(items) => UseTreeKind::Nested(items.move_map(|(tree, id)| {
                 (fld.fold_use_tree(tree), fld.new_id(id))
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index e1f920c16fd..85759e7ae8f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -7157,7 +7157,7 @@ impl<'a> Parser<'a> {
                     UseTreeKind::Nested(self.parse_use_tree_list()?)
                 }
             } else {
-                UseTreeKind::Simple(self.parse_rename()?)
+                UseTreeKind::Simple(self.parse_rename()?, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID)
             }
         };
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 10b7286d5a3..87edfd69e2b 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2958,7 +2958,7 @@ impl<'a> State<'a> {
 
     pub fn print_use_tree(&mut self, tree: &ast::UseTree) -> io::Result<()> {
         match tree.kind {
-            ast::UseTreeKind::Simple(rename) => {
+            ast::UseTreeKind::Simple(rename, ..) => {
                 self.print_path(&tree.prefix, false, 0)?;
                 if let Some(rename) = rename {
                     self.s.space()?;
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 0c7f70a578a..da7deb3c4cf 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -492,7 +492,7 @@ fn mk_std(cx: &TestCtxt) -> P<ast::Item> {
         (ast::ItemKind::Use(P(ast::UseTree {
             span: DUMMY_SP,
             prefix: path_node(vec![id_test]),
-            kind: ast::UseTreeKind::Simple(None),
+            kind: ast::UseTreeKind::Simple(None, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID),
         })),
          ast::VisibilityKind::Public, keywords::Invalid.ident())
     } else {
@@ -588,7 +588,7 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P<ast::Item>, Option<P<ast::Item>>) {
         let use_path = ast::UseTree {
             span: DUMMY_SP,
             prefix: path_node(vec![mod_ident, Ident::from_str("main")]),
-            kind: ast::UseTreeKind::Simple(Some(rename)),
+            kind: ast::UseTreeKind::Simple(Some(rename), ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID),
         };
 
         expander.fold_item(P(ast::Item {
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index dca0e2f634c..adda39c62ed 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -356,7 +356,8 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>(
 ) {
     visitor.visit_path(&use_tree.prefix, id);
     match use_tree.kind {
-        UseTreeKind::Simple(rename) => {
+        UseTreeKind::Simple(rename, ..) => {
+            // the extra IDs are handled during HIR lowering
             if let Some(rename) = rename {
                 visitor.visit_ident(rename);
             }
diff --git a/src/test/rustdoc/namespaces.rs b/src/test/rustdoc/namespaces.rs
new file mode 100644
index 00000000000..ec1bc359ab0
--- /dev/null
+++ b/src/test/rustdoc/namespaces.rs
@@ -0,0 +1,26 @@
+// 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.
+
+// issue #34843: rustdoc prioritises documenting reexports from the type namespace
+
+mod inner {
+    pub mod sync {
+        pub struct SomeStruct;
+    }
+
+    pub fn sync() {}
+}
+
+// @has namespaces/sync/index.html
+// @has namespaces/fn.sync.html
+// @has namespaces/index.html '//a/@href' 'sync/index.html'
+// @has - '//a/@href' 'fn.sync.html'
+#[doc(inline)]
+pub use inner::sync;