diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index dc44a943e4cf8..3a6fabc33ab5d 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -258,8 +258,13 @@ impl Path {
 
 impl fmt::Debug for Path {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "path({})",
-               print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
+        write!(f, "path({})", print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
+    }
+}
+
+impl fmt::Display for Path {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
     }
 }
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index d41881218129f..5b277402f1e03 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -614,6 +614,7 @@ struct TypePrivacyVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tables: &'a ty::TypeckTables<'tcx>,
     current_item: DefId,
+    in_body: bool,
     span: Span,
     empty_tables: &'a ty::TypeckTables<'tcx>,
 }
@@ -671,10 +672,8 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
     // Take node ID of an expression or pattern and check its type for privacy.
     fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
         self.span = span;
-        if let Some(ty) = self.tables.node_id_to_type_opt(id) {
-            if ty.visit_with(self) {
-                return true;
-            }
+        if self.tables.node_id_to_type(id).visit_with(self) {
+            return true;
         }
         if self.tables.node_substs(id).visit_with(self) {
             return true;
@@ -688,6 +687,16 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
         }
         false
     }
+
+    fn check_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
+        if !self.item_is_accessible(trait_ref.def_id) {
+            let msg = format!("trait `{}` is private", trait_ref);
+            self.tcx.sess.span_err(self.span, &msg);
+            return true;
+        }
+
+        trait_ref.super_visit_with(self)
+    }
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
@@ -699,16 +708,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
 
     fn visit_nested_body(&mut self, body: hir::BodyId) {
         let orig_tables = replace(&mut self.tables, self.tcx.body_tables(body));
+        let orig_in_body = replace(&mut self.in_body, true);
         let body = self.tcx.hir.body(body);
         self.visit_body(body);
         self.tables = orig_tables;
+        self.in_body = orig_in_body;
     }
 
     fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty) {
         self.span = hir_ty.span;
-        if let Some(ty) = self.tables.node_id_to_type_opt(hir_ty.hir_id) {
+        if self.in_body {
             // Types in bodies.
-            if ty.visit_with(self) {
+            if self.tables.node_id_to_type(hir_ty.hir_id).visit_with(self) {
                 return;
             }
         } else {
@@ -724,10 +735,21 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
     }
 
     fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
-        if !self.item_is_accessible(trait_ref.path.def.def_id()) {
-            let msg = format!("trait `{:?}` is private", trait_ref.path);
-            self.tcx.sess.span_err(self.span, &msg);
-            return;
+        self.span = trait_ref.path.span;
+        if !self.in_body {
+            // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
+            // The traits' privacy in bodies is already checked as a part of trait object types.
+            let (principal, projections) =
+                rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
+            if self.check_trait_ref(*principal.skip_binder()) {
+                return;
+            }
+            for poly_predicate in projections {
+                let tcx = self.tcx;
+                if self.check_trait_ref(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
+                    return;
+                }
+            }
         }
 
         intravisit::walk_trait_ref(self, trait_ref);
@@ -760,19 +782,35 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
         intravisit::walk_expr(self, expr);
     }
 
+    // Prohibit access to associated items with insufficient nominal visibility.
+    //
+    // Additionally, until better reachability analysis for macros 2.0 is available,
+    // we prohibit access to private statics from other crates, this allows to give
+    // more code internal visibility at link time. (Access to private functions
+    // is already prohibited by type privacy for funciton types.)
     fn visit_qpath(&mut self, qpath: &'tcx hir::QPath, id: ast::NodeId, span: Span) {
-        // Inherent associated constants don't have self type in substs,
-        // we have to check it additionally.
-        if let hir::QPath::TypeRelative(..) = *qpath {
-            let hir_id = self.tcx.hir.node_to_hir_id(id);
-            if let Some(def) = self.tables.type_dependent_defs().get(hir_id).cloned() {
-                if let Some(assoc_item) = self.tcx.opt_associated_item(def.def_id()) {
-                    if let ty::ImplContainer(impl_def_id) = assoc_item.container {
-                        if self.tcx.type_of(impl_def_id).visit_with(self) {
-                            return;
-                        }
-                    }
-                }
+        let def = match *qpath {
+            hir::QPath::Resolved(_, ref path) => match path.def {
+                Def::Method(..) | Def::AssociatedConst(..) |
+                Def::AssociatedTy(..) | Def::Static(..) => Some(path.def),
+                _ => None,
+            }
+            hir::QPath::TypeRelative(..) => {
+                let hir_id = self.tcx.hir.node_to_hir_id(id);
+                self.tables.type_dependent_defs().get(hir_id).cloned()
+            }
+        };
+        if let Some(def) = def {
+            let def_id = def.def_id();
+            let is_local_static = if let Def::Static(..) = def { def_id.is_local() } else { false };
+            if !self.item_is_accessible(def_id) && !is_local_static {
+                let name = match *qpath {
+                    hir::QPath::Resolved(_, ref path) => format!("{}", path),
+                    hir::QPath::TypeRelative(_, ref segment) => segment.name.to_string(),
+                };
+                let msg = format!("{} `{}` is private", def.kind_name(), name);
+                self.tcx.sess.span_err(span, &msg);
+                return;
             }
         }
 
@@ -807,9 +845,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
                                         item.id,
                                         &mut self.tables,
                                         self.empty_tables);
+        let orig_in_body = replace(&mut self.in_body, false);
         self.current_item = self.tcx.hir.local_def_id(item.id);
         intravisit::walk_item(self, item);
         self.tables = orig_tables;
+        self.in_body = orig_in_body;
         self.current_item = orig_current_item;
     }
 
@@ -869,13 +909,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
                 }
             }
             ty::TyProjection(ref proj) => {
-                let trait_ref = proj.trait_ref(self.tcx);
-                if !self.item_is_accessible(trait_ref.def_id) {
-                    let msg = format!("trait `{}` is private", trait_ref);
-                    self.tcx.sess.span_err(self.span, &msg);
-                    return true;
-                }
-                if trait_ref.super_visit_with(self) {
+                let tcx = self.tcx;
+                if self.check_trait_ref(proj.trait_ref(tcx)) {
                     return true;
                 }
             }
@@ -1278,6 +1313,7 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
     min_visibility: ty::Visibility,
     has_pub_restricted: bool,
     has_old_errors: bool,
+    in_assoc_ty: bool,
 }
 
 impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
@@ -1338,11 +1374,11 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
                 self.min_visibility = vis;
             }
             if !vis.is_at_least(self.required_visibility, self.tcx) {
-                if self.has_pub_restricted || self.has_old_errors {
+                if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
                     struct_span_err!(self.tcx.sess, self.span, E0445,
                                      "private trait `{}` in public interface", trait_ref)
                         .span_label(self.span, format!(
-                                    "private trait can't be public"))
+                                    "can't leak private trait"))
                         .emit();
                 } else {
                     self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC,
@@ -1393,7 +1429,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
                     self.min_visibility = vis;
                 }
                 if !vis.is_at_least(self.required_visibility, self.tcx) {
-                    if self.has_pub_restricted || self.has_old_errors {
+                    if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
                         let mut err = struct_span_err!(self.tcx.sess, self.span, E0446,
                             "private type `{}` in public interface", ty);
                         err.span_label(self.span, "can't leak private type");
@@ -1454,6 +1490,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
             required_visibility,
             has_pub_restricted: self.has_pub_restricted,
             has_old_errors,
+            in_assoc_ty: false,
         }
     }
 }
@@ -1494,6 +1531,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
 
                 for trait_item_ref in trait_item_refs {
                     let mut check = self.check(trait_item_ref.id.node_id, item_visibility);
+                    check.in_assoc_ty = trait_item_ref.kind == hir::AssociatedItemKind::Type;
                     check.generics().predicates();
 
                     if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
@@ -1544,10 +1582,10 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
 
                 for impl_item_ref in impl_item_refs {
                     let impl_item = self.tcx.hir.impl_item(impl_item_ref.id);
-                    let impl_item_vis =
-                        ty::Visibility::from_hir(&impl_item.vis, item.id, tcx);
-                    self.check(impl_item.id, min(impl_item_vis, ty_vis))
-                        .generics().predicates().ty();
+                    let impl_item_vis = ty::Visibility::from_hir(&impl_item.vis, item.id, tcx);
+                    let mut check = self.check(impl_item.id, min(impl_item_vis, ty_vis));
+                    check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type;
+                    check.generics().predicates().ty();
 
                     // Recurse for e.g. `impl Trait` (see `visit_ty`).
                     self.inner_visibility = impl_item_vis;
@@ -1562,7 +1600,9 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
                 self.check(item.id, vis).generics().predicates();
                 for impl_item_ref in impl_item_refs {
                     let impl_item = self.tcx.hir.impl_item(impl_item_ref.id);
-                    self.check(impl_item.id, vis).generics().predicates().ty();
+                    let mut check = self.check(impl_item.id, vis);
+                    check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type;
+                    check.generics().predicates().ty();
 
                     // Recurse for e.g. `impl Trait` (see `visit_ty`).
                     self.inner_visibility = vis;
@@ -1629,6 +1669,7 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         tcx,
         tables: &empty_tables,
         current_item: DefId::local(CRATE_DEF_INDEX),
+        in_body: false,
         span: krate.span,
         empty_tables: &empty_tables,
     };
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 6b37a30cb82d8..cc79ae54c6bc8 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -347,13 +347,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         }
     }
 
-    pub fn instantiate_poly_trait_ref(&self,
-        ast_trait_ref: &hir::PolyTraitRef,
+    pub(super) fn instantiate_poly_trait_ref_inner(&self,
+        trait_ref: &hir::TraitRef,
         self_ty: Ty<'tcx>,
-        poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+        poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>,
+        speculative: bool)
         -> ty::PolyTraitRef<'tcx>
     {
-        let trait_ref = &ast_trait_ref.trait_ref;
         let trait_def_id = self.trait_def_id(trait_ref);
 
         debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
@@ -370,7 +370,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         poly_projections.extend(assoc_bindings.iter().filter_map(|binding| {
             // specify type to assert that error was already reported in Err case:
             let predicate: Result<_, ErrorReported> =
-                self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref, binding);
+                self.ast_type_binding_to_poly_projection_predicate(trait_ref.ref_id, poly_trait_ref,
+                                                                   binding, speculative);
             predicate.ok() // ok to ignore Err() because ErrorReported (see above)
         }));
 
@@ -379,6 +380,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         poly_trait_ref
     }
 
+    pub fn instantiate_poly_trait_ref(&self,
+        poly_trait_ref: &hir::PolyTraitRef,
+        self_ty: Ty<'tcx>,
+        poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
+        -> ty::PolyTraitRef<'tcx>
+    {
+        self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty,
+                                              poly_projections, false)
+    }
+
     fn ast_path_to_mono_trait_ref(&self,
                                   span: Span,
                                   trait_def_id: DefId,
@@ -442,82 +453,87 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
     fn ast_type_binding_to_poly_projection_predicate(
         &self,
+        ref_id: ast::NodeId,
         trait_ref: ty::PolyTraitRef<'tcx>,
-        binding: &ConvertedBinding<'tcx>)
+        binding: &ConvertedBinding<'tcx>,
+        speculative: bool)
         -> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
     {
         let tcx = self.tcx();
 
-        // Given something like `U : SomeTrait<T=X>`, we want to produce a
-        // predicate like `<U as SomeTrait>::T = X`. This is somewhat
-        // subtle in the event that `T` is defined in a supertrait of
-        // `SomeTrait`, because in that case we need to upcast.
-        //
-        // That is, consider this case:
-        //
-        // ```
-        // trait SubTrait : SuperTrait<int> { }
-        // trait SuperTrait<A> { type T; }
-        //
-        // ... B : SubTrait<T=foo> ...
-        // ```
-        //
-        // We want to produce `<B as SuperTrait<int>>::T == foo`.
-
-        // Find any late-bound regions declared in `ty` that are not
-        // declared in the trait-ref. These are not wellformed.
-        //
-        // Example:
-        //
-        //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
-        //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
-        let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
-        let late_bound_in_ty = tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty));
-        debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
-        debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
-        for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
-            let br_name = match *br {
-                ty::BrNamed(_, name) => name,
-                _ => {
-                    span_bug!(
-                        binding.span,
-                        "anonymous bound region {:?} in binding but not trait ref",
-                        br);
-                }
-            };
-            struct_span_err!(tcx.sess,
-                             binding.span,
-                             E0582,
-                             "binding for associated type `{}` references lifetime `{}`, \
-                              which does not appear in the trait input types",
-                             binding.item_name, br_name)
-                .emit();
+        if !speculative {
+            // Given something like `U : SomeTrait<T=X>`, we want to produce a
+            // predicate like `<U as SomeTrait>::T = X`. This is somewhat
+            // subtle in the event that `T` is defined in a supertrait of
+            // `SomeTrait`, because in that case we need to upcast.
+            //
+            // That is, consider this case:
+            //
+            // ```
+            // trait SubTrait : SuperTrait<int> { }
+            // trait SuperTrait<A> { type T; }
+            //
+            // ... B : SubTrait<T=foo> ...
+            // ```
+            //
+            // We want to produce `<B as SuperTrait<int>>::T == foo`.
+
+            // Find any late-bound regions declared in `ty` that are not
+            // declared in the trait-ref. These are not wellformed.
+            //
+            // Example:
+            //
+            //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
+            //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
+            let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
+            let late_bound_in_ty =
+                tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty));
+            debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
+            debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+            for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
+                let br_name = match *br {
+                    ty::BrNamed(_, name) => name,
+                    _ => {
+                        span_bug!(
+                            binding.span,
+                            "anonymous bound region {:?} in binding but not trait ref",
+                            br);
+                    }
+                };
+                struct_span_err!(tcx.sess,
+                                binding.span,
+                                E0582,
+                                "binding for associated type `{}` references lifetime `{}`, \
+                                which does not appear in the trait input types",
+                                binding.item_name, br_name)
+                    .emit();
+            }
         }
 
-        // Simple case: X is defined in the current trait.
-        if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
-            return Ok(trait_ref.map_bound(|trait_ref| {
-                ty::ProjectionPredicate {
-                    projection_ty: ty::ProjectionTy::from_ref_and_name(
-                        tcx,
-                        trait_ref,
-                        binding.item_name,
-                    ),
-                    ty: binding.ty,
-                }
-            }));
+        let candidate = if self.trait_defines_associated_type_named(trait_ref.def_id(),
+                                                                    binding.item_name) {
+            // Simple case: X is defined in the current trait.
+            Ok(trait_ref)
+        } else {
+            // Otherwise, we have to walk through the supertraits to find
+            // those that do.
+            let candidates = traits::supertraits(tcx, trait_ref).filter(|r| {
+                self.trait_defines_associated_type_named(r.def_id(), binding.item_name)
+            });
+            self.one_bound_for_assoc_type(candidates, &trait_ref.to_string(),
+                                          binding.item_name, binding.span)
+        }?;
+
+        let (assoc_ident, def_scope) = tcx.adjust(binding.item_name, candidate.def_id(), ref_id);
+        let assoc_ty = tcx.associated_items(candidate.def_id()).find(|i| {
+            i.kind == ty::AssociatedKind::Type && i.name.to_ident() == assoc_ident
+        }).expect("missing associated type");
+
+        if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
+            let msg = format!("associated type `{}` is private", binding.item_name);
+            tcx.sess.span_err(binding.span, &msg);
         }
-
-        // Otherwise, we have to walk through the supertraits to find
-        // those that do.
-        let candidates =
-            traits::supertraits(tcx, trait_ref.clone())
-            .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name));
-
-        let candidate = self.one_bound_for_assoc_type(candidates,
-                                                      &trait_ref.to_string(),
-                                                      binding.item_name,
-                                                      binding.span)?;
+        tcx.check_stability(assoc_ty.def_id, ref_id, binding.span);
 
         Ok(candidate.map_bound(|trait_ref| {
             ty::ProjectionPredicate {
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index bf8f9d8b24a0d..31f3b4e699afd 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -348,7 +348,22 @@ pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) ->
     let env_node_id = tcx.hir.get_parent(hir_ty.id);
     let env_def_id = tcx.hir.local_def_id(env_node_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
-    item_cx.to_ty(hir_ty)
+    astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
+}
+
+pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: &hir::TraitRef)
+        -> (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjectionPredicate<'tcx>>) {
+    // In case there are any projections etc, find the "environment"
+    // def-id that will be used to determine the traits/predicates in
+    // scope.  This is derived from the enclosing item-like thing.
+    let env_node_id = tcx.hir.get_parent(hir_trait.ref_id);
+    let env_def_id = tcx.hir.local_def_id(env_node_id);
+    let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
+    let mut projections = Vec::new();
+    let principal = astconv::AstConv::instantiate_poly_trait_ref_inner(
+        &item_cx, hir_trait, tcx.types.err, &mut projections, true
+    );
+    (principal, projections)
 }
 
 __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
diff --git a/src/test/compile-fail/E0445.rs b/src/test/compile-fail/E0445.rs
index a1447e7ebcddc..bca1b52d17a92 100644
--- a/src/test/compile-fail/E0445.rs
+++ b/src/test/compile-fail/E0445.rs
@@ -14,9 +14,12 @@ trait Foo {
 
 pub trait Bar : Foo {}
 //~^ ERROR private trait `Foo` in public interface [E0445]
+//~| NOTE can't leak private trait
 pub struct Bar2<T: Foo>(pub T);
 //~^ ERROR private trait `Foo` in public interface [E0445]
+//~| NOTE can't leak private trait
 pub fn foo<T: Foo> (t: T) {}
 //~^ ERROR private trait `Foo` in public interface [E0445]
+//~| NOTE can't leak private trait
 
 fn main() {}
diff --git a/src/test/compile-fail/auxiliary/private-inferred-type.rs b/src/test/compile-fail/auxiliary/private-inferred-type.rs
index 7627f5dc0cd09..fc43765f63ce8 100644
--- a/src/test/compile-fail/auxiliary/private-inferred-type.rs
+++ b/src/test/compile-fail/auxiliary/private-inferred-type.rs
@@ -11,6 +11,7 @@
 #![feature(decl_macro)]
 
 fn priv_fn() {}
+static PRIV_STATIC: u8 = 0;
 enum PrivEnum { Variant }
 pub enum PubEnum { Variant }
 trait PrivTrait { fn method() {} }
@@ -34,6 +35,7 @@ impl Pub<u8> {
 
 pub macro m() {
     priv_fn;
+    PRIV_STATIC;
     PrivEnum::Variant;
     PubEnum::Variant;
     <u8 as PrivTrait>::method;
diff --git a/src/test/compile-fail/issue-30079.rs b/src/test/compile-fail/issue-30079.rs
index 15b7edb32d41d..04ae8f6d255d0 100644
--- a/src/test/compile-fail/issue-30079.rs
+++ b/src/test/compile-fail/issue-30079.rs
@@ -8,15 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![deny(private_in_public)]
-#![allow(unused)]
-
 struct SemiPriv;
 
 mod m1 {
     struct Priv;
     impl ::SemiPriv {
-        pub fn f(_: Priv) {} //~ ERROR private type `m1::Priv` in public interface
+        pub fn f(_: Priv) {} //~ WARN private type `m1::Priv` in public interface
         //~^ WARNING hard error
     }
 
@@ -29,7 +26,6 @@ mod m2 {
     struct Priv;
     impl ::std::ops::Deref for ::SemiPriv {
         type Target = Priv; //~ ERROR private type `m2::Priv` in public interface
-        //~^ WARNING hard error
         fn deref(&self) -> &Self::Target { unimplemented!() }
     }
 
@@ -47,7 +43,6 @@ mod m3 {
     struct Priv;
     impl ::SemiPrivTrait for () {
         type Assoc = Priv; //~ ERROR private type `m3::Priv` in public interface
-        //~^ WARNING hard error
     }
 }
 
diff --git a/src/test/compile-fail/lint-stability-deprecated.rs b/src/test/compile-fail/lint-stability-deprecated.rs
index df5c3dddcde32..f2defc1d421b0 100644
--- a/src/test/compile-fail/lint-stability-deprecated.rs
+++ b/src/test/compile-fail/lint-stability-deprecated.rs
@@ -108,6 +108,11 @@ mod cross_crate {
         struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
         struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
         //~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
+        type A = TraitWithAssociatedTypes<
+            TypeUnstable = u8,
+            TypeDeprecated = u16,
+            //~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated'
+        >;
 
         let _ = DeprecatedStruct { //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct'
             i: 0 //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct::i'
diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs
index 1ece7a0b8e334..49a52204295e5 100644
--- a/src/test/compile-fail/lint-stability.rs
+++ b/src/test/compile-fail/lint-stability.rs
@@ -96,6 +96,10 @@ mod cross_crate {
         struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
         //~^ ERROR use of unstable library feature
         struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
+        type A = TraitWithAssociatedTypes<
+            TypeUnstable = u8, //~ ERROR use of unstable library feature
+            TypeDeprecated = u16,
+        >;
 
         let _ = DeprecatedStruct {
             i: 0
diff --git a/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs b/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs
new file mode 100644
index 0000000000000..63cb6e82c259e
--- /dev/null
+++ b/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs
@@ -0,0 +1,122 @@
+// Copyright 2017 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.
+
+#![feature(decl_macro, associated_type_defaults)]
+#![allow(unused, private_in_public)]
+
+mod priv_nominal {
+    pub struct Pub;
+    impl Pub {
+        fn method(&self) {}
+        const CONST: u8 = 0;
+        // type AssocTy = u8;
+    }
+
+    pub macro mac() {
+        let value = Pub::method;
+        //~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
+        value;
+        //~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
+        Pub.method();
+        //~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
+        Pub::CONST;
+        //~^ ERROR associated constant `CONST` is private
+        // let _: Pub::AssocTy;
+        // pub type InSignatureTy = Pub::AssocTy;
+    }
+}
+fn priv_nominal() {
+    priv_nominal::mac!();
+}
+
+mod priv_signature {
+    struct Priv;
+    pub struct Pub;
+    impl Pub {
+        pub fn method(&self, arg: Priv) {}
+    }
+
+    pub macro mac() {
+        let value = Pub::method;
+        //~^ ERROR type `priv_signature::Priv` is private
+        value;
+        //~^ ERROR type `priv_signature::Priv` is private
+        Pub.method(loop {});
+        //~^ ERROR type `priv_signature::Priv` is private
+    }
+}
+fn priv_signature() {
+    priv_signature::mac!();
+}
+
+mod priv_substs {
+    struct Priv;
+    pub struct Pub;
+    impl Pub {
+        pub fn method<T>(&self) {}
+    }
+
+    pub macro mac() {
+        let value = Pub::method::<Priv>;
+        //~^ ERROR type `priv_substs::Priv` is private
+        value;
+        //~^ ERROR type `priv_substs::Priv` is private
+        Pub.method::<Priv>();
+        //~^ ERROR type `priv_substs::Priv` is private
+    }
+}
+fn priv_substs() {
+    priv_substs::mac!();
+}
+
+mod priv_parent_substs {
+    struct Priv;
+    pub struct Pub<T = Priv>(T);
+    impl Pub<Priv> {
+        pub fn method(&self) {}
+        pub fn static_method() {}
+        pub const CONST: u8 = 0;
+        // pub type AssocTy = u8;
+    }
+
+    pub macro mac() {
+        let value = <Pub>::method;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        value;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        let value = Pub::method;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        value;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        let value = <Pub>::static_method;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        value;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        let value = Pub::static_method;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        value;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        Pub(Priv).method();
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+
+        <Pub>::CONST;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        Pub::CONST;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+
+        // let _: Pub::AssocTy;
+        // pub type InSignatureTy = Pub::AssocTy;
+    }
+}
+fn priv_parent_substs() {
+    priv_parent_substs::mac!();
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/privacy/associated-item-privacy-trait.rs b/src/test/compile-fail/privacy/associated-item-privacy-trait.rs
new file mode 100644
index 0000000000000..bdc0c680a92bc
--- /dev/null
+++ b/src/test/compile-fail/privacy/associated-item-privacy-trait.rs
@@ -0,0 +1,151 @@
+// Copyright 2017 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-tidy-linelength
+
+#![feature(decl_macro, associated_type_defaults)]
+#![allow(unused, private_in_public)]
+
+mod priv_trait {
+    trait PrivTr {
+        fn method(&self) {}
+        const CONST: u8 = 0;
+        type AssocTy = u8;
+    }
+    pub struct Pub;
+    impl PrivTr for Pub {}
+    pub trait PubTr: PrivTr {}
+
+    pub macro mac() {
+        let value = <Pub as PrivTr>::method;
+        //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {<priv_trait::Pub as priv_trait::PrivTr>::method}` is private
+        value;
+        //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {<priv_trait::Pub as priv_trait::PrivTr>::method}` is private
+        Pub.method();
+        //~^ ERROR type `for<'r> fn(&'r Self) {<Self as priv_trait::PrivTr>::method}` is private
+        <Pub as PrivTr>::CONST;
+        //~^ ERROR associated constant `PrivTr::CONST` is private
+        let _: <Pub as PrivTr>::AssocTy;
+        //~^ ERROR trait `priv_trait::PrivTr` is private
+        //~| ERROR trait `priv_trait::PrivTr` is private
+        pub type InSignatureTy = <Pub as PrivTr>::AssocTy;
+        //~^ ERROR trait `priv_trait::PrivTr` is private
+        pub trait InSignatureTr: PrivTr {}
+        //~^ ERROR trait `priv_trait::PrivTr` is private
+        impl PrivTr for u8 {}
+        //~^ ERROR trait `priv_trait::PrivTr` is private
+    }
+}
+fn priv_trait() {
+    priv_trait::mac!();
+}
+
+mod priv_signature {
+    pub trait PubTr {
+        fn method(&self, arg: Priv) {}
+    }
+    struct Priv;
+    pub struct Pub;
+    impl PubTr for Pub {}
+
+    pub macro mac() {
+        let value = <Pub as PubTr>::method;
+        //~^ ERROR type `priv_signature::Priv` is private
+        value;
+        //~^ ERROR type `priv_signature::Priv` is private
+        Pub.method(loop {});
+        //~^ ERROR type `priv_signature::Priv` is private
+    }
+}
+fn priv_signature() {
+    priv_signature::mac!();
+}
+
+mod priv_substs {
+    pub trait PubTr {
+        fn method<T>(&self) {}
+    }
+    struct Priv;
+    pub struct Pub;
+    impl PubTr for Pub {}
+
+    pub macro mac() {
+        let value = <Pub as PubTr>::method::<Priv>;
+        //~^ ERROR type `priv_substs::Priv` is private
+        value;
+        //~^ ERROR type `priv_substs::Priv` is private
+        Pub.method::<Priv>();
+        //~^ ERROR type `priv_substs::Priv` is private
+    }
+}
+fn priv_substs() {
+    priv_substs::mac!();
+}
+
+mod priv_parent_substs {
+    pub trait PubTr<T = Priv> {
+        fn method(&self) {}
+        const CONST: u8 = 0;
+        type AssocTy = u8;
+    }
+    struct Priv;
+    pub struct Pub;
+    impl PubTr<Priv> for Pub {}
+    impl PubTr<Pub> for Priv {}
+
+    pub macro mac() {
+        let value = <Pub as PubTr>::method;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        value;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        let value = <Pub as PubTr<_>>::method;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        value;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        Pub.method();
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+
+        let value = <Priv as PubTr<_>>::method;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        value;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        Priv.method();
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+
+        <Pub as PubTr>::CONST;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        <Pub as PubTr<_>>::CONST;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        <Priv as PubTr<_>>::CONST;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+
+        let _: <Pub as PubTr>::AssocTy;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        //~| ERROR type `priv_parent_substs::Priv` is private
+        let _: <Pub as PubTr<_>>::AssocTy;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        //~| ERROR type `priv_parent_substs::Priv` is private
+        let _: <Priv as PubTr<_>>::AssocTy;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        //~| ERROR type `priv_parent_substs::Priv` is private
+
+        pub type InSignatureTy1 = <Pub as PubTr>::AssocTy;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        pub type InSignatureTy2 = <Priv as PubTr<Pub>>::AssocTy;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        impl PubTr for u8 {}
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+    }
+}
+fn priv_parent_substs() {
+    priv_parent_substs::mac!();
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs b/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs
new file mode 100644
index 0000000000000..c25616c54354d
--- /dev/null
+++ b/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs
@@ -0,0 +1,74 @@
+// Copyright 2017 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.
+
+#![feature(decl_macro, associated_type_defaults)]
+#![allow(unused, private_in_public)]
+
+mod priv_trait {
+    trait PrivTr {
+        type AssocTy = u8;
+    }
+    pub trait PubTr: PrivTr {}
+
+    pub macro mac1() {
+        let _: Box<PubTr<AssocTy = u8>>;
+        //~^ ERROR type `priv_trait::PubTr<AssocTy=u8> + '<empty>` is private
+        //~| ERROR type `priv_trait::PubTr<AssocTy=u8> + '<empty>` is private
+        type InSignatureTy2 = Box<PubTr<AssocTy = u8>>;
+        //~^ ERROR type `priv_trait::PubTr<AssocTy=u8> + 'static` is private
+        trait InSignatureTr2: PubTr<AssocTy = u8> {}
+        //~^ ERROR trait `priv_trait::PrivTr` is private
+    }
+    pub macro mac2() {
+        let _: Box<PrivTr<AssocTy = u8>>;
+        //~^ ERROR type `priv_trait::PrivTr<AssocTy=u8> + '<empty>` is private
+        //~| ERROR type `priv_trait::PrivTr<AssocTy=u8> + '<empty>` is private
+        type InSignatureTy1 = Box<PrivTr<AssocTy = u8>>;
+        //~^ ERROR type `priv_trait::PrivTr<AssocTy=u8> + 'static` is private
+        trait InSignatureTr1: PrivTr<AssocTy = u8> {}
+        //~^ ERROR trait `priv_trait::PrivTr` is private
+    }
+}
+fn priv_trait1() {
+    priv_trait::mac1!();
+}
+fn priv_trait2() {
+    priv_trait::mac2!();
+}
+
+mod priv_parent_substs {
+    pub trait PubTrWithParam<T = Priv> {
+        type AssocTy = u8;
+    }
+    struct Priv;
+    pub trait PubTr: PubTrWithParam<Priv> {}
+
+    pub macro mac() {
+        let _: Box<PubTrWithParam<AssocTy = u8>>;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        //~| ERROR type `priv_parent_substs::Priv` is private
+        let _: Box<PubTr<AssocTy = u8>>;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        //~| ERROR type `priv_parent_substs::Priv` is private
+        pub type InSignatureTy1 = Box<PubTrWithParam<AssocTy = u8>>;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        pub type InSignatureTy2 = Box<PubTr<AssocTy = u8>>;
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        trait InSignatureTr1: PubTrWithParam<AssocTy = u8> {}
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+        trait InSignatureTr2: PubTr<AssocTy = u8> {}
+        //~^ ERROR type `priv_parent_substs::Priv` is private
+    }
+}
+fn priv_parent_substs() {
+    priv_parent_substs::mac!();
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/private-in-public-assoc-ty.rs b/src/test/compile-fail/private-in-public-assoc-ty.rs
new file mode 100644
index 0000000000000..59dee25664252
--- /dev/null
+++ b/src/test/compile-fail/private-in-public-assoc-ty.rs
@@ -0,0 +1,43 @@
+// Copyright 2017 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.
+
+// Private types and traits are not allowed in interfaces of associated types.
+// This test also ensures that the checks are performed even inside private modules.
+
+#![feature(associated_type_defaults)]
+
+mod m {
+    struct Priv;
+    trait PrivTr {}
+    impl PrivTr for Priv {}
+    pub trait PubTrAux1<T> {}
+    pub trait PubTrAux2 { type A; }
+
+    // "Private-in-public in associated types is hard error" in RFC 2145
+    // applies only to the aliased types, not bounds.
+    pub trait PubTr {
+        //~^ WARN private trait `m::PrivTr` in public interface
+        //~| WARN this was previously accepted
+        //~| WARN private type `m::Priv` in public interface
+        //~| WARN this was previously accepted
+        type Alias1: PrivTr;
+        type Alias2: PubTrAux1<Priv> = u8;
+        type Alias3: PubTrAux2<A = Priv> = u8;
+
+        type Alias4 = Priv;
+        //~^ ERROR private type `m::Priv` in public interface
+    }
+    impl PubTr for u8 {
+        type Alias1 = Priv;
+        //~^ ERROR private type `m::Priv` in public interface
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/private-in-public-ill-formed.rs b/src/test/compile-fail/private-in-public-ill-formed.rs
new file mode 100644
index 0000000000000..4e10614bf62c6
--- /dev/null
+++ b/src/test/compile-fail/private-in-public-ill-formed.rs
@@ -0,0 +1,45 @@
+// Copyright 2017 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.
+
+mod aliases_pub {
+    struct Priv;
+    mod m {
+        pub struct Pub3;
+    }
+
+    trait PrivTr {
+        type AssocAlias;
+    }
+    impl PrivTr for Priv {
+        type AssocAlias = m::Pub3;
+    }
+
+    impl (<Priv as PrivTr>::AssocAlias) { //~ ERROR no base type found for inherent implementation
+        pub fn f(arg: Priv) {} // private type `aliases_pub::Priv` in public interface
+    }
+}
+
+mod aliases_priv {
+    struct Priv;
+    struct Priv3;
+
+    trait PrivTr {
+        type AssocAlias;
+    }
+    impl PrivTr for Priv {
+        type AssocAlias = Priv3;
+    }
+
+    impl (<Priv as PrivTr>::AssocAlias) { //~ ERROR no base type found for inherent implementation
+        pub fn f(arg: Priv) {} // OK
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/private-in-public-warn.rs b/src/test/compile-fail/private-in-public-warn.rs
index f030012b172f0..dfcf4dc01b8ab 100644
--- a/src/test/compile-fail/private-in-public-warn.rs
+++ b/src/test/compile-fail/private-in-public-warn.rs
@@ -13,7 +13,6 @@
 
 #![feature(associated_type_defaults)]
 #![deny(private_in_public)]
-#![allow(unused)]
 #![allow(improper_ctypes)]
 
 mod types {
@@ -35,7 +34,6 @@ mod types {
         const C: Priv = Priv; //~ ERROR private type `types::Priv` in public interface
         //~^ WARNING hard error
         type Alias = Priv; //~ ERROR private type `types::Priv` in public interface
-        //~^ WARNING hard error
         fn f1(arg: Priv) {} //~ ERROR private type `types::Priv` in public interface
         //~^ WARNING hard error
         fn f2() -> Priv { panic!() } //~ ERROR private type `types::Priv` in public interface
@@ -51,7 +49,6 @@ mod types {
     }
     impl PubTr for Pub {
         type Alias = Priv; //~ ERROR private type `types::Priv` in public interface
-        //~^ WARNING hard error
     }
 }
 
@@ -146,7 +143,6 @@ mod impls {
     }
     impl PubTr for Pub {
         type Alias = Priv; //~ ERROR private type `impls::Priv` in public interface
-        //~^ WARNING hard error
     }
 }
 
@@ -220,21 +216,14 @@ mod aliases_pub {
         pub fn f(arg: Priv) {} //~ ERROR private type `aliases_pub::Priv` in public interface
         //~^ WARNING hard error
     }
-    // This doesn't even parse
-    // impl <Priv as PrivTr>::AssocAlias {
-    //     pub fn f(arg: Priv) {} // ERROR private type `aliases_pub::Priv` in public interface
-    // }
     impl PrivUseAliasTr for PrivUseAlias {
         type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface
-        //~^ WARNING hard error
     }
     impl PrivUseAliasTr for PrivAlias {
         type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface
-        //~^ WARNING hard error
     }
     impl PrivUseAliasTr for <Priv as PrivTr>::AssocAlias {
         type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface
-        //~^ WARNING hard error
     }
 }
 
@@ -273,10 +262,6 @@ mod aliases_priv {
     impl PrivAlias {
         pub fn f(arg: Priv) {} // OK
     }
-    // This doesn't even parse
-    // impl <Priv as PrivTr>::AssocAlias {
-    //     pub fn f(arg: Priv) {} // OK
-    // }
     impl PrivUseAliasTr for PrivUseAlias {
         type Check = Priv; // OK
     }
diff --git a/src/test/compile-fail/private-inferred-type-3.rs b/src/test/compile-fail/private-inferred-type-3.rs
index c0ba38b240202..0c393f02323ec 100644
--- a/src/test/compile-fail/private-inferred-type-3.rs
+++ b/src/test/compile-fail/private-inferred-type-3.rs
@@ -11,6 +11,7 @@
 // aux-build:private-inferred-type.rs
 
 // error-pattern:type `fn() {ext::priv_fn}` is private
+// error-pattern:static `PRIV_STATIC` is private
 // error-pattern:type `ext::PrivEnum` is private
 // error-pattern:type `fn() {<u8 as ext::PrivTrait>::method}` is private
 // error-pattern:type `fn(u8) -> ext::PrivTupleStruct {ext::PrivTupleStruct::{{constructor}}}` is pr
diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs
index 95e3732d61342..351dc6b776b21 100644
--- a/src/test/compile-fail/private-inferred-type.rs
+++ b/src/test/compile-fail/private-inferred-type.rs
@@ -11,10 +11,11 @@
 #![feature(associated_consts)]
 #![feature(conservative_impl_trait)]
 #![feature(decl_macro)]
-#![allow(warnings)]
+#![allow(private_in_public)]
 
 mod m {
     fn priv_fn() {}
+    static PRIV_STATIC: u8 = 0;
     enum PrivEnum { Variant }
     pub enum PubEnum { Variant }
     trait PrivTrait { fn method() {} }
@@ -47,6 +48,7 @@ mod m {
 
     pub macro m() {
         priv_fn; //~ ERROR type `fn() {m::priv_fn}` is private
+        PRIV_STATIC; // OK, not cross-crate
         PrivEnum::Variant; //~ ERROR type `m::PrivEnum` is private
         PubEnum::Variant; // OK
         <u8 as PrivTrait>::method; //~ ERROR type `fn() {<u8 as m::PrivTrait>::method}` is private
@@ -68,6 +70,7 @@ mod m {
     impl<T> TraitWithTyParam<T> for u8 {}
     impl TraitWithTyParam2<Priv> for u8 {}
     impl TraitWithAssocTy for u8 { type AssocTy = Priv; }
+    //~^ ERROR private type `m::Priv` in public interface
 
     pub fn leak_anon1() -> impl Trait + 'static { 0 }
     pub fn leak_anon2() -> impl TraitWithTyParam<Alias> { 0 }
@@ -88,7 +91,7 @@ mod adjust {
     pub struct S3;
 
     impl Deref for S1 {
-        type Target = S2Alias;
+        type Target = S2Alias; //~ ERROR private type `adjust::S2` in public interface
         fn deref(&self) -> &Self::Target { loop {} }
     }
     impl Deref for S2 {
diff --git a/src/test/compile-fail/trait-item-privacy.rs b/src/test/compile-fail/trait-item-privacy.rs
index b8d83e5adf23d..be0f7dd4e1cd7 100644
--- a/src/test/compile-fail/trait-item-privacy.rs
+++ b/src/test/compile-fail/trait-item-privacy.rs
@@ -131,6 +131,16 @@ fn check_assoc_ty<T: assoc_ty::C>() {
     let _: T::A; //~ ERROR associated type `A` is private
     let _: T::B; // OK
     let _: T::C; // OK
+
+    // Associated types, bindings
+    let _: assoc_ty::B<
+        B = u8, // OK
+    >;
+    let _: C<
+        A = u8, //~ ERROR associated type `A` is private
+        B = u8, // OK
+        C = u8, // OK
+    >;
 }
 
 fn main() {}