about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/privacy.rs156
-rw-r--r--src/librustc/middle/resolve.rs220
-rw-r--r--src/test/compile-fail/privacy-ns1.rs66
-rw-r--r--src/test/compile-fail/privacy-ns2.rs91
-rw-r--r--src/test/run-pass/privacy-ns.rs124
5 files changed, 549 insertions, 108 deletions
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 8c5654d3fce..1ab5ebc6d61 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -41,6 +41,11 @@ pub type ExportedItems = HashSet<ast::NodeId>;
 /// reexporting a public struct doesn't inline the doc).
 pub type PublicItems = HashSet<ast::NodeId>;
 
+/// Result of a checking operation - None => no errors were found. Some => an
+/// error and contains the span and message for reporting that error and
+/// optionally the same for a note about the error.
+type CheckResult = Option<(Span, ~str, Option<(Span, ~str)>)>;
+
 ////////////////////////////////////////////////////////////////////////////////
 /// The parent visitor, used to determine what's the parent of what (node-wise)
 ////////////////////////////////////////////////////////////////////////////////
@@ -510,40 +515,50 @@ impl<'a> PrivacyVisitor<'a> {
         }
     }
 
-    /// Guarantee that a particular definition is public, possibly emitting an
-    /// error message if it's not.
+    fn report_error(&self, result: CheckResult) -> bool {
+        match result {
+            None => true,
+            Some((span, msg, note)) => {
+                self.tcx.sess.span_err(span, msg);
+                match note {
+                    Some((span, msg)) => self.tcx.sess.span_note(span, msg),
+                    None => {},
+                }
+                false
+            },
+        }
+    }
+
+    /// Guarantee that a particular definition is public. Returns a CheckResult
+    /// which contains any errors found. These can be reported using `report_error`.
+    /// If the result is `None`, no errors were found.
     fn ensure_public(&self, span: Span, to_check: ast::DefId,
-                     source_did: Option<ast::DefId>, msg: &str) -> bool {
+                     source_did: Option<ast::DefId>, msg: &str) -> CheckResult {
         match self.def_privacy(to_check) {
-            ExternallyDenied => {
-                self.tcx.sess.span_err(span, format!("{} is private", msg))
-            }
+            ExternallyDenied => Some((span, format!("{} is private", msg), None)),
             DisallowedBy(id) => {
-                if id == source_did.unwrap_or(to_check).node {
-                    self.tcx.sess.span_err(span, format!("{} is private", msg));
-                    return false;
+                let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
+                    return Some((span, format!("{} is private", msg), None));
                 } else {
-                    self.tcx.sess.span_err(span, format!("{} is inaccessible",
-                                                         msg));
-                }
+                    (span, format!("{} is inaccessible", msg))
+                };
                 match self.tcx.map.find(id) {
                     Some(ast_map::NodeItem(item)) => {
                         let desc = match item.node {
                             ast::ItemMod(..) => "module",
                             ast::ItemTrait(..) => "trait",
-                            _ => return false,
+                            _ => return Some((err_span, err_msg, None)),
                         };
                         let msg = format!("{} `{}` is private",
                                           desc,
                                           token::get_ident(item.ident));
-                        self.tcx.sess.span_note(span, msg);
-                    }
-                    Some(..) | None => {}
+                        Some((err_span, err_msg, Some((span, msg))))
+                    },
+                    _ => Some((err_span, err_msg, None)),
                 }
-            }
-            Allowable => return true
+            },
+            Allowable => None,
         }
-        return false;
     }
 
     // Checks that a field is in scope.
@@ -613,34 +628,99 @@ impl<'a> PrivacyVisitor<'a> {
         let method_id = ty::method(self.tcx, method_id).provided_source
                                                        .unwrap_or(method_id);
 
-        self.ensure_public(span,
-                           method_id,
-                           None,
-                           format!("method `{}`", token::get_ident(name)));
+        let string = token::get_ident(name);
+        self.report_error(self.ensure_public(span,
+                                             method_id,
+                                             None,
+                                             format!("method `{}`", string)));
     }
 
     // Checks that a path is in scope.
     fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) {
         debug!("privacy - path {}", self.nodestr(path_id));
         let def_map = self.tcx.def_map.borrow();
-        let def = def_map.get().get_copy(&path_id);
+        let orig_def = def_map.get().get_copy(&path_id);
         let ck = |tyname: &str| {
-            let origdid = def_id_of_def(def);
+            let ck_public = |def: ast::DefId| {
+                let name = token::get_ident(path.segments
+                                                .last()
+                                                .unwrap()
+                                                .identifier);
+                let origdid = def_id_of_def(orig_def);
+                self.ensure_public(span,
+                                   def,
+                                   Some(origdid),
+                                   format!("{} `{}`",
+                                           tyname,
+                                           name))
+            };
+
             match *self.last_private_map.get(&path_id) {
-                resolve::AllPublic => {},
-                resolve::DependsOn(def) => {
-                    let name = token::get_ident(path.segments
-                                                    .last()
-                                                    .unwrap()
-                                                    .identifier);
-                    self.ensure_public(span,
-                                       def,
-                                       Some(origdid),
-                                       format!("{} `{}`",
-                                               tyname, name));
-                }
+                resolve::LastMod(resolve::AllPublic) => {},
+                resolve::LastMod(resolve::DependsOn(def)) => {
+                    self.report_error(ck_public(def));
+                },
+                resolve::LastImport{value_priv: value_priv,
+                                    value_used: check_value,
+                                    type_priv: type_priv,
+                                    type_used: check_type} => {
+                    // This dance with found_error is because we don't want to report
+                    // a privacy error twice for the same directive.
+                    let found_error = match (type_priv, check_type) {
+                        (Some(resolve::DependsOn(def)), resolve::Used) => {
+                            !self.report_error(ck_public(def))
+                        },
+                        _ => false,
+                    };
+                    if !found_error {
+                        match (value_priv, check_value) {
+                            (Some(resolve::DependsOn(def)), resolve::Used) => {
+                                self.report_error(ck_public(def));
+                            },
+                            _ => {},
+                        }
+                    }
+                    // If an import is not used in either namespace, we still want to check
+                    // that it could be legal. Therefore we check in both namespaces and only
+                    // report an error if both would be illegal. We only report one error,
+                    // even if it is illegal to import from both namespaces.
+                    match (value_priv, check_value, type_priv, check_type) {
+                        (Some(p), resolve::Unused, None, _) |
+                        (None, _, Some(p), resolve::Unused) => {
+                            let p = match p {
+                                resolve::AllPublic => None,
+                                resolve::DependsOn(def) => ck_public(def),
+                            };
+                            if p.is_some() {
+                                self.report_error(p);
+                            }
+                        },
+                        (Some(v), resolve::Unused, Some(t), resolve::Unused) => {
+                            let v = match v {
+                                resolve::AllPublic => None,
+                                resolve::DependsOn(def) => ck_public(def),
+                            };
+                            let t = match t {
+                                resolve::AllPublic => None,
+                                resolve::DependsOn(def) => ck_public(def),
+                            };
+                            match (v, t) {
+                                (Some(_), Some(t)) => {
+                                    self.report_error(Some(t));
+                                },
+                                _ => {},
+                            }
+                        },
+                        _ => {},
+                    }
+                },
             }
         };
+        // FIXME(#12334) Imports can refer to definitions in both the type and
+        // value namespaces. The privacy information is aware of this, but the
+        // def map is not. Therefore the names we work out below will not always
+        // be accurate and we can get slightly wonky error messages (but type
+        // checking is always correct).
         let def_map = self.tcx.def_map.borrow();
         match def_map.get().get_copy(&path_id) {
             ast::DefStaticMethod(..) => ck("static method"),
@@ -668,7 +748,7 @@ impl<'a> PrivacyVisitor<'a> {
             // is whether the trait itself is accessible or not.
             method_param(method_param { trait_id: trait_id, .. }) |
             method_object(method_object { trait_id: trait_id, .. }) => {
-                self.ensure_public(span, trait_id, None, "source trait");
+                self.report_error(self.ensure_public(span, trait_id, None, "source trait"));
             }
         }
     }
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 1d28c781ea0..327001fcd27 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
 use driver::session::Session;
 use metadata::csearch;
 use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
@@ -64,14 +63,34 @@ pub type ExternalExports = HashSet<DefId>;
 pub type LastPrivateMap = HashMap<NodeId, LastPrivate>;
 
 pub enum LastPrivate {
+    LastMod(PrivateDep),
+    // `use` directives (imports) can refer to two separate definitions in the
+    // type and value namespaces. We record here the last private node for each
+    // and whether the import is in fact used for each.
+    // If the Option<PrivateDep> fields are None, it means there is no defintion
+    // in that namespace.
+    LastImport{value_priv: Option<PrivateDep>,
+               value_used: ImportUse,
+               type_priv: Option<PrivateDep>,
+               type_used: ImportUse},
+}
+
+pub enum PrivateDep {
     AllPublic,
     DependsOn(DefId),
 }
 
+// How an import is used.
+#[deriving(Eq)]
+pub enum ImportUse {
+    Unused,       // The import is not used.
+    Used,         // The import is used.
+}
+
 impl LastPrivate {
     fn or(self, other: LastPrivate) -> LastPrivate {
         match (self, other) {
-            (me, AllPublic) => me,
+            (me, LastMod(AllPublic)) => me,
             (_, other) => other,
         }
     }
@@ -84,7 +103,7 @@ enum PatternBindingMode {
     ArgumentIrrefutableMode,
 }
 
-#[deriving(Eq)]
+#[deriving(Eq, IterBytes)]
 enum Namespace {
     TypeNS,
     ValueNS
@@ -869,7 +888,7 @@ struct Resolver {
     // so as to avoid printing duplicate errors
     emit_errors: bool,
 
-    used_imports: HashSet<NodeId>,
+    used_imports: HashSet<(NodeId, Namespace)>,
 }
 
 struct BuildReducedGraphVisitor<'a> {
@@ -904,7 +923,7 @@ impl<'a> Visitor<ReducedGraphParent> for BuildReducedGraphVisitor<'a> {
 
 }
 
-struct UnusedImportCheckVisitor<'a> { resolver: &'a Resolver }
+struct UnusedImportCheckVisitor<'a> { resolver: &'a mut Resolver }
 
 impl<'a> Visitor<()> for UnusedImportCheckVisitor<'a> {
     fn visit_view_item(&mut self, vi: &ViewItem, _: ()) {
@@ -2152,7 +2171,7 @@ impl Resolver {
         // First, resolve the module path for the directive, if necessary.
         let container = if module_path.len() == 0 {
             // Use the crate root.
-            Some((self.graph_root.get_module(), AllPublic))
+            Some((self.graph_root.get_module(), LastMod(AllPublic)))
         } else {
             match self.resolve_module_path(module_,
                                            *module_path,
@@ -2257,6 +2276,12 @@ impl Resolver {
                directive.id,
                lp);
 
+        let lp = match lp {
+            LastMod(lp) => lp,
+            LastImport{..} => self.session.span_bug(directive.span,
+                                                    "Not expecting Import here, must be LastMod"),
+        };
+
         // We need to resolve both namespaces for this to succeed.
         //
 
@@ -2287,7 +2312,8 @@ impl Resolver {
 
         // Unless we managed to find a result in both namespaces (unlikely),
         // search imports as well.
-        let mut used_reexport = false;
+        let mut value_used_reexport = false;
+        let mut type_used_reexport = false;
         match (value_result, type_result) {
             (BoundResult(..), BoundResult(..)) => {} // Continue.
             _ => {
@@ -2342,7 +2368,7 @@ impl Resolver {
                                 }
                                 Some(target) => {
                                     let id = import_resolution.id(namespace);
-                                    this.used_imports.insert(id);
+                                    this.used_imports.insert((id, namespace));
                                     return BoundResult(target.target_module,
                                                        target.bindings);
                                 }
@@ -2354,12 +2380,12 @@ impl Resolver {
                         if value_result.is_unknown() {
                             value_result = get_binding(self, *import_resolution,
                                                        ValueNS);
-                            used_reexport = import_resolution.is_public.get();
+                            value_used_reexport = import_resolution.is_public.get();
                         }
                         if type_result.is_unknown() {
                             type_result = get_binding(self, *import_resolution,
                                                       TypeNS);
-                            used_reexport = import_resolution.is_public.get();
+                            type_used_reexport = import_resolution.is_public.get();
                         }
 
                     }
@@ -2375,7 +2401,8 @@ impl Resolver {
 
         // If we didn't find a result in the type namespace, search the
         // external modules.
-        let mut used_public = false;
+        let mut value_used_public = false;
+        let mut type_used_public = false;
         match type_result {
             BoundResult(..) => {}
             _ => {
@@ -2393,7 +2420,7 @@ impl Resolver {
                                 module);
                         type_result = BoundResult(containing_module,
                                                   name_bindings);
-                        used_public = true;
+                        type_used_public = true;
                     }
                 }
             }
@@ -2412,7 +2439,7 @@ impl Resolver {
                 import_resolution.value_target.set(
                     Some(Target::new(target_module, name_bindings)));
                 import_resolution.value_id.set(directive.id);
-                used_public = name_bindings.defined_in_public_namespace(ValueNS);
+                value_used_public = name_bindings.defined_in_public_namespace(ValueNS);
             }
             UnboundResult => { /* Continue. */ }
             UnknownResult => {
@@ -2426,7 +2453,7 @@ impl Resolver {
                 import_resolution.type_target.set(
                     Some(Target::new(target_module, name_bindings)));
                 import_resolution.type_id.set(directive.id);
-                used_public = name_bindings.defined_in_public_namespace(TypeNS);
+                type_used_public = name_bindings.defined_in_public_namespace(TypeNS);
             }
             UnboundResult => { /* Continue. */ }
             UnknownResult => {
@@ -2443,7 +2470,8 @@ impl Resolver {
             self.resolve_error(directive.span, msg);
             return Failed;
         }
-        let used_public = used_reexport || used_public;
+        let value_used_public = value_used_reexport || value_used_public;
+        let type_used_public = type_used_reexport || type_used_public;
 
         assert!(import_resolution.outstanding_references.get() >= 1);
         import_resolution.outstanding_references.set(
@@ -2452,28 +2480,33 @@ impl Resolver {
         // record what this import resolves to for later uses in documentation,
         // 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.
-        match import_resolution.value_target.get() {
+        let value_private = match import_resolution.value_target.get() {
             Some(target) => {
                 let def = target.bindings.def_for_namespace(ValueNS).unwrap();
                 let mut def_map = self.def_map.borrow_mut();
                 def_map.get().insert(directive.id, def);
                 let did = def_id_of_def(def);
-                self.last_private.insert(directive.id,
-                    if used_public {lp} else {DependsOn(did)});
-            }
-            None => {}
-        }
-        match import_resolution.type_target.get() {
+                if value_used_public {Some(lp)} else {Some(DependsOn(did))}
+            },
+            // AllPublic here and below is a dummy value, it should never be used because
+            // _exists is false.
+            None => None,
+        };
+        let type_private = match import_resolution.type_target.get() {
             Some(target) => {
                 let def = target.bindings.def_for_namespace(TypeNS).unwrap();
                 let mut def_map = self.def_map.borrow_mut();
                 def_map.get().insert(directive.id, def);
                 let did = def_id_of_def(def);
-                self.last_private.insert(directive.id,
-                    if used_public {lp} else {DependsOn(did)});
-            }
-            None => {}
-        }
+                if type_used_public {Some(lp)} else {Some(DependsOn(did))}
+            },
+            None => None,
+        };
+
+        self.last_private.insert(directive.id, LastImport{value_priv: value_private,
+                                                          value_used: Used,
+                                                          type_priv: type_private,
+                                                          type_used: Used});
 
         debug!("(resolving single import) successfully resolved import");
         return Success(());
@@ -2732,7 +2765,7 @@ impl Resolver {
                                                                    .get() {
                                                     Some(did) => {
                                                         closest_private =
-                                                            DependsOn(did);
+                                                            LastMod(DependsOn(did));
                                                     }
                                                     None => {}
                                                 }
@@ -2817,7 +2850,7 @@ impl Resolver {
                         // resolution process at index zero.
                         search_module = self.graph_root.get_module();
                         start_index = 0;
-                        last_private = AllPublic;
+                        last_private = LastMod(AllPublic);
                     }
                     UseLexicalScope => {
                         // This is not a crate-relative path. We resolve the
@@ -2839,7 +2872,7 @@ impl Resolver {
                             Success(containing_module) => {
                                 search_module = containing_module;
                                 start_index = 1;
-                                last_private = AllPublic;
+                                last_private = LastMod(AllPublic);
                             }
                         }
                     }
@@ -2848,9 +2881,9 @@ impl Resolver {
             Success(PrefixFound(containing_module, index)) => {
                 search_module = containing_module;
                 start_index = index;
-                last_private = DependsOn(containing_module.def_id
-                                                          .get()
-                                                          .unwrap());
+                last_private = LastMod(DependsOn(containing_module.def_id
+                                                                  .get()
+                                                                  .unwrap()));
             }
         }
 
@@ -2914,7 +2947,7 @@ impl Resolver {
                     Some(target) => {
                         debug!("(resolving item in lexical scope) using \
                                 import resolution");
-                        self.used_imports.insert(import_resolution.id(namespace));
+                        self.used_imports.insert((import_resolution.id(namespace), namespace));
                         return Success((target, false));
                     }
                 }
@@ -3199,7 +3232,7 @@ impl Resolver {
                     Some(target) => {
                         debug!("(resolving name in module) resolved to \
                                 import");
-                        self.used_imports.insert(import_resolution.id(namespace));
+                        self.used_imports.insert((import_resolution.id(namespace), namespace));
                         return Success((target, true));
                     }
                 }
@@ -3808,7 +3841,7 @@ impl Resolver {
                     // Associate this type parameter with
                     // the item that bound it
                     self.record_def(type_parameter.id,
-                                    (DefTyParamBinder(node_id), AllPublic));
+                                    (DefTyParamBinder(node_id), LastMod(AllPublic)));
                     // plain insert (no renaming)
                     let mut bindings = function_type_rib.bindings
                                                         .borrow_mut();
@@ -4269,7 +4302,7 @@ impl Resolver {
 
                         Some(&primitive_type) => {
                             result_def =
-                                Some((DefPrimTy(primitive_type), AllPublic));
+                                Some((DefPrimTy(primitive_type), LastMod(AllPublic)));
 
                             if path.segments
                                    .iter()
@@ -4438,7 +4471,7 @@ impl Resolver {
                             // will be able to distinguish variants from
                             // locals in patterns.
 
-                            self.record_def(pattern.id, (def, AllPublic));
+                            self.record_def(pattern.id, (def, LastMod(AllPublic)));
 
                             // Add the binding to the local ribs, if it
                             // doesn't already exist in the bindings list. (We
@@ -4632,10 +4665,10 @@ impl Resolver {
                         // the lookup happened only within the current module.
                         match def.def {
                             def @ DefVariant(..) | def @ DefStruct(..) => {
-                                return FoundStructOrEnumVariant(def, AllPublic);
+                                return FoundStructOrEnumVariant(def, LastMod(AllPublic));
                             }
                             def @ DefStatic(_, false) => {
-                                return FoundConst(def, AllPublic);
+                                return FoundConst(def, LastMod(AllPublic));
                             }
                             _ => {
                                 return BareIdentifierPatternUnresolved;
@@ -4711,7 +4744,7 @@ impl Resolver {
                                                       namespace,
                                                       span) {
                 Some(def) => {
-                    return Some((def, AllPublic));
+                    return Some((def, LastMod(AllPublic)));
                 }
                 None => {
                     // Continue.
@@ -4741,8 +4774,8 @@ impl Resolver {
                             // Found it. Stop the search here.
                             let p = child_name_bindings.defined_in_public_namespace(
                                             namespace);
-                            let lp = if p {AllPublic} else {
-                                DependsOn(def_id_of_def(def))
+                            let lp = if p {LastMod(AllPublic)} else {
+                                LastMod(DependsOn(def_id_of_def(def)))
                             };
                             return ChildNameDefinition(def, lp);
                         }
@@ -4764,8 +4797,8 @@ impl Resolver {
                             Some(def) => {
                                 // Found it.
                                 let id = import_resolution.id(namespace);
-                                self.used_imports.insert(id);
-                                return ImportNameDefinition(def, AllPublic);
+                                self.used_imports.insert((id, namespace));
+                                return ImportNameDefinition(def, LastMod(AllPublic));
                             }
                             None => {
                                 // This can happen with external impls, due to
@@ -4792,8 +4825,8 @@ impl Resolver {
                     match module.def_id.get() {
                         None => {} // Continue.
                         Some(def_id) => {
-                            let lp = if module.is_public {AllPublic} else {
-                                DependsOn(def_id)
+                            let lp = if module.is_public {LastMod(AllPublic)} else {
+                                LastMod(DependsOn(def_id))
                             };
                             return ChildNameDefinition(DefMod(def_id), lp);
                         }
@@ -4887,7 +4920,7 @@ impl Resolver {
                                                  0,
                                                  path.span,
                                                  PathSearch,
-                                                 AllPublic) {
+                                                 LastMod(AllPublic)) {
             Failed => {
                 let msg = format!("use of undeclared module `::{}`",
                                   self.idents_to_str(module_path_idents));
@@ -4983,7 +5016,7 @@ impl Resolver {
                         // This lookup is "all public" because it only searched
                         // for one identifier in the current module (couldn't
                         // have passed through reexports or anything like that.
-                        return Some((def, AllPublic));
+                        return Some((def, LastMod(AllPublic)));
                     }
                 }
             }
@@ -5194,8 +5227,8 @@ impl Resolver {
                                               format!("use of undeclared label `{}`",
                                                    token::get_name(label))),
                     Some(DlDef(def @ DefLabel(_))) => {
-                        // FIXME: is AllPublic correct?
-                        self.record_def(expr.id, (def, AllPublic))
+                        // Since this def is a label, it is never read.
+                        self.record_def(expr.id, (def, LastMod(AllPublic)))
                     }
                     Some(_) => {
                         self.session.span_bug(expr.span,
@@ -5353,7 +5386,7 @@ impl Resolver {
                     };
                     if candidate_traits.contains(&did) {
                         self.add_trait_info(&mut found_traits, did, name);
-                        self.used_imports.insert(import.type_id.get());
+                        self.used_imports.insert((import.type_id.get(), TypeNS));
                     }
                 }
 
@@ -5395,6 +5428,8 @@ impl Resolver {
     fn record_def(&mut self, node_id: NodeId, (def, lp): (Def, LastPrivate)) {
         debug!("(recording def) recording {:?} for {:?}, last private {:?}",
                 def, node_id, lp);
+        assert!(match lp {LastImport{..} => false, _ => true},
+                "Import should only be used for `use` directives");
         self.last_private.insert(node_id, lp);
         let mut def_map = self.def_map.borrow_mut();
         def_map.get().insert_or_update_with(node_id, def, |_, old_value| {
@@ -5426,16 +5461,17 @@ impl Resolver {
     //
     // Unused import checking
     //
-    // Although this is a lint pass, it lives in here because it depends on
-    // resolve data structures.
+    // Although this is mostly a lint pass, it lives in here because it depends on
+    // resolve data structures and because it finalises the privacy information for
+    // `use` directives.
     //
 
-    fn check_for_unused_imports(&self, krate: &ast::Crate) {
+    fn check_for_unused_imports(&mut self, krate: &ast::Crate) {
         let mut visitor = UnusedImportCheckVisitor{ resolver: self };
         visit::walk_crate(&mut visitor, krate, ());
     }
 
-    fn check_for_item_unused_imports(&self, vi: &ViewItem) {
+    fn check_for_item_unused_imports(&mut self, vi: &ViewItem) {
         // Ignore is_public import statements because there's no way to be sure
         // whether they're used or not. Also ignore imports with a dummy span
         // because this means that they were generated in some fashion by the
@@ -5448,29 +5484,73 @@ impl Resolver {
             ViewItemUse(ref path) => {
                 for p in path.iter() {
                     match p.node {
-                        ViewPathSimple(_, _, id) | ViewPathGlob(_, id) => {
-                            if !self.used_imports.contains(&id) {
-                                self.session.add_lint(UnusedImports,
-                                                      id, p.span,
-                                                      ~"unused import");
-                            }
-                        }
-
+                        ViewPathSimple(_, _, id) => self.finalize_import(id, p.span),
                         ViewPathList(_, ref list, _) => {
                             for i in list.iter() {
-                                if !self.used_imports.contains(&i.node.id) {
-                                    self.session.add_lint(UnusedImports,
-                                                          i.node.id, i.span,
-                                                          ~"unused import");
-                                }
+                                self.finalize_import(i.node.id, i.span);
                             }
-                        }
+                        },
+                        ViewPathGlob(_, id) => {
+                            if !self.used_imports.contains(&(id, TypeNS)) &&
+                               !self.used_imports.contains(&(id, ValueNS)) {
+                                self.session.add_lint(UnusedImports, id, p.span, ~"unused import");
+                            }
+                        },
                     }
                 }
             }
         }
     }
 
+    // We have information about whether `use` (import) directives are actually used now.
+    // If an import is not used at all, we signal a lint error. If an import is only used
+    // for a single namespace, we remove the other namespace from the recorded privacy
+    // information. That means in privacy.rs, we will only check imports and namespaces
+    // which are used. In particular, this means that if an import could name either a
+    // public or private item, we will check the correct thing, dependent on how the import
+    // is used.
+    fn finalize_import(&mut self, id: NodeId, span: Span) {
+        debug!("finalizing import uses for {}", self.session.codemap.span_to_snippet(span));
+
+        if !self.used_imports.contains(&(id, TypeNS)) &&
+           !self.used_imports.contains(&(id, ValueNS)) {
+            self.session.add_lint(UnusedImports, id, span, ~"unused import");
+        }
+
+        let (v_priv, t_priv) = match self.last_private.find(&id) {
+            Some(&LastImport{value_priv: v,
+                             value_used: _,
+                             type_priv: t,
+                             type_used: _}) => (v, t),
+            Some(_) => fail!("We should only have LastImport for `use` directives"),
+            _ => return,
+        };
+
+        let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
+            Used
+        } else {
+            Unused
+        };
+        let t_used = if self.used_imports.contains(&(id, TypeNS)) {
+            Used
+        } else {
+            Unused
+        };
+
+        match (v_priv, t_priv) {
+            // Since some items may be both in the value _and_ type namespaces (e.g., structs)
+            // we might have two LastPrivates pointing at the same thing. There is no point
+            // checking both, so lets not check the value one.
+            (Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused,
+            _ => {},
+        }
+
+        self.last_private.insert(id, LastImport{value_priv: v_priv,
+                                                value_used: v_used,
+                                                type_priv: t_priv,
+                                                type_used: t_used});
+    }
+
     //
     // Diagnostics
     //
diff --git a/src/test/compile-fail/privacy-ns1.rs b/src/test/compile-fail/privacy-ns1.rs
new file mode 100644
index 00000000000..541356f6599
--- /dev/null
+++ b/src/test/compile-fail/privacy-ns1.rs
@@ -0,0 +1,66 @@
+// Copyright 2014 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.
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_glob1() {
+    use foo1::*;
+
+    Bar();  //~ ERROR unresolved name `Bar`.
+}
+
+// private type, public value
+pub mod foo2 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_glob2() {
+    use foo2::*;
+
+    let _x: ~Bar;  //~ ERROR use of undeclared type name `Bar`
+}
+
+// neither public
+pub mod foo3 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_glob3() {
+    use foo3::*;
+
+    Bar();  //~ ERROR unresolved name `Bar`.
+    let _x: ~Bar;  //~ ERROR  use of undeclared type name `Bar`
+}
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/privacy-ns2.rs b/src/test/compile-fail/privacy-ns2.rs
new file mode 100644
index 00000000000..e293153e9da
--- /dev/null
+++ b/src/test/compile-fail/privacy-ns2.rs
@@ -0,0 +1,91 @@
+// Copyright 2014 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.
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_single1() {
+    // In an ideal world, these would be private instead of inaccessible.
+    use foo1::Bar;  //~ ERROR `Bar` is inaccessible
+
+    Bar();
+}
+
+fn test_list1() {
+    use foo1::{Bar,Baz};  //~ ERROR `Bar` is inaccessible
+
+    Bar();
+}
+
+// private type, public value
+pub mod foo2 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_single2() {
+    use foo2::Bar;  //~ ERROR `Bar` is private
+
+    let _x : ~Bar;
+}
+
+fn test_list2() {
+    use foo2::{Bar,Baz};  //~ ERROR `Bar` is private
+
+    let _x: ~Bar;
+}
+
+// neither public
+pub mod foo3 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_unused3() {
+    use foo3::Bar;  //~ ERROR `Bar` is private
+    use foo3::{Bar,Baz};  //~ ERROR `Bar` is private
+}
+
+fn test_single3() {
+    use foo3::Bar;  //~ ERROR `Bar` is private
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn test_list3() {
+    use foo3::{Bar,Baz};  //~ ERROR `Bar` is private
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn main() {
+}
+
diff --git a/src/test/run-pass/privacy-ns.rs b/src/test/run-pass/privacy-ns.rs
new file mode 100644
index 00000000000..c933e5bc919
--- /dev/null
+++ b/src/test/run-pass/privacy-ns.rs
@@ -0,0 +1,124 @@
+// Copyright 2014 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.
+
+// ignore-fast
+
+// Check we do the correct privacy checks when we import a name and there is an
+// item with that name in both the value and type namespaces.
+
+#[feature(globs)];
+#[allow(dead_code)];
+#[allow(unused_imports)];
+
+// public type, private value
+pub mod foo1 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    fn Bar() { }
+}
+
+fn test_unused1() {
+    use foo1::Bar;
+    use foo1::{Bar,Baz};
+    use foo1::*;
+}
+
+fn test_single1() {
+    use foo1::Bar;
+
+    let _x: ~Bar;
+}
+
+fn test_list1() {
+    use foo1::{Bar,Baz};
+
+    let _x: ~Bar;
+}
+
+fn test_glob1() {
+    use foo1::*;
+
+    let _x: ~Bar;
+}
+
+// private type, public value
+pub mod foo2 {
+    trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_unused2() {
+    use foo2::Bar;
+    use foo2::{Bar,Baz};
+    use foo2::*;
+}
+
+fn test_single2() {
+    use foo2::Bar;
+
+    Bar();
+}
+
+fn test_list2() {
+    use foo2::{Bar,Baz};
+
+    Bar();
+}
+
+fn test_glob2() {
+    use foo2::*;
+
+    Bar();
+}
+
+// public type, public value
+pub mod foo3 {
+    pub trait Bar {
+    }
+    pub struct Baz;
+
+    pub fn Bar() { }
+}
+
+fn test_unused3() {
+    use foo3::Bar;
+    use foo3::{Bar,Baz};
+    use foo3::*;
+}
+
+fn test_single3() {
+    use foo3::Bar;
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn test_list3() {
+    use foo3::{Bar,Baz};
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn test_glob3() {
+    use foo3::*;
+
+    Bar();
+    let _x: ~Bar;
+}
+
+fn main() {
+}
+