about summary refs log tree commit diff
path: root/src/librustc_resolve/resolve_imports.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_resolve/resolve_imports.rs')
-rw-r--r--src/librustc_resolve/resolve_imports.rs331
1 files changed, 183 insertions, 148 deletions
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 48f312ce9f2..a3694cd73ad 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -13,15 +13,16 @@ use self::ImportDirectiveSubclass::*;
 use {AmbiguityError, CrateLint, Module, ModuleOrUniformRoot, PerNS};
 use Namespace::{self, TypeNS, MacroNS};
 use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
-use Resolver;
+use {Resolver, Segment};
 use {names_to_string, module_to_string};
 use {resolve_error, ResolutionError};
+use macros::ParentScope;
 
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc::ty;
 use rustc::lint::builtin::BuiltinLintDiagnostics;
 use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE};
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::def_id::DefId;
 use rustc::hir::def::*;
 use rustc::session::DiagnosticMessageId;
 use rustc::util::nodemap::FxHashSet;
@@ -35,7 +36,6 @@ use syntax_pos::{MultiSpan, Span};
 
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeMap;
-use std::fmt::Write;
 use std::{mem, ptr};
 
 /// Contains data for specific types of import directives.
@@ -52,7 +52,10 @@ pub enum ImportDirectiveSubclass<'a> {
         max_vis: Cell<ty::Visibility>, // The visibility of the greatest re-export.
         // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
     },
-    ExternCrate(Option<Name>),
+    ExternCrate {
+        source: Option<Name>,
+        target: Ident,
+    },
     MacroUse,
 }
 
@@ -85,13 +88,12 @@ pub struct ImportDirective<'a> {
     /// Span of the *root* use tree (see `root_id`).
     pub root_span: Span,
 
-    pub parent: Module<'a>,
-    pub module_path: Vec<Ident>,
+    pub parent_scope: ParentScope<'a>,
+    pub module_path: Vec<Segment>,
     /// The resolution of `module_path`.
     pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
     pub subclass: ImportDirectiveSubclass<'a>,
     pub vis: Cell<ty::Visibility>,
-    pub expansion: Mark,
     pub used: Cell<bool>,
 
     /// Whether this import is a "canary" for the `uniform_paths` feature,
@@ -199,7 +201,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
                     if !(
                         ns == TypeNS &&
                         !ident.is_path_segment_keyword() &&
-                        self.extern_prelude.contains(&ident.name)
+                        self.extern_prelude.contains_key(&ident.modern())
                     ) {
                         // ... unless the crate name is not in the `extern_prelude`.
                         return binding;
@@ -217,12 +219,18 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
                     self.resolve_crate_root(ident)
                 } else if
                     ns == TypeNS &&
-                    !ident.is_path_segment_keyword() &&
-                    self.extern_prelude.contains(&ident.name)
+                    !ident.is_path_segment_keyword()
                 {
-                    let crate_id =
-                        self.crate_loader.process_path_extern(ident.name, ident.span);
-                    self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
+                    if let Some(binding) = self.extern_prelude_get(ident, !record_used, false) {
+                        let module = self.get_module(binding.def().def_id());
+                        self.populate_module_if_necessary(module);
+                        return Ok(binding);
+                    } else if !self.graph_root.unresolved_invocations.borrow().is_empty() {
+                        // Macro-expanded `extern crate`items still can add names to extern prelude.
+                        return Err(Undetermined);
+                    } else {
+                        return Err(Determined);
+                    }
                 } else {
                     return Err(Determined);
                 };
@@ -266,7 +274,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
                     return Ok(self.dummy_binding);
                 }
                 if !self.is_accessible(binding.vis) {
-                    self.privacy_errors.push(PrivacyError(path_span, ident.name, binding));
+                    self.privacy_errors.push(PrivacyError(path_span, ident, binding));
                 }
             }
 
@@ -301,8 +309,9 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
             };
             match self.resolve_ident_in_module(module, ident, ns, false, path_span) {
                 Err(Determined) => continue,
-                Ok(binding)
-                    if !self.is_accessible_from(binding.vis, single_import.parent) => continue,
+                Ok(binding) if !self.is_accessible_from(
+                    binding.vis, single_import.parent_scope.module
+                ) => continue,
                 Ok(_) | Err(Undetermined) => return Err(Undetermined),
             }
         }
@@ -375,8 +384,9 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
 
             match result {
                 Err(Determined) => continue,
-                Ok(binding)
-                    if !self.is_accessible_from(binding.vis, glob_import.parent) => continue,
+                Ok(binding) if !self.is_accessible_from(
+                    binding.vis, glob_import.parent_scope.module
+                ) => continue,
                 Ok(_) | Err(Undetermined) => return Err(Undetermined),
             }
         }
@@ -387,18 +397,18 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
 
     // Add an import directive to the current module.
     pub fn add_import_directive(&mut self,
-                                module_path: Vec<Ident>,
+                                module_path: Vec<Segment>,
                                 subclass: ImportDirectiveSubclass<'a>,
                                 span: Span,
                                 id: NodeId,
                                 root_span: Span,
                                 root_id: NodeId,
                                 vis: ty::Visibility,
-                                expansion: Mark,
+                                parent_scope: ParentScope<'a>,
                                 is_uniform_paths_canary: bool) {
-        let current_module = self.current_module;
+        let current_module = parent_scope.module;
         let directive = self.arenas.alloc_import_directive(ImportDirective {
-            parent: current_module,
+            parent_scope,
             module_path,
             imported_module: Cell::new(None),
             subclass,
@@ -407,7 +417,6 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
             root_span,
             root_id,
             vis: Cell::new(vis),
-            expansion,
             used: Cell::new(false),
             is_uniform_paths_canary,
         });
@@ -425,7 +434,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
             // We don't add prelude imports to the globs since they only affect lexical scopes,
             // which are not relevant to import resolution.
             GlobImport { is_prelude: true, .. } => {}
-            GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive),
+            GlobImport { .. } => current_module.globs.borrow_mut().push(directive),
             _ => unreachable!(),
         }
     }
@@ -456,7 +465,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
             },
             span: directive.span,
             vis,
-            expansion: directive.expansion,
+            expansion: directive.parent_scope.expansion,
         })
     }
 
@@ -562,12 +571,12 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
             let scope = match ident.span.reverse_glob_adjust(module.expansion,
                                                              directive.span.ctxt().modern()) {
                 Some(Some(def)) => self.macro_def_scope(def),
-                Some(None) => directive.parent,
+                Some(None) => directive.parent_scope.module,
                 None => continue,
             };
             if self.is_accessible_from(binding.vis, scope) {
                 let imported_binding = self.import(binding, directive);
-                let _ = self.try_define(directive.parent, ident, ns, imported_binding);
+                let _ = self.try_define(directive.parent_scope.module, ident, ns, imported_binding);
             }
         }
 
@@ -581,7 +590,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
             let dummy_binding = self.dummy_binding;
             let dummy_binding = self.import(dummy_binding, directive);
             self.per_ns(|this, ns| {
-                let _ = this.try_define(directive.parent, target, ns, dummy_binding);
+                let _ = this.try_define(directive.parent_scope.module, target, ns, dummy_binding);
             });
         }
     }
@@ -652,7 +661,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
         > = BTreeMap::new();
 
         let mut errors = false;
-        let mut seen_spans = FxHashSet();
+        let mut seen_spans = FxHashSet::default();
         let mut error_vec = Vec::new();
         let mut prev_root_id: NodeId = NodeId::new(0);
         for i in 0 .. self.determined_imports.len() {
@@ -672,8 +681,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                 };
 
                 let has_explicit_self =
-                    import.module_path.len() > 0 &&
-                    import.module_path[0].name == keywords::SelfValue.name();
+                    !import.module_path.is_empty() &&
+                    import.module_path[0].ident.name == keywords::SelfValue.name();
 
                 self.per_ns(|_, ns| {
                     if let Some(result) = result[ns].get().ok() {
@@ -697,15 +706,14 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                         }
                     }
                 });
-            } else if let Some((span, err)) = error {
+            } else if let Some((span, err, note)) = error {
                 errors = true;
 
                 if let SingleImport { source, ref result, .. } = import.subclass {
                     if source.name == "self" {
                         // Silence `unresolved import` error if E0429 is already emitted
-                        match result.value_ns.get() {
-                            Err(Determined) => continue,
-                            _ => {},
+                        if let Err(Determined) = result.value_ns.get() {
+                            continue;
                         }
                     }
                 }
@@ -723,10 +731,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                     self.throw_unresolved_import_error(empty_vec, None);
                 }
                 if !seen_spans.contains(&span) {
-                    let path = import_path_to_string(&import.module_path[..],
-                                                     &import.subclass,
-                                                     span);
-                    error_vec.push((span, path, err));
+                    let path = import_path_to_string(
+                        &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
+                        &import.subclass,
+                        span,
+                    );
+                    error_vec.push((span, path, err, note));
                     seen_spans.insert(span);
                     prev_root_id = import.root_id;
                 }
@@ -736,10 +746,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
         let uniform_paths_feature = self.session.features_untracked().uniform_paths;
         for ((span, _, ns), results) in uniform_paths_canaries {
             let name = results.name;
-            let external_crate = if ns == TypeNS && self.extern_prelude.contains(&name) {
-                let crate_id =
-                    self.crate_loader.process_path_extern(name, span);
-                Some(Def::Mod(DefId { krate: crate_id, index: CRATE_DEF_INDEX }))
+            let external_crate = if ns == TypeNS {
+                self.extern_prelude_get(Ident::with_empty_ctxt(name), true, false)
+                    .map(|binding| binding.def())
             } else {
                 None
             };
@@ -770,17 +779,14 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
 
             let msg = format!("`{}` import is ambiguous", name);
             let mut err = self.session.struct_span_err(span, &msg);
-            let mut suggestion_choices = String::new();
+            let mut suggestion_choices = vec![];
             if external_crate.is_some() {
-                write!(suggestion_choices, "`::{}`", name);
+                suggestion_choices.push(format!("`::{}`", name));
                 err.span_label(span,
                     format!("can refer to external crate `::{}`", name));
             }
             if let Some(result) = results.module_scope {
-                if !suggestion_choices.is_empty() {
-                    suggestion_choices.push_str(" or ");
-                }
-                write!(suggestion_choices, "`self::{}`", name);
+                suggestion_choices.push(format!("`self::{}`", name));
                 if uniform_paths_feature {
                     err.span_label(result.span,
                         format!("can refer to `self::{}`", name));
@@ -793,7 +799,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                 err.span_label(result.span,
                     format!("shadowed by block-scoped `{}`", name));
             }
-            err.help(&format!("write {} explicitly instead", suggestion_choices));
+            err.help(&format!("write {} explicitly instead", suggestion_choices.join(" or ")));
             if uniform_paths_feature {
                 err.note("relative `use` paths enabled by `#![feature(uniform_paths)]`");
             } else {
@@ -819,28 +825,45 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
         }
     }
 
-    fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>,
-                                     span: Option<MultiSpan>) {
+    fn throw_unresolved_import_error(
+        &self,
+        error_vec: Vec<(Span, String, String, Option<String>)>,
+        span: Option<MultiSpan>,
+    ) {
         let max_span_label_msg_count = 10;  // upper limit on number of span_label message.
-        let (span,msg) = match error_vec.is_empty() {
-            true => (span.unwrap(), "unresolved import".to_string()),
-            false => {
-                let span = MultiSpan::from_spans(error_vec.clone().into_iter()
-                                    .map(|elem: (Span, String, String)| { elem.0 }
-                                    ).collect());
-                let path_vec: Vec<String> = error_vec.clone().into_iter()
-                                .map(|elem: (Span, String, String)| { format!("`{}`", elem.1) }
-                                ).collect();
-                let path = path_vec.join(", ");
-                let msg = format!("unresolved import{} {}",
-                                if path_vec.len() > 1 { "s" } else { "" },  path);
-                (span, msg)
-            }
+        let (span, msg, note) = if error_vec.is_empty() {
+            (span.unwrap(), "unresolved import".to_string(), None)
+        } else {
+            let span = MultiSpan::from_spans(
+                error_vec.clone().into_iter()
+                .map(|elem: (Span, String, String, Option<String>)| elem.0)
+                .collect()
+            );
+
+            let note: Option<String> = error_vec.clone().into_iter()
+                .filter_map(|elem: (Span, String, String, Option<String>)| elem.3)
+                .last();
+
+            let path_vec: Vec<String> = error_vec.clone().into_iter()
+                .map(|elem: (Span, String, String, Option<String>)| format!("`{}`", elem.1))
+                .collect();
+            let path = path_vec.join(", ");
+            let msg = format!(
+                "unresolved import{} {}",
+                if path_vec.len() > 1 { "s" } else { "" },
+                path
+            );
+
+            (span, msg, note)
         };
+
         let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg);
         for span_error in error_vec.into_iter().take(max_span_label_msg_count) {
             err.span_label(span_error.0, span_error.2);
         }
+        if let Some(note) = note {
+            err.note(&note);
+        }
         err.emit();
     }
 
@@ -848,10 +871,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
     /// If successful, the resolved bindings are written into the module.
     fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
         debug!("(resolving import for module) resolving import `{}::...` in `{}`",
-               names_to_string(&directive.module_path[..]),
-               module_to_string(self.current_module).unwrap_or("???".to_string()));
+               Segment::names_to_string(&directive.module_path[..]),
+               module_to_string(self.current_module).unwrap_or_else(|| "???".to_string()));
 
-        self.current_module = directive.parent;
+        self.current_module = directive.parent_scope.module;
 
         let module = if let Some(module) = directive.imported_module.get() {
             module
@@ -862,12 +885,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
             directive.vis.set(ty::Visibility::Invisible);
             let result = self.resolve_path(
                 Some(if directive.is_uniform_paths_canary {
-                    ModuleOrUniformRoot::Module(directive.parent)
+                    ModuleOrUniformRoot::Module(directive.parent_scope.module)
                 } else {
                     ModuleOrUniformRoot::UniformRoot(keywords::Invalid.name())
                 }),
                 &directive.module_path[..],
                 None,
+                &directive.parent_scope,
                 false,
                 directive.span,
                 directive.crate_lint(),
@@ -904,7 +928,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                 return
             };
 
-            let parent = directive.parent;
+            let parent = directive.parent_scope.module;
             match result[ns].get() {
                 Err(Undetermined) => indeterminate = true,
                 Err(Determined) => {
@@ -935,18 +959,22 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
     }
 
     // If appropriate, returns an error to report.
-    fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
-        self.current_module = directive.parent;
+    fn finalize_import(
+        &mut self,
+        directive: &'b ImportDirective<'b>
+    ) -> Option<(Span, String, Option<String>)> {
+        self.current_module = directive.parent_scope.module;
         let ImportDirective { ref module_path, span, .. } = *directive;
 
         let module_result = self.resolve_path(
             Some(if directive.is_uniform_paths_canary {
-                ModuleOrUniformRoot::Module(directive.parent)
+                ModuleOrUniformRoot::Module(directive.parent_scope.module)
             } else {
                 ModuleOrUniformRoot::UniformRoot(keywords::Invalid.name())
             }),
             &module_path,
             None,
+            &directive.parent_scope,
             true,
             span,
             directive.crate_lint(),
@@ -958,15 +986,16 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                 return None;
             }
             PathResult::Failed(span, msg, true) => {
-                return if let Some(suggested_path) = self.make_path_suggestion(
-                    span, module_path.clone()
+                return if let Some((suggested_path, note)) = self.make_path_suggestion(
+                    span, module_path.clone(), &directive.parent_scope
                 ) {
                     Some((
                         span,
-                        format!("Did you mean `{}`?", names_to_string(&suggested_path[..]))
+                        format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path)),
+                        note,
                     ))
                 } else {
-                    Some((span, msg))
+                    Some((span, msg, None))
                 };
             },
             _ => return None,
@@ -979,7 +1008,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                     // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
                     // 2 segments, so the `resolve_path` above won't trigger it.
                     let mut full_path = module_path.clone();
-                    full_path.push(keywords::Invalid.ident());
+                    full_path.push(Segment::from_ident(keywords::Invalid.ident()));
                     self.lint_if_path_starts_with_module(
                         directive.crate_lint(),
                         &full_path,
@@ -989,10 +1018,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                 }
 
                 if let ModuleOrUniformRoot::Module(module) = module {
-                    if module.def_id() == directive.parent.def_id() {
+                    if module.def_id() == directive.parent_scope.module.def_id() {
                         // Importing a module into itself is not allowed.
-                        return Some((directive.span,
-                            "Cannot glob-import a module into itself.".to_string()));
+                        return Some((
+                            directive.span,
+                            "Cannot glob-import a module into itself.".to_string(),
+                            None,
+                        ));
                     }
                 }
                 if !is_prelude &&
@@ -1020,15 +1052,21 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                             Some(this.dummy_binding);
                     }
                 }
+                if record_used && ns == TypeNS {
+                    if let ModuleOrUniformRoot::UniformRoot(..) = module {
+                        // Make sure single-segment import is resolved non-speculatively
+                        // at least once to report the feature error.
+                        this.extern_prelude_get(ident, false, false);
+                    }
+                }
             }
         });
 
         if all_ns_err {
             let mut all_ns_failed = true;
             self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
-                match this.resolve_ident_in_module(module, ident, ns, record_used, span) {
-                    Ok(_) => all_ns_failed = false,
-                    _ => {}
+                if this.resolve_ident_in_module(module, ident, ns, record_used, span).is_ok() {
+                    all_ns_failed = false;
                 }
             });
 
@@ -1084,7 +1122,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                         }
                     }
                 };
-                Some((span, msg))
+                Some((span, msg, None))
             } else {
                 // `resolve_ident_in_module` reported a privacy error.
                 self.import_dummy_binding(directive);
@@ -1137,7 +1175,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
             // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
             // 2 segments, so the `resolve_path` above won't trigger it.
             let mut full_path = module_path.clone();
-            full_path.push(ident);
+            full_path.push(Segment::from_ident(ident));
             self.per_ns(|this, ns| {
                 if let Ok(binding) = result[ns].get() {
                     this.lint_if_path_starts_with_module(
@@ -1177,7 +1215,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
         if let Some(Def::Trait(_)) = module.def() {
             self.session.span_err(directive.span, "items in traits are not importable.");
             return;
-        } else if module.def_id() == directive.parent.def_id()  {
+        } else if module.def_id() == directive.parent_scope.module.def_id()  {
             return;
         } else if let GlobImport { is_prelude: true, .. } = directive.subclass {
             self.prelude = Some(module);
@@ -1201,7 +1239,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
             };
             if self.is_accessible_from(binding.pseudo_vis(), scope) {
                 let imported_binding = self.import(binding, directive);
-                let _ = self.try_define(directive.parent, ident, ns, imported_binding);
+                let _ = self.try_define(directive.parent_scope.module, ident, ns, imported_binding);
             }
         }
 
@@ -1247,65 +1285,62 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
                 }
             }
 
-            match binding.kind {
-                NameBindingKind::Import { binding: orig_binding, directive, .. } => {
-                    if ns == TypeNS && orig_binding.is_variant() &&
-                        !orig_binding.vis.is_at_least(binding.vis, &*self) {
-                            let msg = match directive.subclass {
-                                ImportDirectiveSubclass::SingleImport { .. } => {
-                                    format!("variant `{}` is private and cannot be re-exported",
-                                            ident)
-                                },
-                                ImportDirectiveSubclass::GlobImport { .. } => {
-                                    let msg = "enum is private and its variants \
-                                               cannot be re-exported".to_owned();
-                                    let error_id = (DiagnosticMessageId::ErrorId(0), // no code?!
-                                                    Some(binding.span),
-                                                    msg.clone());
-                                    let fresh = self.session.one_time_diagnostics
-                                        .borrow_mut().insert(error_id);
-                                    if !fresh {
-                                        continue;
-                                    }
-                                    msg
-                                },
-                                ref s @ _ => bug!("unexpected import subclass {:?}", s)
-                            };
-                            let mut err = self.session.struct_span_err(binding.span, &msg);
-
-                            let imported_module = match directive.imported_module.get() {
-                                Some(ModuleOrUniformRoot::Module(module)) => module,
-                                _ => bug!("module should exist"),
-                            };
-                            let resolutions = imported_module.parent.expect("parent should exist")
-                                .resolutions.borrow();
-                            let enum_path_segment_index = directive.module_path.len() - 1;
-                            let enum_ident = directive.module_path[enum_path_segment_index];
-
-                            let enum_resolution = resolutions.get(&(enum_ident, TypeNS))
-                                .expect("resolution should exist");
-                            let enum_span = enum_resolution.borrow()
-                                .binding.expect("binding should exist")
-                                .span;
-                            let enum_def_span = self.session.source_map().def_span(enum_span);
-                            let enum_def_snippet = self.session.source_map()
-                                .span_to_snippet(enum_def_span).expect("snippet should exist");
-                            // potentially need to strip extant `crate`/`pub(path)` for suggestion
-                            let after_vis_index = enum_def_snippet.find("enum")
-                                .expect("`enum` keyword should exist in snippet");
-                            let suggestion = format!("pub {}",
-                                                     &enum_def_snippet[after_vis_index..]);
-
-                            self.session
-                                .diag_span_suggestion_once(&mut err,
-                                                           DiagnosticMessageId::ErrorId(0),
-                                                           enum_def_span,
-                                                           "consider making the enum public",
-                                                           suggestion);
-                            err.emit();
-                    }
+            if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind {
+                if ns == TypeNS && orig_binding.is_variant() &&
+                    !orig_binding.vis.is_at_least(binding.vis, &*self) {
+                        let msg = match directive.subclass {
+                            ImportDirectiveSubclass::SingleImport { .. } => {
+                                format!("variant `{}` is private and cannot be re-exported",
+                                        ident)
+                            },
+                            ImportDirectiveSubclass::GlobImport { .. } => {
+                                let msg = "enum is private and its variants \
+                                           cannot be re-exported".to_owned();
+                                let error_id = (DiagnosticMessageId::ErrorId(0), // no code?!
+                                                Some(binding.span),
+                                                msg.clone());
+                                let fresh = self.session.one_time_diagnostics
+                                    .borrow_mut().insert(error_id);
+                                if !fresh {
+                                    continue;
+                                }
+                                msg
+                            },
+                            ref s @ _ => bug!("unexpected import subclass {:?}", s)
+                        };
+                        let mut err = self.session.struct_span_err(binding.span, &msg);
+
+                        let imported_module = match directive.imported_module.get() {
+                            Some(ModuleOrUniformRoot::Module(module)) => module,
+                            _ => bug!("module should exist"),
+                        };
+                        let resolutions = imported_module.parent.expect("parent should exist")
+                            .resolutions.borrow();
+                        let enum_path_segment_index = directive.module_path.len() - 1;
+                        let enum_ident = directive.module_path[enum_path_segment_index].ident;
+
+                        let enum_resolution = resolutions.get(&(enum_ident, TypeNS))
+                            .expect("resolution should exist");
+                        let enum_span = enum_resolution.borrow()
+                            .binding.expect("binding should exist")
+                            .span;
+                        let enum_def_span = self.session.source_map().def_span(enum_span);
+                        let enum_def_snippet = self.session.source_map()
+                            .span_to_snippet(enum_def_span).expect("snippet should exist");
+                        // potentially need to strip extant `crate`/`pub(path)` for suggestion
+                        let after_vis_index = enum_def_snippet.find("enum")
+                            .expect("`enum` keyword should exist in snippet");
+                        let suggestion = format!("pub {}",
+                                                 &enum_def_snippet[after_vis_index..]);
+
+                        self.session
+                            .diag_span_suggestion_once(&mut err,
+                                                       DiagnosticMessageId::ErrorId(0),
+                                                       enum_def_span,
+                                                       "consider making the enum public",
+                                                       suggestion);
+                        err.emit();
                 }
-                _ => {}
             }
         }
 
@@ -1342,7 +1377,7 @@ fn import_directive_subclass_to_string(subclass: &ImportDirectiveSubclass) -> St
     match *subclass {
         SingleImport { source, .. } => source.to_string(),
         GlobImport { .. } => "*".to_string(),
-        ExternCrate(_) => "<extern crate>".to_string(),
+        ExternCrate { .. } => "<extern crate>".to_string(),
         MacroUse => "#[macro_use]".to_string(),
     }
 }