about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libproc_macro/quote.rs2
-rw-r--r--src/librustc_privacy/lib.rs352
-rw-r--r--src/test/compile-fail/auxiliary/private-inferred-type.rs44
-rw-r--r--src/test/compile-fail/hygiene/auxiliary/intercrate.rs (renamed from src/test/run-pass/hygiene/auxiliary/intercrate.rs)0
-rw-r--r--src/test/compile-fail/hygiene/fields.rs (renamed from src/test/run-pass/hygiene/fields.rs)8
-rw-r--r--src/test/compile-fail/hygiene/impl_items.rs (renamed from src/test/run-pass/hygiene/impl_items.rs)2
-rw-r--r--src/test/compile-fail/hygiene/intercrate.rs (renamed from src/test/run-pass/hygiene/intercrate.rs)2
-rw-r--r--src/test/compile-fail/private-inferred-type-1.rs28
-rw-r--r--src/test/compile-fail/private-inferred-type-2.rs29
-rw-r--r--src/test/compile-fail/private-inferred-type-3.rs26
-rw-r--r--src/test/compile-fail/private-inferred-type.rs139
-rw-r--r--src/test/compile-fail/private-type-in-interface.rs41
12 files changed, 665 insertions, 8 deletions
diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs
index bee2c1e0eb6..0db2b86b15f 100644
--- a/src/libproc_macro/quote.rs
+++ b/src/libproc_macro/quote.rs
@@ -87,7 +87,7 @@ impl ProcMacro for Quoter {
         let mut info = cx.current_expansion.mark.expn_info().unwrap();
         info.callee.allow_internal_unstable = true;
         cx.current_expansion.mark.set_expn_info(info);
-        ::__internal::set_sess(cx, || quote!(::TokenStream((quote stream))))
+        ::__internal::set_sess(cx, || quote!(::TokenStream { 0: (quote stream) }))
     }
 }
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 9eb96fea527..051b89219c1 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -18,13 +18,13 @@
 
 #![feature(rustc_diagnostic_macros)]
 
-extern crate rustc;
+#[macro_use] extern crate rustc;
 #[macro_use] extern crate syntax;
 extern crate syntax_pos;
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::def::Def;
-use rustc::hir::def_id::{LOCAL_CRATE, CrateNum, DefId};
+use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::DeepVisitor;
 use rustc::lint;
@@ -537,6 +537,344 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////////////////
+/// Type privacy visitor, checks types for privacy and reports violations.
+/// Both explicitly written types and inferred types of expressions and patters are checked.
+/// Checks are performed on "semantic" types regardless of names and their hygiene.
+////////////////////////////////////////////////////////////////////////////////////////////
+
+struct TypePrivacyVisitor<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    tables: &'a ty::TypeckTables<'tcx>,
+    current_item: DefId,
+    span: Span,
+}
+
+impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
+    fn def_id_visibility(&self, did: DefId) -> ty::Visibility {
+        match self.tcx.hir.as_local_node_id(did) {
+            Some(node_id) => {
+                let vis = match self.tcx.hir.get(node_id) {
+                    hir::map::NodeItem(item) => &item.vis,
+                    hir::map::NodeForeignItem(foreign_item) => &foreign_item.vis,
+                    hir::map::NodeImplItem(impl_item) => &impl_item.vis,
+                    hir::map::NodeTraitItem(..) |
+                    hir::map::NodeVariant(..) => {
+                        return self.def_id_visibility(self.tcx.hir.get_parent_did(node_id));
+                    }
+                    hir::map::NodeStructCtor(vdata) => {
+                        let struct_node_id = self.tcx.hir.get_parent(node_id);
+                        let struct_vis = match self.tcx.hir.get(struct_node_id) {
+                            hir::map::NodeItem(item) => &item.vis,
+                            node => bug!("unexpected node kind: {:?}", node),
+                        };
+                        let mut ctor_vis
+                            = ty::Visibility::from_hir(struct_vis, struct_node_id, self.tcx);
+                        for field in vdata.fields() {
+                            let field_vis = ty::Visibility::from_hir(&field.vis, node_id, self.tcx);
+                            if ctor_vis.is_at_least(field_vis, self.tcx) {
+                                ctor_vis = field_vis;
+                            }
+                        }
+                        return ctor_vis;
+                    }
+                    node => bug!("unexpected node kind: {:?}", node)
+                };
+                ty::Visibility::from_hir(vis, node_id, self.tcx)
+            }
+            None => self.tcx.sess.cstore.visibility(did),
+        }
+    }
+
+    fn item_is_accessible(&self, did: DefId) -> bool {
+        self.def_id_visibility(did).is_accessible_from(self.current_item, self.tcx)
+    }
+
+    // Take node ID of an expression or pattern and check its type for privacy.
+    fn check_expr_pat_type(&mut self, id: ast::NodeId, 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_substs(id).visit_with(self) {
+            return true;
+        }
+        if let Some(adjustments) = self.tables.adjustments.get(&id) {
+            for adjustment in adjustments {
+                if adjustment.target.visit_with(self) {
+                    return true;
+                }
+            }
+        }
+        false
+    }
+
+    fn check_item(&mut self, item_id: ast::NodeId) -> &mut Self {
+        self.current_item = self.tcx.hir.local_def_id(item_id);
+        self.span = self.tcx.hir.span(item_id);
+        self
+    }
+
+    // Convenience methods for checking item interfaces
+    fn ty(&mut self) -> &mut Self {
+        self.tcx.type_of(self.current_item).visit_with(self);
+        self
+    }
+
+    fn generics(&mut self) -> &mut Self {
+        for def in &self.tcx.generics_of(self.current_item).types {
+            if def.has_default {
+                self.tcx.type_of(def.def_id).visit_with(self);
+            }
+        }
+        self
+    }
+
+    fn predicates(&mut self) -> &mut Self {
+        self.tcx.predicates_of(self.current_item).visit_with(self);
+        self
+    }
+
+    fn impl_trait_ref(&mut self) -> &mut Self {
+        self.tcx.impl_trait_ref(self.current_item).visit_with(self);
+        self
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
+    /// We want to visit items in the context of their containing
+    /// module and so forth, so supply a crate for doing a deep walk.
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::All(&self.tcx.hir)
+    }
+
+    fn visit_nested_body(&mut self, body: hir::BodyId) {
+        let orig_tables = replace(&mut self.tables, self.tcx.body_tables(body));
+        let body = self.tcx.hir.body(body);
+        self.visit_body(body);
+        self.tables = orig_tables;
+    }
+
+    // Check types of expressions
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+        if self.check_expr_pat_type(expr.id, expr.span) {
+            // Do not check nested expressions if the error already happened.
+            return;
+        }
+        match expr.node {
+            hir::ExprAssign(.., ref rhs) | hir::ExprMatch(ref rhs, ..) => {
+                // Do not report duplicate errors for `x = y` and `match x { ... }`.
+                if self.check_expr_pat_type(rhs.id, rhs.span) {
+                    return;
+                }
+            }
+            hir::ExprMethodCall(name, ..) => {
+                // Method calls have to be checked specially.
+                let def_id = self.tables.type_dependent_defs[&expr.id].def_id();
+                self.span = name.span;
+                if self.tcx.type_of(def_id).visit_with(self) {
+                    return;
+                }
+            }
+            _ => {}
+        }
+
+        intravisit::walk_expr(self, expr);
+    }
+
+    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 {
+            if let Some(def) = self.tables.type_dependent_defs.get(&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;
+                        }
+                    }
+                }
+            }
+        }
+
+        intravisit::walk_qpath(self, qpath, id, span);
+    }
+
+    // Check types of patterns
+    fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
+        if self.check_expr_pat_type(pattern.id, pattern.span) {
+            // Do not check nested patterns if the error already happened.
+            return;
+        }
+
+        intravisit::walk_pat(self, pattern);
+    }
+
+    fn visit_local(&mut self, local: &'tcx hir::Local) {
+        if let Some(ref init) = local.init {
+            if self.check_expr_pat_type(init.id, init.span) {
+                // Do not report duplicate errors for `let x = y`.
+                return;
+            }
+        }
+
+        intravisit::walk_local(self, local);
+    }
+
+    // Check types in item interfaces
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        let orig_current_item = self.current_item;
+
+        match item.node {
+            hir::ItemExternCrate(..) | hir::ItemMod(..) |
+            hir::ItemUse(..) | hir::ItemGlobalAsm(..) => {}
+            hir::ItemConst(..) | hir::ItemStatic(..) |
+            hir::ItemTy(..) | hir::ItemFn(..) => {
+                self.check_item(item.id).generics().predicates().ty();
+            }
+            hir::ItemTrait(.., ref trait_item_refs) => {
+                self.check_item(item.id).generics().predicates();
+                for trait_item_ref in trait_item_refs {
+                    let mut check = self.check_item(trait_item_ref.id.node_id);
+                    check.generics().predicates();
+                    if trait_item_ref.kind != hir::AssociatedItemKind::Type ||
+                       trait_item_ref.defaultness.has_value() {
+                        check.ty();
+                    }
+                }
+            }
+            hir::ItemEnum(ref def, _) => {
+                self.check_item(item.id).generics().predicates();
+                for variant in &def.variants {
+                    for field in variant.node.data.fields() {
+                        self.check_item(field.id).ty();
+                    }
+                }
+            }
+            hir::ItemForeignMod(ref foreign_mod) => {
+                for foreign_item in &foreign_mod.items {
+                    self.check_item(foreign_item.id).generics().predicates().ty();
+                }
+            }
+            hir::ItemStruct(ref struct_def, _) |
+            hir::ItemUnion(ref struct_def, _) => {
+                self.check_item(item.id).generics().predicates();
+                for field in struct_def.fields() {
+                    self.check_item(field.id).ty();
+                }
+            }
+            hir::ItemDefaultImpl(..) => {
+                self.check_item(item.id).impl_trait_ref();
+            }
+            hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => {
+                {
+                    let mut check = self.check_item(item.id);
+                    check.ty().generics().predicates();
+                    if trait_ref.is_some() {
+                        check.impl_trait_ref();
+                    }
+                }
+                for impl_item_ref in impl_item_refs {
+                    let impl_item = self.tcx.hir.impl_item(impl_item_ref.id);
+                    self.check_item(impl_item.id).generics().predicates().ty();
+                }
+            }
+        }
+
+        self.current_item = self.tcx.hir.local_def_id(item.id);
+        intravisit::walk_item(self, item);
+        self.current_item = orig_current_item;
+    }
+}
+
+impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+        match ty.sty {
+            ty::TyAdt(&ty::AdtDef { did: def_id, .. }, ..) | ty::TyFnDef(def_id, ..) => {
+                if !self.item_is_accessible(def_id) {
+                    let msg = format!("type `{}` is private", ty);
+                    self.tcx.sess.span_err(self.span, &msg);
+                    return true;
+                }
+                if let ty::TyFnDef(..) = ty.sty {
+                    if self.tcx.fn_sig(def_id).visit_with(self) {
+                        return true;
+                    }
+                }
+                // Inherent static methods don't have self type in substs,
+                // we have to check it additionally.
+                if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) {
+                    if let ty::ImplContainer(impl_def_id) = assoc_item.container {
+                        if self.tcx.type_of(impl_def_id).visit_with(self) {
+                            return true;
+                        }
+                    }
+                }
+            }
+            ty::TyDynamic(ref predicates, ..) => {
+                let is_private = predicates.skip_binder().iter().any(|predicate| {
+                    let def_id = match *predicate {
+                        ty::ExistentialPredicate::Trait(trait_ref) => trait_ref.def_id,
+                        ty::ExistentialPredicate::Projection(proj) => proj.trait_ref.def_id,
+                        ty::ExistentialPredicate::AutoTrait(def_id) => def_id,
+                    };
+                    !self.item_is_accessible(def_id)
+                });
+                if is_private {
+                    let msg = format!("type `{}` is private", ty);
+                    self.tcx.sess.span_err(self.span, &msg);
+                    return true;
+                }
+            }
+            ty::TyAnon(def_id, ..) => {
+                for predicate in &self.tcx.predicates_of(def_id).predicates {
+                    let trait_ref = match *predicate {
+                        ty::Predicate::Trait(ref poly_trait_predicate) => {
+                            Some(poly_trait_predicate.skip_binder().trait_ref)
+                        }
+                        ty::Predicate::Projection(ref poly_projection_predicate) => {
+                            if poly_projection_predicate.skip_binder().ty.visit_with(self) {
+                                return true;
+                            }
+                            Some(poly_projection_predicate.skip_binder().projection_ty.trait_ref)
+                        }
+                        ty::Predicate::TypeOutlives(..) => None,
+                        _ => bug!("unexpected predicate: {:?}", predicate),
+                    };
+                    if let Some(trait_ref) = trait_ref {
+                        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;
+                        }
+                        // `Self` here is the same `TyAnon`, so skip it to avoid infinite recursion
+                        for subst in trait_ref.substs.iter().skip(1) {
+                            if subst.visit_with(self) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        ty.super_visit_with(self)
+    }
+
+    fn visit_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)
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 /// Obsolete visitors for checking for private items in public interfaces.
 /// These visitors are supposed to be kept in frozen state and produce an
@@ -1225,6 +1563,16 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     };
     intravisit::walk_crate(&mut visitor, krate);
 
+    // Check privacy of explicitly written types and traits as well as
+    // inferred types of expressions and patterns.
+    let mut visitor = TypePrivacyVisitor {
+        tcx: tcx,
+        tables: &ty::TypeckTables::empty(),
+        current_item: DefId::local(CRATE_DEF_INDEX),
+        span: krate.span,
+    };
+    intravisit::walk_crate(&mut visitor, krate);
+
     // Build up a set of all exported items in the AST. This is a set of all
     // items which are reachable from external crates based on visibility.
     let mut visitor = EmbargoVisitor {
diff --git a/src/test/compile-fail/auxiliary/private-inferred-type.rs b/src/test/compile-fail/auxiliary/private-inferred-type.rs
new file mode 100644
index 00000000000..7627f5dc0cd
--- /dev/null
+++ b/src/test/compile-fail/auxiliary/private-inferred-type.rs
@@ -0,0 +1,44 @@
+// 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)]
+
+fn priv_fn() {}
+enum PrivEnum { Variant }
+pub enum PubEnum { Variant }
+trait PrivTrait { fn method() {} }
+impl PrivTrait for u8 {}
+pub trait PubTrait { fn method() {} }
+impl PubTrait for u8 {}
+struct PrivTupleStruct(u8);
+pub struct PubTupleStruct(u8);
+impl PubTupleStruct { fn method() {} }
+
+struct Priv;
+pub type Alias = Priv;
+pub struct Pub<T = Alias>(pub T);
+
+impl Pub<Priv> {
+    pub fn static_method() {}
+}
+impl Pub<u8> {
+    fn priv_method(&self) {}
+}
+
+pub macro m() {
+    priv_fn;
+    PrivEnum::Variant;
+    PubEnum::Variant;
+    <u8 as PrivTrait>::method;
+    <u8 as PubTrait>::method;
+    PrivTupleStruct;
+    PubTupleStruct;
+    Pub(0u8).priv_method();
+}
diff --git a/src/test/run-pass/hygiene/auxiliary/intercrate.rs b/src/test/compile-fail/hygiene/auxiliary/intercrate.rs
index aa67e5c5f4d..aa67e5c5f4d 100644
--- a/src/test/run-pass/hygiene/auxiliary/intercrate.rs
+++ b/src/test/compile-fail/hygiene/auxiliary/intercrate.rs
diff --git a/src/test/run-pass/hygiene/fields.rs b/src/test/compile-fail/hygiene/fields.rs
index d7f99ba2118..64217770b13 100644
--- a/src/test/run-pass/hygiene/fields.rs
+++ b/src/test/compile-fail/hygiene/fields.rs
@@ -22,11 +22,11 @@ mod foo {
             x: i32,
         }
 
-        let s = S { x: 0 };
-        let _ = s.x;
+        let s = S { x: 0 }; //~ ERROR type `foo::S` is private
+        let _ = s.x; //~ ERROR type `foo::S` is private
 
-        let t = T(0);
-        let _ = t.0;
+        let t = T(0); //~ ERROR type `foo::T` is private
+        let _ = t.0; //~ ERROR type `foo::T` is private
 
         let s = $S { $x: 0, x: 1 };
         assert_eq!((s.$x, s.x), (0, 1));
diff --git a/src/test/run-pass/hygiene/impl_items.rs b/src/test/compile-fail/hygiene/impl_items.rs
index a5780a573ab..445aa62f236 100644
--- a/src/test/run-pass/hygiene/impl_items.rs
+++ b/src/test/compile-fail/hygiene/impl_items.rs
@@ -19,7 +19,7 @@ mod foo {
     }
 
     pub macro m() {
-        let _: () = S.f();
+        let _: () = S.f(); //~ ERROR type `fn(&foo::S) {foo::S::f}` is private
     }
 }
 
diff --git a/src/test/run-pass/hygiene/intercrate.rs b/src/test/compile-fail/hygiene/intercrate.rs
index 3a75085f22e..50fc985ba34 100644
--- a/src/test/run-pass/hygiene/intercrate.rs
+++ b/src/test/compile-fail/hygiene/intercrate.rs
@@ -12,6 +12,8 @@
 
 // aux-build:intercrate.rs
 
+// error-pattern:type `fn() -> u32 {intercrate::foo::bar::f}` is private
+
 #![feature(decl_macro)]
 
 extern crate intercrate;
diff --git a/src/test/compile-fail/private-inferred-type-1.rs b/src/test/compile-fail/private-inferred-type-1.rs
new file mode 100644
index 00000000000..ba8b3d1810a
--- /dev/null
+++ b/src/test/compile-fail/private-inferred-type-1.rs
@@ -0,0 +1,28 @@
+// 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.
+
+trait Arr0 {
+    fn arr0_secret(&self);
+}
+trait TyParam {
+    fn ty_param_secret(&self);
+}
+
+mod m {
+    struct Priv;
+
+    impl ::Arr0 for [Priv; 0] { fn arr0_secret(&self) {} }
+    impl ::TyParam for Option<Priv> { fn ty_param_secret(&self) {} }
+}
+
+fn main() {
+    [].arr0_secret(); //~ ERROR type `m::Priv` is private
+    None.ty_param_secret(); //~ ERROR type `m::Priv` is private
+}
diff --git a/src/test/compile-fail/private-inferred-type-2.rs b/src/test/compile-fail/private-inferred-type-2.rs
new file mode 100644
index 00000000000..e981f125750
--- /dev/null
+++ b/src/test/compile-fail/private-inferred-type-2.rs
@@ -0,0 +1,29 @@
+// 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.
+
+// aux-build:private-inferred-type.rs
+
+extern crate private_inferred_type as ext;
+
+mod m {
+    struct Priv;
+    pub struct Pub<T>(pub T);
+
+    impl Pub<Priv> {
+        pub fn get_priv() -> Priv { Priv }
+        pub fn static_method() {}
+    }
+}
+
+fn main() {
+    m::Pub::get_priv; //~ ERROR type `m::Priv` is private
+    m::Pub::static_method; //~ ERROR type `m::Priv` is private
+    ext::Pub::static_method; //~ ERROR type `ext::Priv` is private
+}
diff --git a/src/test/compile-fail/private-inferred-type-3.rs b/src/test/compile-fail/private-inferred-type-3.rs
new file mode 100644
index 00000000000..fdd9166ef29
--- /dev/null
+++ b/src/test/compile-fail/private-inferred-type-3.rs
@@ -0,0 +1,26 @@
+// 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.
+
+// aux-build:private-inferred-type.rs
+
+// error-pattern:type `fn() {ext::priv_fn}` 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
+// error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct::{{constructor}}}` is priv
+// error-pattern:type `fn(&ext::Pub<u8>) {<ext::Pub<u8>>::priv_method}` is private
+
+#![feature(decl_macro)]
+
+extern crate private_inferred_type as ext;
+
+fn main() {
+    ext::m!();
+}
diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs
new file mode 100644
index 00000000000..140891027d5
--- /dev/null
+++ b/src/test/compile-fail/private-inferred-type.rs
@@ -0,0 +1,139 @@
+// 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(associated_consts)]
+#![feature(conservative_impl_trait)]
+#![feature(decl_macro)]
+
+mod m {
+    fn priv_fn() {}
+    enum PrivEnum { Variant }
+    pub enum PubEnum { Variant }
+    trait PrivTrait { fn method() {} }
+    impl PrivTrait for u8 {}
+    pub trait PubTrait { fn method() {} }
+    impl PubTrait for u8 {}
+    struct PrivTupleStruct(u8);
+    pub struct PubTupleStruct(u8);
+    impl PubTupleStruct { fn method() {} }
+
+    struct Priv;
+    pub type Alias = Priv;
+    pub struct Pub<T = Alias>(pub T);
+
+    impl Pub<Priv> {
+        pub fn static_method() {}
+        pub const INHERENT_ASSOC_CONST: u8 = 0;
+    }
+    impl<T> Pub<T> {
+        pub fn static_method_generic_self() {}
+        pub const INHERENT_ASSOC_CONST_GENERIC_SELF: u8 = 0;
+    }
+    impl Pub<u8> {
+        fn priv_method(&self) {}
+        pub fn method_with_substs<T>(&self) {}
+        pub fn method_with_priv_params(&self, _: Priv) {}
+    }
+    impl TraitWithAssocConst for Priv {}
+    impl TraitWithAssocTy for Priv { type AssocTy = u8; }
+
+    pub macro m() {
+        priv_fn; //~ ERROR type `fn() {m::priv_fn}` is private
+        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
+        <u8 as PubTrait>::method; // OK
+        PrivTupleStruct;
+        //~^ ERROR type `fn(u8) -> m::PrivTupleStruct {m::PrivTupleStruct::{{constructor}}}` is priv
+        PubTupleStruct;
+        //~^ ERROR type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct::{{constructor}}}` is privat
+        Pub(0u8).priv_method();
+        //~^ ERROR type `fn(&m::Pub<u8>) {<m::Pub<u8>>::priv_method}` is private
+    }
+
+    trait Trait {}
+    pub trait TraitWithTyParam<T> {}
+    pub trait TraitWithTyParam2<T> { fn pub_method() {} }
+    pub trait TraitWithAssocTy { type AssocTy; }
+    pub trait TraitWithAssocConst { const TRAIT_ASSOC_CONST: u8 = 0; }
+    impl Trait for u8 {}
+    impl<T> TraitWithTyParam<T> for u8 {}
+    impl TraitWithTyParam2<Priv> for u8 {}
+    impl TraitWithAssocTy for u8 { type AssocTy = Priv; }
+
+    pub fn leak_anon1() -> impl Trait + 'static { 0 }
+    pub fn leak_anon2() -> impl TraitWithTyParam<Alias> { 0 }
+    pub fn leak_anon3() -> impl TraitWithAssocTy<AssocTy = Alias> { 0 }
+
+    pub fn leak_dyn1() -> Box<Trait + 'static> { Box::new(0) }
+    pub fn leak_dyn2() -> Box<TraitWithTyParam<Alias>> { Box::new(0) }
+    pub fn leak_dyn3() -> Box<TraitWithAssocTy<AssocTy = Alias>> { Box::new(0) }
+}
+
+mod adjust {
+    // Construct a chain of derefs with a private type in the middle
+    use std::ops::Deref;
+
+    pub struct S1;
+    struct S2;
+    pub type S2Alias = S2;
+    pub struct S3;
+
+    impl Deref for S1 {
+        type Target = S2Alias;
+        fn deref(&self) -> &Self::Target { loop {} }
+    }
+    impl Deref for S2 {
+        type Target = S3;
+        fn deref(&self) -> &Self::Target { loop {} }
+    }
+
+    impl S3 {
+        pub fn method_s3(&self) {}
+    }
+}
+
+fn main() {
+    let _: m::Alias; //~ ERROR type `m::Priv` is private
+    let _: <m::Alias as m::TraitWithAssocTy>::AssocTy; // FIXME
+    m::Alias {}; //~ ERROR type `m::Priv` is private
+    m::Pub { 0: m::Alias {} }; //~ ERROR type `m::Priv` is private
+    m::Pub { 0: loop {} }; // FIXME
+    m::Pub::static_method; //~ ERROR type `m::Priv` is private
+    m::Pub::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private
+    m::Pub(0u8).method_with_substs::<m::Alias>(); //~ ERROR type `m::Priv` is private
+    m::Pub(0u8).method_with_priv_params(loop{}); //~ ERROR type `m::Priv` is private
+    <m::Alias as m::TraitWithAssocConst>::TRAIT_ASSOC_CONST; //~ ERROR type `m::Priv` is private
+    <m::Pub<m::Alias>>::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private
+    <m::Pub<m::Alias>>::INHERENT_ASSOC_CONST_GENERIC_SELF; //~ ERROR type `m::Priv` is private
+    <m::Pub<m::Alias>>::static_method_generic_self; //~ ERROR type `m::Priv` is private
+    use m::TraitWithTyParam2;
+    u8::pub_method; //~ ERROR type `m::Priv` is private
+
+    adjust::S1.method_s3(); //~ ERROR type `adjust::S2` is private
+
+    m::m!();
+
+    m::leak_anon1(); //~ ERROR trait `m::Trait` is private
+    m::leak_anon2(); //~ ERROR type `m::Priv` is private
+    m::leak_anon3(); //~ ERROR type `m::Priv` is private
+
+    m::leak_dyn1(); //~ ERROR type `m::Trait + 'static` is private
+    m::leak_dyn2(); //~ ERROR type `m::Priv` is private
+    m::leak_dyn3(); //~ ERROR type `m::Priv` is private
+
+    // Check that messages are not duplicated for various kinds of assignments
+    let a = m::Alias {}; //~ ERROR type `m::Priv` is private
+    let mut b = a; //~ ERROR type `m::Priv` is private
+    b = a; //~ ERROR type `m::Priv` is private
+    match a { //~ ERROR type `m::Priv` is private
+        _ => {}
+    }
+}
diff --git a/src/test/compile-fail/private-type-in-interface.rs b/src/test/compile-fail/private-type-in-interface.rs
new file mode 100644
index 00000000000..925d692f8ae
--- /dev/null
+++ b/src/test/compile-fail/private-type-in-interface.rs
@@ -0,0 +1,41 @@
+// 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.
+
+// aux-build:private-inferred-type.rs
+
+#![feature(conservative_impl_trait)]
+
+extern crate private_inferred_type as ext;
+
+mod m {
+    struct Priv;
+    pub type Alias = Priv;
+
+    pub trait Trait { type X; }
+    impl Trait for Priv { type X = u8; }
+}
+
+fn f(_: m::Alias) {} //~ ERROR type `m::Priv` is private
+                     //~^ ERROR type `m::Priv` is private
+fn f_ext(_: ext::Alias) {} //~ ERROR type `ext::Priv` is private
+                           //~^ ERROR type `ext::Priv` is private
+
+trait Tr1 {}
+impl m::Alias {} //~ ERROR type `m::Priv` is private
+impl Tr1 for ext::Alias {} //~ ERROR type `ext::Priv` is private
+                           //~^ ERROR type `ext::Priv` is private
+type A = <m::Alias as m::Trait>::X; //~ ERROR type `m::Priv` is private
+
+trait Tr2<T> {}
+impl<T> Tr2<T> for u8 {}
+fn g() -> impl Tr2<m::Alias> { 0 } //~ ERROR type `m::Priv` is private
+fn g_ext() -> impl Tr2<ext::Alias> { 0 } //~ ERROR type `ext::Priv` is private
+
+fn main() {}