about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-04-05 10:55:38 -0700
committerbors <bors@rust-lang.org>2016-04-05 10:55:38 -0700
commit57e5d43c770201d837298175a2d55818867bdb33 (patch)
treed2aff29aff613d9023bb26d7a8bc5b4ee3ee2ec7 /src
parent953c3b5f502437398711ca442be0a10ad575b667 (diff)
parente8ab71fa00f2264f4587ca536e93b909a9358e27 (diff)
Auto merge of #32743 - Manishearth:rollup, r=Manishearth
Rollup of 11 pull requests

- Successful merges: #32403, #32596, #32675, #32678, #32685, #32686, #32692, #32710, #32712, #32714, #32715
- Failed merges: #32488
Diffstat (limited to 'src')
-rw-r--r--src/liballoc_jemalloc/build.rs2
-rw-r--r--src/liballoc_jemalloc/lib.rs19
-rw-r--r--src/librustc/infer/combine.rs4
-rw-r--r--src/librustc/infer/equate.rs5
-rw-r--r--src/librustc/infer/glb.rs5
-rw-r--r--src/librustc/infer/lub.rs5
-rw-r--r--src/librustc/infer/mod.rs97
-rw-r--r--src/librustc/infer/sub.rs5
-rw-r--r--src/librustc/lint/builtin.rs9
-rw-r--r--src/librustc/middle/liveness.rs4
-rw-r--r--src/librustc/traits/fulfill.rs8
-rw-r--r--src/librustc/traits/project.rs23
-rw-r--r--src/librustc/traits/select.rs83
-rw-r--r--src/librustc_driver/test.rs25
-rw-r--r--src/librustc_lint/lib.rs4
-rw-r--r--src/librustc_mir/transform/type_check.rs6
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs20
-rw-r--r--src/librustc_typeck/check/_match.rs9
-rw-r--r--src/librustc_typeck/check/coercion.rs34
-rw-r--r--src/librustc_typeck/check/compare_method.rs7
-rw-r--r--src/librustc_typeck/check/demand.rs22
-rw-r--r--src/librustc_typeck/check/method/probe.rs5
-rw-r--r--src/librustc_typeck/check/method/suggest.rs51
-rw-r--r--src/librustc_typeck/check/mod.rs33
-rw-r--r--src/librustc_typeck/check/regionck.rs8
-rw-r--r--src/librustdoc/clean/mod.rs55
-rw-r--r--src/librustdoc/fold.rs56
-rw-r--r--src/librustdoc/html/highlight.rs61
-rw-r--r--src/librustdoc/html/item_type.rs8
-rw-r--r--src/librustdoc/html/markdown.rs6
-rw-r--r--src/librustdoc/html/render.rs315
-rw-r--r--src/librustdoc/passes.rs60
-rw-r--r--src/librustdoc/test.rs4
-rw-r--r--src/libstd/time/duration.rs5
-rw-r--r--src/libsyntax/errors/json.rs75
-rw-r--r--src/libsyntax/parse/parser.rs10
-rw-r--r--src/libsyntax/parse/token.rs2
-rw-r--r--src/snapshots.txt2
-rw-r--r--src/test/auxiliary/reexp_stripped.rs21
-rw-r--r--src/test/compile-fail/consider-removing-last-semi.rs23
-rw-r--r--src/test/compile-fail/issue-32128.rs25
-rw-r--r--src/test/compile-fail/use-super-global-path.rs22
-rw-r--r--src/test/rustdoc/redirect.rs48
-rw-r--r--src/test/rustdoc/structfields.rs44
44 files changed, 911 insertions, 424 deletions
diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs
index 9e2090c3246..5d521913b48 100644
--- a/src/liballoc_jemalloc/build.rs
+++ b/src/liballoc_jemalloc/build.rs
@@ -86,6 +86,8 @@ fn main() {
         // should be good to go!
         cmd.arg("--with-jemalloc-prefix=je_");
         cmd.arg("--disable-tls");
+    } else if target.contains("dragonfly") {
+        cmd.arg("--with-jemalloc-prefix=je_");
     }
 
     if cfg!(feature = "debug-jemalloc") {
diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs
index c96d303e6bb..3a30bebec54 100644
--- a/src/liballoc_jemalloc/lib.rs
+++ b/src/liballoc_jemalloc/lib.rs
@@ -42,22 +42,27 @@ use libc::{c_int, c_void, size_t};
 extern {}
 
 // Note that the symbols here are prefixed by default on OSX (we don't
-// explicitly request it), and on Android we explicitly request it as
-// unprefixing cause segfaults (mismatches in allocators).
+// explicitly request it), and on Android and DragonFly we explicitly request
+// it as unprefixing cause segfaults (mismatches in allocators).
 extern {
-    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios"),
+    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+                   target_os = "dragonfly"),
                link_name = "je_mallocx")]
     fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
-    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios"),
+    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+                   target_os = "dragonfly"),
                link_name = "je_rallocx")]
     fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
-    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios"),
+    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+                   target_os = "dragonfly"),
                link_name = "je_xallocx")]
     fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
-    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios"),
+    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+                   target_os = "dragonfly"),
                link_name = "je_sdallocx")]
     fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
-    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios"),
+    #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
+                   target_os = "dragonfly"),
                link_name = "je_nallocx")]
     fn nallocx(size: size_t, flags: c_int) -> size_t;
 }
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 8edf24fbc25..67669c54ac5 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -37,7 +37,7 @@ use super::equate::Equate;
 use super::glb::Glb;
 use super::lub::Lub;
 use super::sub::Sub;
-use super::{InferCtxt};
+use super::InferCtxt;
 use super::{MiscVariable, TypeTrace};
 use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};
 
@@ -46,6 +46,7 @@ use ty::{self, Ty, TyCtxt};
 use ty::error::TypeError;
 use ty::fold::{TypeFolder, TypeFoldable};
 use ty::relate::{Relate, RelateResult, TypeRelation};
+use traits::PredicateObligations;
 
 use syntax::ast;
 use syntax::codemap::Span;
@@ -56,6 +57,7 @@ pub struct CombineFields<'a, 'tcx: 'a> {
     pub a_is_expected: bool,
     pub trace: TypeTrace<'tcx>,
     pub cause: Option<ty::relate::Cause>,
+    pub obligations: PredicateObligations<'tcx>,
 }
 
 pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,
diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs
index 3c9c9c57884..5540046c9e3 100644
--- a/src/librustc/infer/equate.rs
+++ b/src/librustc/infer/equate.rs
@@ -16,6 +16,7 @@ use super::type_variable::{EqTo};
 use ty::{self, Ty, TyCtxt};
 use ty::TyVar;
 use ty::relate::{Relate, RelateResult, TypeRelation};
+use traits::PredicateObligations;
 
 /// Ensures `a` is made equal to `b`. Returns `a` on success.
 pub struct Equate<'a, 'tcx: 'a> {
@@ -26,6 +27,10 @@ impl<'a, 'tcx> Equate<'a, 'tcx> {
     pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> {
         Equate { fields: fields }
     }
+
+    pub fn obligations(self) -> PredicateObligations<'tcx> {
+        self.fields.obligations
+    }
 }
 
 impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> {
diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs
index 235428a6898..37717c2b6bc 100644
--- a/src/librustc/infer/glb.rs
+++ b/src/librustc/infer/glb.rs
@@ -16,6 +16,7 @@ use super::Subtype;
 
 use ty::{self, Ty, TyCtxt};
 use ty::relate::{Relate, RelateResult, TypeRelation};
+use traits::PredicateObligations;
 
 /// "Greatest lower bound" (common subtype)
 pub struct Glb<'a, 'tcx: 'a> {
@@ -26,6 +27,10 @@ impl<'a, 'tcx> Glb<'a, 'tcx> {
     pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> {
         Glb { fields: fields }
     }
+
+    pub fn obligations(self) -> PredicateObligations<'tcx> {
+        self.fields.obligations
+    }
 }
 
 impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> {
diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs
index 00b85929b4b..32b2fe911e8 100644
--- a/src/librustc/infer/lub.rs
+++ b/src/librustc/infer/lub.rs
@@ -16,6 +16,7 @@ use super::Subtype;
 
 use ty::{self, Ty, TyCtxt};
 use ty::relate::{Relate, RelateResult, TypeRelation};
+use traits::PredicateObligations;
 
 /// "Least upper bound" (common supertype)
 pub struct Lub<'a, 'tcx: 'a> {
@@ -26,6 +27,10 @@ impl<'a, 'tcx> Lub<'a, 'tcx> {
     pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> {
         Lub { fields: fields }
     }
+
+    pub fn obligations(self) -> PredicateObligations<'tcx> {
+        self.fields.obligations
+    }
 }
 
 impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> {
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 35e1be7e5f4..e22fb988904 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -27,13 +27,13 @@ use middle::region::CodeExtent;
 use ty::subst;
 use ty::subst::Substs;
 use ty::subst::Subst;
-use traits::{self, ProjectionMode};
 use ty::adjustment;
 use ty::{TyVid, IntVid, FloatVid};
 use ty::{self, Ty, TyCtxt};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use ty::fold::{TypeFolder, TypeFoldable};
 use ty::relate::{Relate, RelateResult, TypeRelation};
+use traits::{self, PredicateObligations, ProjectionMode};
 use rustc_data_structures::unify::{self, UnificationTable};
 use std::cell::{RefCell, Ref};
 use std::fmt;
@@ -63,6 +63,12 @@ pub mod sub;
 pub mod type_variable;
 pub mod unify_key;
 
+pub struct InferOk<'tcx, T> {
+    pub value: T,
+    pub obligations: PredicateObligations<'tcx>,
+}
+pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
+
 pub type Bound<T> = Option<T>;
 pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
 pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
@@ -391,16 +397,15 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                           origin: TypeOrigin,
                           a: Ty<'tcx>,
                           b: Ty<'tcx>)
-                          -> UnitResult<'tcx>
+    -> InferResult<'tcx, ()>
 {
     debug!("mk_subty({:?} <: {:?})", a, b);
     cx.sub_types(a_is_expected, origin, a, b)
 }
 
-pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
-                              a: Ty<'tcx>,
-                              b: Ty<'tcx>)
-                              -> UnitResult<'tcx> {
+pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>)
+    -> UnitResult<'tcx>
+{
     debug!("can_mk_subty({:?} <: {:?})", a, b);
     cx.probe(|_| {
         let trace = TypeTrace {
@@ -412,7 +417,7 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
 }
 
 pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>)
-                             -> UnitResult<'tcx>
+    -> UnitResult<'tcx>
 {
     cx.can_equate(&a, &b)
 }
@@ -432,7 +437,7 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                          origin: TypeOrigin,
                          a: Ty<'tcx>,
                          b: Ty<'tcx>)
-                         -> UnitResult<'tcx>
+    -> InferResult<'tcx, ()>
 {
     debug!("mk_eqty({:?} <: {:?})", a, b);
     cx.eq_types(a_is_expected, origin, a, b)
@@ -443,7 +448,7 @@ pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                                   origin: TypeOrigin,
                                   a: ty::TraitRef<'tcx>,
                                   b: ty::TraitRef<'tcx>)
-                                  -> UnitResult<'tcx>
+    -> InferResult<'tcx, ()>
 {
     debug!("mk_eq_trait_refs({:?} = {:?})", a, b);
     cx.eq_trait_refs(a_is_expected, origin, a, b)
@@ -454,7 +459,7 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                                         origin: TypeOrigin,
                                         a: ty::PolyTraitRef<'tcx>,
                                         b: ty::PolyTraitRef<'tcx>)
-                                        -> UnitResult<'tcx>
+    -> InferResult<'tcx, ()>
 {
     debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b);
     cx.sub_poly_trait_refs(a_is_expected, origin, a, b)
@@ -465,7 +470,7 @@ pub fn mk_eq_impl_headers<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
                                     origin: TypeOrigin,
                                     a: &ty::ImplHeader<'tcx>,
                                     b: &ty::ImplHeader<'tcx>)
-                                    -> UnitResult<'tcx>
+    -> InferResult<'tcx, ()>
 {
     debug!("mk_eq_impl_header({:?} = {:?})", a, b);
     match (a.trait_ref, b.trait_ref) {
@@ -574,6 +579,12 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
     Ok(infcx.tcx.erase_regions(&result))
 }
 
+impl<'tcx, T> InferOk<'tcx, T> {
+    fn unit(self) -> InferOk<'tcx, ()> {
+        InferOk { value: (), obligations: self.obligations }
+    }
+}
+
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn projection_mode(&self) -> ProjectionMode {
         self.projection_mode
@@ -661,39 +672,51 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-                      -> CombineFields<'a, 'tcx> {
-        CombineFields {infcx: self,
-                       a_is_expected: a_is_expected,
-                       trace: trace,
-                       cause: None}
+        -> CombineFields<'a, 'tcx>
+    {
+        CombineFields {
+            infcx: self,
+            a_is_expected: a_is_expected,
+            trace: trace,
+            cause: None,
+            obligations: PredicateObligations::new(),
+        }
     }
 
     pub fn equate<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-        -> RelateResult<'tcx, T>
+        -> InferResult<'tcx, T>
         where T: Relate<'a, 'tcx>
     {
-        self.combine_fields(a_is_expected, trace).equate().relate(a, b)
+        let mut equate = self.combine_fields(a_is_expected, trace).equate();
+        let result = equate.relate(a, b);
+        result.map(|t| InferOk { value: t, obligations: equate.obligations() })
     }
 
     pub fn sub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-        -> RelateResult<'tcx, T>
+        -> InferResult<'tcx, T>
         where T: Relate<'a, 'tcx>
     {
-        self.combine_fields(a_is_expected, trace).sub().relate(a, b)
+        let mut sub = self.combine_fields(a_is_expected, trace).sub();
+        let result = sub.relate(a, b);
+        result.map(|t| InferOk { value: t, obligations: sub.obligations() })
     }
 
     pub fn lub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-        -> RelateResult<'tcx, T>
+        -> InferResult<'tcx, T>
         where T: Relate<'a, 'tcx>
     {
-        self.combine_fields(a_is_expected, trace).lub().relate(a, b)
+        let mut lub = self.combine_fields(a_is_expected, trace).lub();
+        let result = lub.relate(a, b);
+        result.map(|t| InferOk { value: t, obligations: lub.obligations() })
     }
 
     pub fn glb<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-        -> RelateResult<'tcx, T>
+        -> InferResult<'tcx, T>
         where T: Relate<'a, 'tcx>
     {
-        self.combine_fields(a_is_expected, trace).glb().relate(a, b)
+        let mut glb = self.combine_fields(a_is_expected, trace).glb();
+        let result = glb.relate(a, b);
+        result.map(|t| InferOk { value: t, obligations: glb.obligations() })
     }
 
     fn start_snapshot(&self) -> CombinedSnapshot {
@@ -829,12 +852,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                      origin: TypeOrigin,
                      a: Ty<'tcx>,
                      b: Ty<'tcx>)
-                     -> UnitResult<'tcx>
+        -> InferResult<'tcx, ()>
     {
         debug!("sub_types({:?} <: {:?})", a, b);
         self.commit_if_ok(|_| {
             let trace = TypeTrace::types(origin, a_is_expected, a, b);
-            self.sub(a_is_expected, trace, &a, &b).map(|_| ())
+            self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
         })
     }
 
@@ -843,11 +866,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     origin: TypeOrigin,
                     a: Ty<'tcx>,
                     b: Ty<'tcx>)
-                    -> UnitResult<'tcx>
+        -> InferResult<'tcx, ()>
     {
         self.commit_if_ok(|_| {
             let trace = TypeTrace::types(origin, a_is_expected, a, b);
-            self.equate(a_is_expected, trace, &a, &b).map(|_| ())
+            self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
         })
     }
 
@@ -856,7 +879,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                           origin: TypeOrigin,
                           a: ty::TraitRef<'tcx>,
                           b: ty::TraitRef<'tcx>)
-                          -> UnitResult<'tcx>
+        -> InferResult<'tcx, ()>
     {
         debug!("eq_trait_refs({:?} <: {:?})",
                a,
@@ -866,7 +889,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 origin: origin,
                 values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
             };
-            self.equate(a_is_expected, trace, &a, &b).map(|_| ())
+            self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
         })
     }
 
@@ -875,7 +898,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                origin: TypeOrigin,
                                a: ty::PolyTraitRef<'tcx>,
                                b: ty::PolyTraitRef<'tcx>)
-                               -> UnitResult<'tcx>
+        -> InferResult<'tcx, ()>
     {
         debug!("sub_poly_trait_refs({:?} <: {:?})",
                a,
@@ -885,7 +908,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 origin: origin,
                 values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
             };
-            self.sub(a_is_expected, trace, &a, &b).map(|_| ())
+            self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
         })
     }
 
@@ -928,20 +951,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn equality_predicate(&self,
                               span: Span,
                               predicate: &ty::PolyEquatePredicate<'tcx>)
-                              -> UnitResult<'tcx> {
+        -> InferResult<'tcx, ()>
+    {
         self.commit_if_ok(|snapshot| {
             let (ty::EquatePredicate(a, b), skol_map) =
                 self.skolemize_late_bound_regions(predicate, snapshot);
             let origin = TypeOrigin::EquatePredicate(span);
-            let () = mk_eqty(self, false, origin, a, b)?;
-            self.leak_check(&skol_map, snapshot)
+            let eqty_ok = mk_eqty(self, false, origin, a, b)?;
+            self.leak_check(&skol_map, snapshot).map(|_| eqty_ok.unit())
         })
     }
 
     pub fn region_outlives_predicate(&self,
                                      span: Span,
                                      predicate: &ty::PolyRegionOutlivesPredicate)
-                                     -> UnitResult<'tcx> {
+        -> UnitResult<'tcx>
+    {
         self.commit_if_ok(|snapshot| {
             let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
                 self.skolemize_late_bound_regions(predicate, snapshot);
diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs
index 0505c9d627b..ece8c0c696a 100644
--- a/src/librustc/infer/sub.rs
+++ b/src/librustc/infer/sub.rs
@@ -16,6 +16,7 @@ use super::type_variable::{SubtypeOf, SupertypeOf};
 use ty::{self, Ty, TyCtxt};
 use ty::TyVar;
 use ty::relate::{Cause, Relate, RelateResult, TypeRelation};
+use traits::PredicateObligations;
 use std::mem;
 
 /// Ensures `a` is made a subtype of `b`. Returns `a` on success.
@@ -27,6 +28,10 @@ impl<'a, 'tcx> Sub<'a, 'tcx> {
     pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> {
         Sub { fields: f }
     }
+
+    pub fn obligations(self) -> PredicateObligations<'tcx> {
+        self.fields.obligations
+    }
 }
 
 impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 879b8945620..1573d0c4292 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -179,6 +179,12 @@ declare_lint! {
     "lints that have been renamed or removed"
 }
 
+declare_lint! {
+    pub SUPER_OR_SELF_IN_GLOBAL_PATH,
+    Warn,
+    "detects super or self keywords at the beginning of global path"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -213,7 +219,8 @@ impl LintPass for HardwiredLints {
             RAW_POINTER_DERIVE,
             TRANSMUTE_FROM_FN_ITEM_TYPES,
             OVERLAPPING_INHERENT_IMPLS,
-            RENAMED_AND_REMOVED_LINTS
+            RENAMED_AND_REMOVED_LINTS,
+            SUPER_OR_SELF_IN_GLOBAL_PATH
         )
     }
 }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index cc37ee7dbda..4451e7ac472 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1502,7 +1502,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 } else {
                     let ends_with_stmt = match body.expr {
                         None if !body.stmts.is_empty() =>
-                            match body.stmts.first().unwrap().node {
+                            match body.stmts.last().unwrap().node {
                                 hir::StmtSemi(ref e, _) => {
                                     self.ir.tcx.expr_ty(&e) == t_ret
                                 },
@@ -1515,7 +1515,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                                                    E0269,
                                                    "not all control paths return a value");
                     if ends_with_stmt {
-                        let last_stmt = body.stmts.first().unwrap();
+                        let last_stmt = body.stmts.last().unwrap();
                         let original_span = original_sp(self.ir.tcx.sess.codemap(),
                                                         last_stmt.span, sp);
                         let span_semicolon = Span {
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 810dfb960c6..11e8dae8717 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use dep_graph::DepGraph;
-use infer::InferCtxt;
+use infer::{InferCtxt, InferOk};
 use ty::{self, Ty, TyCtxt, TypeFoldable, ToPolyTraitRef};
 use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error};
 use std::iter;
@@ -580,7 +580,11 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
 
         ty::Predicate::Equate(ref binder) => {
             match selcx.infcx().equality_predicate(obligation.cause.span, binder) {
-                Ok(()) => Ok(Some(Vec::new())),
+                Ok(InferOk { obligations, .. }) => {
+                    // FIXME(#32730) propagate obligations
+                    assert!(obligations.is_empty());
+                    Ok(Some(Vec::new()))
+                },
                 Err(_) => Err(CodeSelectionError(Unimplemented)),
             }
         }
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index f7b75c2259e..d4d61ec0244 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -24,7 +24,7 @@ use super::VtableImplData;
 use super::util;
 
 use middle::def_id::DefId;
-use infer::{self, TypeOrigin};
+use infer::{self, InferOk, TypeOrigin};
 use ty::subst::Subst;
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder};
@@ -232,7 +232,11 @@ fn project_and_unify_type<'cx,'tcx>(
     let infcx = selcx.infcx();
     let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
     match infer::mk_eqty(infcx, true, origin, normalized_ty, obligation.predicate.ty) {
-        Ok(()) => Ok(Some(obligations)),
+        Ok(InferOk { obligations: inferred_obligations, .. }) => {
+            // FIXME(#32730) propagate obligations
+            assert!(inferred_obligations.is_empty());
+            Ok(Some(obligations))
+        },
         Err(err) => Err(MismatchedProjectionTypes { err: err }),
     }
 }
@@ -278,7 +282,10 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext
             let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
             let obligation_ty = obligation.predicate.ty;
             match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) {
-                Ok(()) => { }
+                Ok(InferOk { obligations, .. }) => {
+                    // FIXME(#32730) propagate obligations
+                    assert!(obligations.is_empty());
+                }
                 Err(_) => { /* ignore errors */ }
             }
         }
@@ -829,7 +836,10 @@ fn assemble_candidates_from_predicates<'cx,'tcx,I>(
                     infcx.sub_poly_trait_refs(false,
                                               origin,
                                               data_poly_trait_ref,
-                                              obligation_poly_trait_ref).is_ok()
+                                              obligation_poly_trait_ref)
+                        // FIXME(#32730) propagate obligations
+                        .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
+                        .is_ok()
                 });
 
                 debug!("assemble_candidates_from_predicates: candidate={:?} \
@@ -1082,7 +1092,10 @@ fn confirm_param_env_candidate<'cx,'tcx>(
                               origin,
                               obligation.predicate.trait_ref.clone(),
                               projection.projection_ty.trait_ref.clone()) {
-        Ok(()) => { }
+        Ok(InferOk { obligations, .. }) => {
+            // FIXME(#32730) propagate obligations
+            assert!(obligations.is_empty());
+        }
         Err(e) => {
             span_bug!(
                 obligation.cause.span,
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 7635ff1eb4c..f68386feddb 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -38,7 +38,7 @@ use super::util;
 
 use middle::def_id::DefId;
 use infer;
-use infer::{InferCtxt, TypeFreshener, TypeOrigin};
+use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin};
 use ty::subst::{Subst, Substs, TypeSpace};
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use traits;
@@ -484,7 +484,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ty::Predicate::Equate(ref p) => {
                 // does this code ever run?
                 match self.infcx.equality_predicate(obligation.cause.span, p) {
-                    Ok(()) => EvaluatedToOk,
+                    Ok(InferOk { obligations, .. }) => {
+                        // FIXME(#32730) propagate obligations
+                        assert!(obligations.is_empty());
+                        EvaluatedToOk
+                    },
                     Err(_) => EvaluatedToErr
                 }
             }
@@ -1185,7 +1189,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                              origin,
                                              trait_bound.clone(),
                                              ty::Binder(skol_trait_ref.clone())) {
-            Ok(()) => { }
+            Ok(InferOk { obligations, .. }) => {
+                // FIXME(#32730) propagate obligations
+                assert!(obligations.is_empty());
+            }
             Err(_) => { return false; }
         }
 
@@ -2487,13 +2494,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let origin = TypeOrigin::RelateOutputImplTypes(obligation_cause.span);
 
         let obligation_trait_ref = obligation_trait_ref.clone();
-        match self.infcx.sub_poly_trait_refs(false,
-                                             origin,
-                                             expected_trait_ref.clone(),
-                                             obligation_trait_ref.clone()) {
-            Ok(()) => Ok(()),
-            Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
-        }
+        self.infcx.sub_poly_trait_refs(false,
+                                       origin,
+                                       expected_trait_ref.clone(),
+                                       obligation_trait_ref.clone())
+            // FIXME(#32730) propagate obligations
+            .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
+            .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
     }
 
     fn confirm_builtin_unsize_candidate(&mut self,
@@ -2524,9 +2531,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 let new_trait = tcx.mk_trait(data_a.principal.clone(), bounds);
                 let origin = TypeOrigin::Misc(obligation.cause.span);
-                if self.infcx.sub_types(false, origin, new_trait, target).is_err() {
-                    return Err(Unimplemented);
-                }
+                let InferOk { obligations, .. } =
+                    self.infcx.sub_types(false, origin, new_trait, target)
+                    .map_err(|_| Unimplemented)?;
+                // FIXME(#32730) propagate obligations
+                assert!(obligations.is_empty());
 
                 // Register one obligation for 'a: 'b.
                 let cause = ObligationCause::new(obligation.cause.span,
@@ -2589,9 +2598,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // [T; n] -> [T].
             (&ty::TyArray(a, _), &ty::TySlice(b)) => {
                 let origin = TypeOrigin::Misc(obligation.cause.span);
-                if self.infcx.sub_types(false, origin, a, b).is_err() {
-                    return Err(Unimplemented);
-                }
+                let InferOk { obligations, .. } =
+                    self.infcx.sub_types(false, origin, a, b)
+                    .map_err(|_| Unimplemented)?;
+                // FIXME(#32730) propagate obligations
+                assert!(obligations.is_empty());
             }
 
             // Struct<T> -> Struct<U>.
@@ -2647,9 +2658,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
                 let new_struct = tcx.mk_struct(def, tcx.mk_substs(new_substs));
                 let origin = TypeOrigin::Misc(obligation.cause.span);
-                if self.infcx.sub_types(false, origin, new_struct, target).is_err() {
-                    return Err(Unimplemented);
-                }
+                let InferOk { obligations, .. } =
+                    self.infcx.sub_types(false, origin, new_struct, target)
+                    .map_err(|_| Unimplemented)?;
+                // FIXME(#32730) propagate obligations
+                assert!(obligations.is_empty());
 
                 // Construct the nested Field<T>: Unsize<Field<U>> predicate.
                 nested.push(util::predicate_for_trait_def(tcx,
@@ -2734,13 +2747,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                skol_obligation_trait_ref);
 
         let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
-        if let Err(e) = self.infcx.eq_trait_refs(false,
-                                                 origin,
-                                                 impl_trait_ref.value.clone(),
-                                                 skol_obligation_trait_ref) {
-            debug!("match_impl: failed eq_trait_refs due to `{}`", e);
-            return Err(());
-        }
+        let InferOk { obligations, .. } =
+            self.infcx.eq_trait_refs(false,
+                                     origin,
+                                     impl_trait_ref.value.clone(),
+                                     skol_obligation_trait_ref)
+            .map_err(|e| {
+                debug!("match_impl: failed eq_trait_refs due to `{}`", e);
+                ()
+            })?;
+        // FIXME(#32730) propagate obligations
+        assert!(obligations.is_empty());
 
         if let Err(e) = self.infcx.leak_check(&skol_map, snapshot) {
             debug!("match_impl: failed leak check due to `{}`", e);
@@ -2803,13 +2820,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                poly_trait_ref);
 
         let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
-        match self.infcx.sub_poly_trait_refs(false,
-                                             origin,
-                                             poly_trait_ref,
-                                             obligation.predicate.to_poly_trait_ref()) {
-            Ok(()) => Ok(()),
-            Err(_) => Err(()),
-        }
+        self.infcx.sub_poly_trait_refs(false,
+                                       origin,
+                                       poly_trait_ref,
+                                       obligation.predicate.to_poly_trait_ref())
+            // FIXME(#32730) propagate obligations
+            .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
+            .map_err(|_| ())
     }
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 6ce623a3b28..ce0d42203b9 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -24,8 +24,8 @@ use rustc::ty::subst;
 use rustc::ty::subst::Subst;
 use rustc::traits::ProjectionMode;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::relate::{TypeRelation, RelateResult};
-use rustc::infer::{self, TypeOrigin};
+use rustc::ty::relate::TypeRelation;
+use rustc::infer::{self, InferOk, InferResult, TypeOrigin};
 use rustc_metadata::cstore::CStore;
 use rustc::front::map as hir_map;
 use rustc::session::{self, config};
@@ -355,17 +355,17 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
         infer::TypeTrace::dummy(self.tcx())
     }
 
-    pub fn sub(&self, t1: &Ty<'tcx>, t2: &Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+    pub fn sub(&self, t1: &Ty<'tcx>, t2: &Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
         let trace = self.dummy_type_trace();
         self.infcx.sub(true, trace, t1, t2)
     }
 
-    pub fn lub(&self, t1: &Ty<'tcx>, t2: &Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+    pub fn lub(&self, t1: &Ty<'tcx>, t2: &Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
         let trace = self.dummy_type_trace();
         self.infcx.lub(true, trace, t1, t2)
     }
 
-    pub fn glb(&self, t1: &Ty<'tcx>, t2: &Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+    pub fn glb(&self, t1: &Ty<'tcx>, t2: &Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
         let trace = self.dummy_type_trace();
         self.infcx.glb(true, trace, t1, t2)
     }
@@ -374,7 +374,10 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
     /// region checks).
     pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
         match self.sub(&t1, &t2) {
-            Ok(_) => {}
+            Ok(InferOk { obligations, .. }) => {
+                // FIXME(#32730) once obligations are being propagated, assert the right thing.
+                assert!(obligations.is_empty());
+            }
             Err(ref e) => {
                 panic!("unexpected error computing sub({:?},{:?}): {}", t1, t2, e);
             }
@@ -395,7 +398,10 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
     /// Checks that `LUB(t1,t2) == t_lub`
     pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
         match self.lub(&t1, &t2) {
-            Ok(t) => {
+            Ok(InferOk { obligations, value: t }) => {
+                // FIXME(#32730) once obligations are being propagated, assert the right thing.
+                assert!(obligations.is_empty());
+
                 self.assert_eq(t, t_lub);
             }
             Err(ref e) => {
@@ -411,7 +417,10 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
             Err(e) => {
                 panic!("unexpected error computing LUB: {:?}", e)
             }
-            Ok(t) => {
+            Ok(InferOk { obligations, value: t }) => {
+                // FIXME(#32730) once obligations are being propagated, assert the right thing.
+                assert!(obligations.is_empty());
+
                 self.assert_eq(t, t_glb);
 
                 // sanity check for good measure:
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 6e3a961caca..0780e4cd048 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -168,6 +168,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             reference: "PR 30742 <https://github.com/rust-lang/rust/pull/30724>",
         },
         FutureIncompatibleInfo {
+            id: LintId::of(SUPER_OR_SELF_IN_GLOBAL_PATH),
+            reference: "PR #32403 <https://github.com/rust-lang/rust/pull/32403>",
+        },
+        FutureIncompatibleInfo {
             id: LintId::of(MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT),
             reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\
                         master/text/0218-empty-struct-with-braces.md>",
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 6cfde27ac97..ce8ede7f4b9 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -12,7 +12,7 @@
 #![allow(unreachable_code)]
 
 use rustc::dep_graph::DepNode;
-use rustc::infer::{self, InferCtxt};
+use rustc::infer::{self, InferCtxt, InferOk};
 use rustc::traits::{self, ProjectionMode};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -338,6 +338,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     {
         infer::mk_subty(self.infcx, false, infer::TypeOrigin::Misc(span),
                         sup, sub)
+            // FIXME(#32730) propagate obligations
+            .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
     }
 
     fn mk_eqty(&self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
@@ -345,6 +347,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     {
         infer::mk_eqty(self.infcx, false, infer::TypeOrigin::Misc(span),
                        a, b)
+            // FIXME(#32730) propagate obligations
+            .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
     }
 
     fn tcx(&self) -> &'a TyCtxt<'tcx> {
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 7eb7d8cafe7..f36a8269dc0 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -23,13 +23,14 @@ use Resolver;
 use {resolve_error, resolve_struct_error, ResolutionError};
 
 use rustc::middle::cstore::{CrateStore, ChildItem, DlDef};
+use rustc::lint;
 use rustc::middle::def::*;
 use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::ty::VariantKind;
 
 use syntax::ast::Name;
 use syntax::attr::AttrMetaMethods;
-use syntax::parse::token::special_idents;
+use syntax::parse::token::{special_idents, SELF_KEYWORD_NAME, SUPER_KEYWORD_NAME};
 use syntax::codemap::{Span, DUMMY_SP};
 
 use rustc_front::hir;
@@ -116,8 +117,10 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> {
                 // Extract and intern the module part of the path. For
                 // globs and lists, the path is found directly in the AST;
                 // for simple paths we have to munge the path a little.
-                let module_path = match view_path.node {
+                let is_global;
+                let module_path: Vec<Name> = match view_path.node {
                     ViewPathSimple(_, ref full_path) => {
+                        is_global = full_path.global;
                         full_path.segments
                                  .split_last()
                                  .unwrap()
@@ -129,6 +132,7 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> {
 
                     ViewPathGlob(ref module_ident_path) |
                     ViewPathList(ref module_ident_path, _) => {
+                        is_global = module_ident_path.global;
                         module_ident_path.segments
                                          .iter()
                                          .map(|seg| seg.identifier.name)
@@ -136,6 +140,18 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> {
                     }
                 };
 
+                // Checking for special identifiers in path
+                // prevent `self` or `super` at beginning of global path
+                if is_global && (module_path.first() == Some(&SELF_KEYWORD_NAME) ||
+                                 module_path.first() == Some(&SUPER_KEYWORD_NAME)) {
+                    self.session.add_lint(
+                        lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH,
+                        item.id,
+                        item.span,
+                        format!("expected identifier, found keyword `{}`",
+                                module_path.first().unwrap().as_str()));
+                }
+
                 // Build up the import directives.
                 let is_prelude = item.attrs.iter().any(|attr| {
                     attr.name() == special_idents::prelude_import.name.as_str()
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 6dad3ff850b..55c3a5add37 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use middle::def::{self, Def};
-use rustc::infer::{self, TypeOrigin};
+use rustc::infer::{self, InferOk, TypeOrigin};
 use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
 use middle::pat_util::pat_is_resolved_const;
 use rustc::ty::subst::Substs;
@@ -531,7 +531,12 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         };
 
         let result = if is_if_let_fallback {
-            fcx.infcx().eq_types(true, origin, arm_ty, result_ty).map(|_| arm_ty)
+            fcx.infcx().eq_types(true, origin, arm_ty, result_ty)
+                .map(|InferOk { obligations, .. }| {
+                    // FIXME(#32730) propagate obligations
+                    assert!(obligations.is_empty());
+                    arm_ty
+                })
         } else if i == 0 {
             // Special-case the first arm, as it has no "previous expressions".
             coercion::try(fcx, &arm.body, coerce_first)
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 70467e2d2dd..cafd0519c28 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -62,7 +62,7 @@
 
 use check::{autoderef, FnCtxt, UnresolvedTypeAction};
 
-use rustc::infer::{Coercion, TypeOrigin, TypeTrace};
+use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
 use rustc::traits::{self, ObligationCause};
 use rustc::traits::{predicate_for_trait_def, report_selection_error};
 use rustc::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
@@ -118,8 +118,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             let trace = TypeTrace::types(self.origin, false, a, b);
             if self.use_lub {
                 infcx.lub(false, trace, &a, &b)
+                    .map(|InferOk { value, obligations }| {
+                        // FIXME(#32730) propagate obligations
+                        assert!(obligations.is_empty());
+                        value
+                    })
             } else {
                 infcx.sub(false, trace, &a, &b)
+                    .map(|InferOk { value, obligations }| {
+                        // FIXME(#32730) propagate obligations
+                        assert!(obligations.is_empty());
+                        value
+                    })
             }
         })
     }
@@ -655,12 +665,22 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
         (&ty::TyFnDef(a_def_id, a_substs, a_fty),
          &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
             // The signature must always match.
-            let fty = fcx.infcx().lub(true, trace.clone(), a_fty, b_fty)?;
+            let fty = fcx.infcx().lub(true, trace.clone(), a_fty, b_fty)
+                .map(|InferOk { value, obligations }| {
+                    // FIXME(#32730) propagate obligations
+                    assert!(obligations.is_empty());
+                    value
+                })?;
 
             if a_def_id == b_def_id {
                 // Same function, maybe the parameters match.
                 let substs = fcx.infcx().commit_if_ok(|_| {
                     fcx.infcx().lub(true, trace.clone(), a_substs, b_substs)
+                        .map(|InferOk { value, obligations }| {
+                            // FIXME(#32730) propagate obligations
+                            assert!(obligations.is_empty());
+                            value
+                        })
                 }).map(|s| fcx.tcx().mk_substs(s));
 
                 if let Ok(substs) = substs {
@@ -724,6 +744,11 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
         if !noop {
             return fcx.infcx().commit_if_ok(|_| {
                 fcx.infcx().lub(true, trace.clone(), &prev_ty, &new_ty)
+                    .map(|InferOk { value, obligations }| {
+                        // FIXME(#32730) propagate obligations
+                        assert!(obligations.is_empty());
+                        value
+                    })
             });
         }
     }
@@ -736,6 +761,11 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
             } else {
                 fcx.infcx().commit_if_ok(|_| {
                     fcx.infcx().lub(true, trace, &prev_ty, &new_ty)
+                        .map(|InferOk { value, obligations }| {
+                            // FIXME(#32730) propagate obligations
+                            assert!(obligations.is_empty());
+                            value
+                        })
                 })
             }
         }
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 6d429fa7b73..3c12ab8d598 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use middle::free_region::FreeRegionMap;
-use rustc::infer::{self, TypeOrigin};
+use rustc::infer::{self, InferOk, TypeOrigin};
 use rustc::ty::{self, TyCtxt};
 use rustc::traits::{self, ProjectionMode};
 use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace};
@@ -475,7 +475,10 @@ pub fn compare_const_impl<'tcx>(tcx: &TyCtxt<'tcx>,
     });
 
     match err {
-        Ok(()) => { }
+        Ok(InferOk { obligations, .. }) => {
+            // FIXME(#32730) propagate obligations
+            assert!(obligations.is_empty())
+        }
         Err(terr) => {
             debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
                    impl_ty,
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index d8bdf6c61aa..bc2ef9aafee 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -11,7 +11,7 @@
 
 use check::{coercion, FnCtxt};
 use rustc::ty::Ty;
-use rustc::infer::TypeOrigin;
+use rustc::infer::{InferOk, TypeOrigin};
 
 use syntax::codemap::Span;
 use rustc_front::hir;
@@ -21,16 +21,28 @@ use rustc_front::hir;
 pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
                          expected: Ty<'tcx>, actual: Ty<'tcx>) {
     let origin = TypeOrigin::Misc(sp);
-    if let Err(e) = fcx.infcx().sub_types(false, origin, actual, expected) {
-        fcx.infcx().report_mismatched_types(origin, expected, actual, e);
+    match fcx.infcx().sub_types(false, origin, actual, expected) {
+        Ok(InferOk { obligations, .. }) => {
+            // FIXME(#32730) propagate obligations
+            assert!(obligations.is_empty());
+        },
+        Err(e) => {
+            fcx.infcx().report_mismatched_types(origin, expected, actual, e);
+        }
     }
 }
 
 pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
                         expected: Ty<'tcx>, actual: Ty<'tcx>) {
     let origin = TypeOrigin::Misc(sp);
-    if let Err(e) = fcx.infcx().eq_types(false, origin, actual, expected) {
-        fcx.infcx().report_mismatched_types(origin, expected, actual, e);
+    match fcx.infcx().eq_types(false, origin, actual, expected) {
+        Ok(InferOk { obligations, .. }) => {
+            // FIXME(#32730) propagate obligations
+            assert!(obligations.is_empty());
+        },
+        Err(e) => {
+            fcx.infcx().report_mismatched_types(origin, expected, actual, e);
+        }
     }
 }
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index c4a8022071b..2e15ac0e130 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -21,8 +21,7 @@ use rustc::ty::subst;
 use rustc::ty::subst::Subst;
 use rustc::traits;
 use rustc::ty::{self, NoPreference, Ty, TyCtxt, ToPolyTraitRef, TraitRef, TypeFoldable};
-use rustc::infer;
-use rustc::infer::{InferCtxt, TypeOrigin};
+use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin};
 use syntax::ast;
 use syntax::codemap::{Span, DUMMY_SP};
 use rustc_front::hir;
@@ -1151,6 +1150,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
     fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::UnitResult<'tcx> {
         self.infcx().sub_types(false, TypeOrigin::Misc(DUMMY_SP), sub, sup)
+            // FIXME(#32730) propagate obligations
+            .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
     }
 
     fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool {
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 4d806bda484..32b5a63817e 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -14,7 +14,7 @@
 use CrateCtxt;
 
 use astconv::AstConv;
-use check::{self, FnCtxt};
+use check::{self, FnCtxt, UnresolvedTypeAction, autoderef};
 use front::map as hir_map;
 use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
 use middle::cstore::{self, CrateStore};
@@ -22,6 +22,7 @@ use middle::def::Def;
 use middle::def_id::DefId;
 use middle::lang_items::FnOnceTraitLangItem;
 use rustc::ty::subst::Substs;
+use rustc::ty::LvaluePreference;
 use rustc::traits::{Obligation, SelectionContext};
 use util::nodemap::{FnvHashSet};
 
@@ -50,23 +51,37 @@ fn is_fn_ty<'a, 'tcx>(ty: &Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> bool
             if let Ok(fn_once_trait_did) =
                     cx.lang_items.require(FnOnceTraitLangItem) {
                 let infcx = fcx.infcx();
-                infcx.probe(|_| {
-                    let fn_once_substs =
-                        Substs::new_trait(vec![infcx.next_ty_var()],
-                                          Vec::new(),
-                                          ty);
-                    let trait_ref =
-                      ty::TraitRef::new(fn_once_trait_did,
-                                        cx.mk_substs(fn_once_substs));
-                    let poly_trait_ref = trait_ref.to_poly_trait_ref();
-                    let obligation = Obligation::misc(span,
-                                                      fcx.body_id,
-                                                      poly_trait_ref
-                                                         .to_predicate());
-                    let mut selcx = SelectionContext::new(infcx);
-
-                    return selcx.evaluate_obligation(&obligation)
-                })
+                let (_, _, opt_is_fn) = autoderef(fcx,
+                                                  span,
+                                                  ty,
+                                                  || None,
+                                                  UnresolvedTypeAction::Ignore,
+                                                  LvaluePreference::NoPreference,
+                                                  |ty, _| {
+                    infcx.probe(|_| {
+                        let fn_once_substs =
+                            Substs::new_trait(vec![infcx.next_ty_var()],
+                                              Vec::new(),
+                                              ty);
+                        let trait_ref =
+                          ty::TraitRef::new(fn_once_trait_did,
+                                            cx.mk_substs(fn_once_substs));
+                        let poly_trait_ref = trait_ref.to_poly_trait_ref();
+                        let obligation = Obligation::misc(span,
+                                                          fcx.body_id,
+                                                          poly_trait_ref
+                                                             .to_predicate());
+                        let mut selcx = SelectionContext::new(infcx);
+
+                        if selcx.evaluate_obligation(&obligation) {
+                            Some(())
+                        } else {
+                            None
+                        }
+                    })
+                });
+
+                opt_is_fn.is_some()
             } else {
                 false
             }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 6c3469c9d72..e485fbe1621 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -88,8 +88,7 @@ use middle::astconv_util::prohibit_type_params;
 use middle::cstore::LOCAL_CRATE;
 use middle::def::{self, Def};
 use middle::def_id::DefId;
-use rustc::infer;
-use rustc::infer::{TypeOrigin, TypeTrace, type_variable};
+use rustc::infer::{self, InferOk, TypeOrigin, TypeTrace, type_variable};
 use middle::pat_util::{self, pat_id_map};
 use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
 use rustc::traits::{self, report_fulfillment_errors, ProjectionMode};
@@ -1627,6 +1626,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     sup: Ty<'tcx>)
                     -> Result<(), TypeError<'tcx>> {
         infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup)
+            // FIXME(#32730) propagate obligations
+            .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
     }
 
     pub fn mk_eqty(&self,
@@ -1636,6 +1637,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                    sup: Ty<'tcx>)
                    -> Result<(), TypeError<'tcx>> {
         infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup)
+            // FIXME(#32730) propagate obligations
+            .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
     }
 
     pub fn mk_subr(&self,
@@ -1914,7 +1917,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     match infer::mk_eqty(self.infcx(), false,
                                                          TypeOrigin::Misc(default.origin_span),
                                                          ty, default.ty) {
-                                        Ok(()) => {}
+                                        Ok(InferOk { obligations, .. }) => {
+                                            // FIXME(#32730) propagate obligations
+                                            assert!(obligations.is_empty())
+                                        },
                                         Err(_) => {
                                             conflicts.push((*ty, default));
                                         }
@@ -2007,7 +2013,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             match infer::mk_eqty(self.infcx(), false,
                                                  TypeOrigin::Misc(default.origin_span),
                                                  ty, default.ty) {
-                                Ok(()) => {}
+                                // FIXME(#32730) propagate obligations
+                                Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
                                 Err(_) => {
                                     result = Some(default);
                                 }
@@ -2773,8 +2780,10 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 let ures = fcx.infcx().sub_types(false, origin, formal_ret_ty, ret_ty);
                 // FIXME(#15760) can't use try! here, FromError doesn't default
                 // to identity so the resulting type is not constrained.
-                if let Err(e) = ures {
-                    return Err(e);
+                match ures {
+                    // FIXME(#32730) propagate obligations
+                    Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
+                    Err(e) => return Err(e),
                 }
 
                 // Record all the argument types, with the substitutions
@@ -2902,13 +2911,23 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 fcx.infcx().commit_if_ok(|_| {
                     let trace = TypeTrace::types(origin, true, then_ty, else_ty);
                     fcx.infcx().lub(true, trace, &then_ty, &else_ty)
+                        .map(|InferOk { value, obligations }| {
+                            // FIXME(#32730) propagate obligations
+                            assert!(obligations.is_empty());
+                            value
+                        })
                 })
             };
             (origin, then_ty, else_ty, result)
         } else {
             let origin = TypeOrigin::IfExpressionWithNoElse(sp);
             (origin, unit, then_ty,
-             fcx.infcx().eq_types(true, origin, unit, then_ty).map(|_| unit))
+             fcx.infcx().eq_types(true, origin, unit, then_ty)
+                 .map(|InferOk { obligations, .. }| {
+                     // FIXME(#32730) propagate obligations
+                     assert!(obligations.is_empty());
+                     unit
+                 }))
         };
 
         let if_ty = match result {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 283245bd6f4..15bf6671de5 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -92,7 +92,7 @@ use middle::region::{self, CodeExtent};
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, MethodCall, TypeFoldable};
-use rustc::infer::{self, GenericKind, InferCtxt, SubregionOrigin, TypeOrigin, VerifyBound};
+use rustc::infer::{self, GenericKind, InferCtxt, InferOk, SubregionOrigin, TypeOrigin, VerifyBound};
 use middle::pat_util;
 use rustc::ty::adjustment;
 use rustc::ty::wf::ImpliedBound;
@@ -1841,7 +1841,11 @@ fn declared_projection_bounds_from_trait<'a,'tcx>(rcx: &Rcx<'a, 'tcx>,
 
                 // check whether this predicate applies to our current projection
                 match infer::mk_eqty(infcx, false, TypeOrigin::Misc(span), ty, outlives.0) {
-                    Ok(()) => { Ok(outlives.1) }
+                    Ok(InferOk { obligations, .. }) => {
+                        // FIXME(#32730) propagate obligations
+                        assert!(obligations.is_empty());
+                        Ok(outlives.1)
+                    }
                     Err(_) => { Err(()) }
                 }
             });
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b26e56008ac..7437d608771 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -14,7 +14,6 @@
 pub use self::Type::*;
 pub use self::PrimitiveType::*;
 pub use self::TypeKind::*;
-pub use self::StructField::*;
 pub use self::VariantKind::*;
 pub use self::Mutability::*;
 pub use self::Import::*;
@@ -53,6 +52,7 @@ use std::env::current_dir;
 use core::DocContext;
 use doctree;
 use visit_ast;
+use html::item_type::ItemType;
 
 /// A stable identifier to the particular version of JSON output.
 /// Increment this when the `Crate` and related structures change.
@@ -273,36 +273,49 @@ impl Item {
     }
     pub fn is_crate(&self) -> bool {
         match self.inner {
-            ModuleItem(Module { items: _, is_crate: true }) => true,
-            _ => false
+            StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
+            ModuleItem(Module { is_crate: true, ..}) => true,
+            _ => false,
         }
     }
     pub fn is_mod(&self) -> bool {
-        match self.inner { ModuleItem(..) => true, _ => false }
+        ItemType::from_item(self) == ItemType::Module
     }
     pub fn is_trait(&self) -> bool {
-        match self.inner { TraitItem(..) => true, _ => false }
+        ItemType::from_item(self) == ItemType::Trait
     }
     pub fn is_struct(&self) -> bool {
-        match self.inner { StructItem(..) => true, _ => false }
+        ItemType::from_item(self) == ItemType::Struct
     }
     pub fn is_enum(&self) -> bool {
-        match self.inner { EnumItem(..) => true, _ => false }
+        ItemType::from_item(self) == ItemType::Module
     }
     pub fn is_fn(&self) -> bool {
-        match self.inner { FunctionItem(..) => true, _ => false }
+        ItemType::from_item(self) == ItemType::Function
     }
     pub fn is_associated_type(&self) -> bool {
-        match self.inner { AssociatedTypeItem(..) => true, _ => false }
+        ItemType::from_item(self) == ItemType::AssociatedType
     }
     pub fn is_associated_const(&self) -> bool {
-        match self.inner { AssociatedConstItem(..) => true, _ => false }
+        ItemType::from_item(self) == ItemType::AssociatedConst
     }
     pub fn is_method(&self) -> bool {
-        match self.inner { MethodItem(..) => true, _ => false }
+        ItemType::from_item(self) == ItemType::Method
     }
     pub fn is_ty_method(&self) -> bool {
-        match self.inner { TyMethodItem(..) => true, _ => false }
+        ItemType::from_item(self) == ItemType::TyMethod
+    }
+    pub fn is_stripped(&self) -> bool {
+        match self.inner { StrippedItem(..) => true, _ => false }
+    }
+    pub fn has_stripped_fields(&self) -> Option<bool> {
+        match self.inner {
+            StructItem(ref _struct) => Some(_struct.fields_stripped),
+            VariantItem(Variant { kind: StructVariant(ref vstruct)} ) => {
+                Some(vstruct.fields_stripped)
+            },
+            _ => None,
+        }
     }
 
     pub fn stability_class(&self) -> String {
@@ -341,7 +354,7 @@ pub enum ItemEnum {
     TyMethodItem(TyMethod),
     /// A method with a body.
     MethodItem(Method),
-    StructFieldItem(StructField),
+    StructFieldItem(Type),
     VariantItem(Variant),
     /// `fn`s from an extern block
     ForeignFunctionItem(Function),
@@ -352,6 +365,8 @@ pub enum ItemEnum {
     AssociatedConstItem(Type, Option<String>),
     AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
     DefaultImplItem(DefaultImpl),
+    /// An item that has been stripped by a rustdoc pass
+    StrippedItem(Box<ItemEnum>),
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -1733,12 +1748,6 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
     }
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum StructField {
-    HiddenStructField, // inserted later by strip passes
-    TypedStructField(Type),
-}
-
 impl Clean<Item> for hir::StructField {
     fn clean(&self, cx: &DocContext) -> Item {
         Item {
@@ -1749,7 +1758,7 @@ impl Clean<Item> for hir::StructField {
             stability: get_stability(cx, cx.map.local_def_id(self.id)),
             deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
             def_id: cx.map.local_def_id(self.id),
-            inner: StructFieldItem(TypedStructField(self.ty.clean(cx))),
+            inner: StructFieldItem(self.ty.clean(cx)),
         }
     }
 }
@@ -1766,7 +1775,7 @@ impl<'tcx> Clean<Item> for ty::FieldDefData<'tcx, 'static> {
             stability: get_stability(cx, self.did),
             deprecation: get_deprecation(cx, self.did),
             def_id: self.did,
-            inner: StructFieldItem(TypedStructField(self.unsubst_ty().clean(cx))),
+            inner: StructFieldItem(self.unsubst_ty().clean(cx)),
         }
     }
 }
@@ -1897,9 +1906,7 @@ impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
                             def_id: field.did,
                             stability: get_stability(cx, field.did),
                             deprecation: get_deprecation(cx, field.did),
-                            inner: StructFieldItem(
-                                TypedStructField(field.unsubst_ty().clean(cx))
-                            )
+                            inner: StructFieldItem(field.unsubst_ty().clean(cx))
                         }
                     }).collect()
                 })
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index ceec80402c0..5595c749256 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -10,28 +10,50 @@
 
 use clean::*;
 
+pub enum FoldItem {
+    Retain(Item),
+    Strip(Item),
+    Erase,
+}
+
+impl FoldItem {
+    pub fn fold(self) -> Option<Item> {
+        match self {
+            FoldItem::Erase => None,
+            FoldItem::Retain(i) => Some(i),
+            FoldItem::Strip(item@ Item { inner: StrippedItem(..), .. } ) => Some(item),
+            FoldItem::Strip(mut i) => {
+                i.inner = StrippedItem(box i.inner);
+                Some(i)
+            }
+        }
+    }
+}
+
 pub trait DocFolder : Sized {
     fn fold_item(&mut self, item: Item) -> Option<Item> {
         self.fold_item_recur(item)
     }
 
     /// don't override!
-    fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
-        let Item { attrs, name, source, visibility, def_id, inner, stability, deprecation } = item;
-        let inner = match inner {
+    fn fold_inner_recur(&mut self, inner: ItemEnum) -> ItemEnum {
+        match inner {
+            StrippedItem(..) => unreachable!(),
+            ModuleItem(i) => {
+                ModuleItem(self.fold_mod(i))
+            },
             StructItem(mut i) => {
                 let num_fields = i.fields.len();
                 i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                i.fields_stripped |= num_fields != i.fields.len();
+                i.fields_stripped |= num_fields != i.fields.len() ||
+                                     i.fields.iter().any(|f| f.is_stripped());
                 StructItem(i)
             },
-            ModuleItem(i) => {
-                ModuleItem(self.fold_mod(i))
-            },
             EnumItem(mut i) => {
                 let num_variants = i.variants.len();
                 i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                i.variants_stripped |= num_variants != i.variants.len();
+                i.variants_stripped |= num_variants != i.variants.len() ||
+                                       i.variants.iter().any(|f| f.is_stripped());
                 EnumItem(i)
             },
             TraitItem(mut i) => {
@@ -48,13 +70,24 @@ pub trait DocFolder : Sized {
                     StructVariant(mut j) => {
                         let num_fields = j.fields.len();
                         j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                        j.fields_stripped |= num_fields != j.fields.len();
+                        j.fields_stripped |= num_fields != j.fields.len() ||
+                                             j.fields.iter().any(|f| f.is_stripped());
                         VariantItem(Variant {kind: StructVariant(j), ..i2})
                     },
                     _ => VariantItem(i2)
                 }
             },
             x => x
+        }
+    }
+
+    /// don't override!
+    fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
+        let Item { attrs, name, source, visibility, def_id, inner, stability, deprecation } = item;
+
+        let inner = match inner {
+            StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
+            _ => self.fold_inner_recur(inner),
         };
 
         Some(Item { attrs: attrs, name: name, source: source, inner: inner,
@@ -70,9 +103,8 @@ pub trait DocFolder : Sized {
     }
 
     fn fold_crate(&mut self, mut c: Crate) -> Crate {
-        c.module = c.module.and_then(|module| {
-            self.fold_item(module)
-        });
+        c.module = c.module.and_then(|module| self.fold_item(module));
+
         c.external_traits = c.external_traits.into_iter().map(|(k, mut v)| {
             v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
             (k, v)
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index b3cad90ccb5..7ca4703a2e1 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -17,22 +17,36 @@ use html::escape::Escape;
 
 use std::io;
 use std::io::prelude::*;
-use syntax::parse::lexer;
+use syntax::parse::lexer::{self, Reader};
 use syntax::parse::token;
 use syntax::parse;
 
-/// Highlights some source code, returning the HTML output.
-pub fn highlight(src: &str, class: Option<&str>, id: Option<&str>) -> String {
+/// Highlights `src`, returning the HTML output.
+pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>) -> String {
     debug!("highlighting: ================\n{}\n==============", src);
     let sess = parse::ParseSess::new();
     let fm = sess.codemap().new_filemap("<stdin>".to_string(), src.to_string());
 
     let mut out = Vec::new();
-    doit(&sess,
-         lexer::StringReader::new(&sess.span_diagnostic, fm),
-         class,
-         id,
-         &mut out).unwrap();
+    write_header(class, id, &mut out).unwrap();
+    write_source(&sess,
+                 lexer::StringReader::new(&sess.span_diagnostic, fm),
+                 &mut out).unwrap();
+    write_footer(&mut out).unwrap();
+    String::from_utf8_lossy(&out[..]).into_owned()
+}
+
+/// Highlights `src`, returning the HTML output. Returns only the inner html to
+/// be inserted into an element. C.f., `render_with_highlighting` which includes
+/// an enclosing `<pre>` block.
+pub fn render_inner_with_highlighting(src: &str) -> String {
+    let sess = parse::ParseSess::new();
+    let fm = sess.codemap().new_filemap("<stdin>".to_string(), src.to_string());
+
+    let mut out = Vec::new();
+    write_source(&sess,
+                 lexer::StringReader::new(&sess.span_diagnostic, fm),
+                 &mut out).unwrap();
     String::from_utf8_lossy(&out[..]).into_owned()
 }
 
@@ -43,17 +57,10 @@ pub fn highlight(src: &str, class: Option<&str>, id: Option<&str>) -> String {
 /// it's used. All source code emission is done as slices from the source map,
 /// not from the tokens themselves, in order to stay true to the original
 /// source.
-fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader,
-        class: Option<&str>, id: Option<&str>,
-        out: &mut Write) -> io::Result<()> {
-    use syntax::parse::lexer::Reader;
-
-    write!(out, "<pre ")?;
-    match id {
-        Some(id) => write!(out, "id='{}' ", id)?,
-        None => {}
-    }
-    write!(out, "class='rust {}'>\n", class.unwrap_or(""))?;
+fn write_source(sess: &parse::ParseSess,
+                mut lexer: lexer::StringReader,
+                out: &mut Write)
+                -> io::Result<()> {
     let mut is_attribute = false;
     let mut is_macro = false;
     let mut is_macro_nonterminal = false;
@@ -184,5 +191,21 @@ fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader,
         }
     }
 
+    Ok(())
+}
+
+fn write_header(class: Option<&str>,
+                id: Option<&str>,
+                out: &mut Write)
+                -> io::Result<()> {
+    write!(out, "<pre ")?;
+    match id {
+        Some(id) => write!(out, "id='{}' ", id)?,
+        None => {}
+    }
+    write!(out, "class='rust {}'>\n", class.unwrap_or(""))
+}
+
+fn write_footer(out: &mut Write) -> io::Result<()> {
     write!(out, "</pre>\n")
 }
diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs
index afc93f41172..74f7b099044 100644
--- a/src/librustdoc/html/item_type.rs
+++ b/src/librustdoc/html/item_type.rs
@@ -44,7 +44,12 @@ pub enum ItemType {
 
 impl ItemType {
     pub fn from_item(item: &clean::Item) -> ItemType {
-        match item.inner {
+        let inner = match item.inner {
+            clean::StrippedItem(box ref item) => item,
+            ref inner@_ => inner,
+        };
+
+        match *inner {
             clean::ModuleItem(..)          => ItemType::Module,
             clean::ExternCrateItem(..)     => ItemType::ExternCrate,
             clean::ImportItem(..)          => ItemType::Import,
@@ -67,6 +72,7 @@ impl ItemType {
             clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
             clean::AssociatedTypeItem(..)  => ItemType::AssociatedType,
             clean::DefaultImplItem(..)     => ItemType::Impl,
+            clean::StrippedItem(..)        => unreachable!(),
         }
     }
 
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index e7304b69510..3baf22b38ef 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -262,9 +262,9 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
                                               &Default::default());
                     s.push_str(&format!("<span class='rusttest'>{}</span>", Escape(&test)));
                 });
-                s.push_str(&highlight::highlight(&text,
-                                                 Some("rust-example-rendered"),
-                                                 None));
+                s.push_str(&highlight::render_with_highlighting(&text,
+                                                                Some("rust-example-rendered"),
+                                                                None));
                 let output = CString::new(s).unwrap();
                 hoedown_buffer_puts(ob, output.as_ptr());
             })
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 0f436efd70b..1427dfcbaf1 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -91,12 +91,20 @@ pub struct Context {
     /// String representation of how to get back to the root path of the 'doc/'
     /// folder in terms of a relative URL.
     pub root_path: String,
-    /// The path to the crate root source minus the file name.
-    /// Used for simplifying paths to the highlighted source code files.
-    pub src_root: PathBuf,
     /// The current destination folder of where HTML artifacts should be placed.
     /// This changes as the context descends into the module hierarchy.
     pub dst: PathBuf,
+    /// A flag, which when `true`, will render pages which redirect to the
+    /// real location of an item. This is used to allow external links to
+    /// publicly reused items to redirect to the right location.
+    pub render_redirect_pages: bool,
+    pub shared: Arc<SharedContext>,
+}
+
+pub struct SharedContext {
+    /// The path to the crate root source minus the file name.
+    /// Used for simplifying paths to the highlighted source code files.
+    pub src_root: PathBuf,
     /// This describes the layout of each page, and is not modified after
     /// creation of the context (contains info like the favicon and added html).
     pub layout: layout::Layout,
@@ -106,10 +114,6 @@ pub struct Context {
     pub include_sources: bool,
     /// The local file sources we've emitted and their respective url-paths.
     pub local_sources: HashMap<PathBuf, String>,
-    /// A flag, which when turned off, will render pages which redirect to the
-    /// real location of an item. This is used to allow external links to
-    /// publicly reused items to redirect to the right location.
-    pub render_redirect_pages: bool,
     /// All the passes that were run on this crate.
     pub passes: HashSet<String>,
     /// The base-URL of the issue tracker for when an item has been tagged with
@@ -245,8 +249,7 @@ pub struct Cache {
     parent_stack: Vec<DefId>,
     parent_is_trait_impl: bool,
     search_index: Vec<IndexItem>,
-    privmod: bool,
-    remove_priv: bool,
+    stripped_mod: bool,
     access_levels: AccessLevels<DefId>,
     deref_trait_did: Option<DefId>,
 
@@ -260,7 +263,7 @@ pub struct Cache {
 
 /// Helper struct to render all source code to HTML pages
 struct SourceCollector<'a> {
-    cx: &'a mut Context,
+    scx: &'a mut SharedContext,
 
     /// Root destination to place all HTML output into
     dst: PathBuf,
@@ -413,12 +416,12 @@ pub fn run(mut krate: clean::Crate,
         Some(p) => p.to_path_buf(),
         None => PathBuf::new(),
     };
-    let mut cx = Context {
-        dst: dst,
+    let mut scx = SharedContext {
         src_root: src_root,
         passes: passes,
-        current: Vec::new(),
-        root_path: String::new(),
+        include_sources: true,
+        local_sources: HashMap::new(),
+        issue_tracker_base_url: None,
         layout: layout::Layout {
             logo: "".to_string(),
             favicon: "".to_string(),
@@ -426,14 +429,8 @@ pub fn run(mut krate: clean::Crate,
             krate: krate.name.clone(),
             playground_url: "".to_string(),
         },
-        include_sources: true,
-        local_sources: HashMap::new(),
-        render_redirect_pages: false,
-        issue_tracker_base_url: None,
     };
 
-    try_err!(mkdir(&cx.dst), &cx.dst);
-
     // Crawl the crate attributes looking for attributes which control how we're
     // going to emit HTML
     if let Some(attrs) = krate.module.as_ref().map(|m| m.attrs.list("doc")) {
@@ -441,15 +438,15 @@ pub fn run(mut krate: clean::Crate,
             match *attr {
                 clean::NameValue(ref x, ref s)
                         if "html_favicon_url" == *x => {
-                    cx.layout.favicon = s.to_string();
+                    scx.layout.favicon = s.to_string();
                 }
                 clean::NameValue(ref x, ref s)
                         if "html_logo_url" == *x => {
-                    cx.layout.logo = s.to_string();
+                    scx.layout.logo = s.to_string();
                 }
                 clean::NameValue(ref x, ref s)
                         if "html_playground_url" == *x => {
-                    cx.layout.playground_url = s.to_string();
+                    scx.layout.playground_url = s.to_string();
                     markdown::PLAYGROUND_KRATE.with(|slot| {
                         if slot.borrow().is_none() {
                             let name = krate.name.clone();
@@ -459,16 +456,25 @@ pub fn run(mut krate: clean::Crate,
                 }
                 clean::NameValue(ref x, ref s)
                         if "issue_tracker_base_url" == *x => {
-                    cx.issue_tracker_base_url = Some(s.to_string());
+                    scx.issue_tracker_base_url = Some(s.to_string());
                 }
                 clean::Word(ref x)
                         if "html_no_source" == *x => {
-                    cx.include_sources = false;
+                    scx.include_sources = false;
                 }
                 _ => {}
             }
         }
     }
+    try_err!(mkdir(&dst), &dst);
+    krate = render_sources(&dst, &mut scx, krate)?;
+    let cx = Context {
+        current: Vec::new(),
+        root_path: String::new(),
+        dst: dst,
+        render_redirect_pages: false,
+        shared: Arc::new(scx),
+    };
 
     // Crawl the crate to build various caches used for the output
     let analysis = ::ANALYSISKEY.with(|a| a.clone());
@@ -492,8 +498,7 @@ pub fn run(mut krate: clean::Crate,
         parent_is_trait_impl: false,
         extern_locations: HashMap::new(),
         primitive_locations: HashMap::new(),
-        remove_priv: cx.passes.contains("strip-private"),
-        privmod: false,
+        stripped_mod: false,
         access_levels: access_levels,
         orphan_methods: Vec::new(),
         traits: mem::replace(&mut krate.external_traits, HashMap::new()),
@@ -540,7 +545,6 @@ pub fn run(mut krate: clean::Crate,
     CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear());
 
     write_shared(&cx, &krate, &*cache, index)?;
-    let krate = render_sources(&mut cx, krate)?;
 
     // And finally render the whole crate's documentation
     cx.krate(krate)
@@ -762,16 +766,16 @@ fn write_shared(cx: &Context,
     Ok(())
 }
 
-fn render_sources(cx: &mut Context,
+fn render_sources(dst: &Path, scx: &mut SharedContext,
                   krate: clean::Crate) -> Result<clean::Crate, Error> {
     info!("emitting source files");
-    let dst = cx.dst.join("src");
+    let dst = dst.join("src");
     try_err!(mkdir(&dst), &dst);
     let dst = dst.join(&krate.name);
     try_err!(mkdir(&dst), &dst);
     let mut folder = SourceCollector {
         dst: dst,
-        cx: cx,
+        scx: scx,
     };
     Ok(folder.fold_crate(krate))
 }
@@ -849,7 +853,7 @@ impl<'a> DocFolder for SourceCollector<'a> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         // If we're including source files, and we haven't seen this file yet,
         // then we need to render it out to the filesystem
-        if self.cx.include_sources
+        if self.scx.include_sources
             // skip all invalid spans
             && item.source.filename != ""
             // macros from other libraries get special filenames which we can
@@ -862,7 +866,7 @@ impl<'a> DocFolder for SourceCollector<'a> {
             // something like that), so just don't include sources for the
             // entire crate. The other option is maintaining this mapping on a
             // per-file basis, but that's probably not worth it...
-            self.cx
+            self.scx
                 .include_sources = match self.emit_source(&item.source.filename) {
                 Ok(()) => true,
                 Err(e) => {
@@ -874,7 +878,6 @@ impl<'a> DocFolder for SourceCollector<'a> {
                 }
             };
         }
-
         self.fold_item_recur(item)
     }
 }
@@ -883,7 +886,7 @@ impl<'a> SourceCollector<'a> {
     /// Renders the given filename into its corresponding HTML source file.
     fn emit_source(&mut self, filename: &str) -> io::Result<()> {
         let p = PathBuf::from(filename);
-        if self.cx.local_sources.contains_key(&p) {
+        if self.scx.local_sources.contains_key(&p) {
             // We've already emitted this source
             return Ok(());
         }
@@ -904,7 +907,7 @@ impl<'a> SourceCollector<'a> {
         let mut cur = self.dst.clone();
         let mut root_path = String::from("../../");
         let mut href = String::new();
-        clean_srcpath(&self.cx.src_root, &p, false, |component| {
+        clean_srcpath(&self.scx.src_root, &p, false, |component| {
             cur.push(component);
             mkdir(&cur).unwrap();
             root_path.push_str("../");
@@ -928,24 +931,25 @@ impl<'a> SourceCollector<'a> {
             description: &desc,
             keywords: BASIC_KEYWORDS,
         };
-        layout::render(&mut w, &self.cx.layout,
+        layout::render(&mut w, &self.scx.layout,
                        &page, &(""), &Source(contents))?;
         w.flush()?;
-        self.cx.local_sources.insert(p, href);
+        self.scx.local_sources.insert(p, href);
         Ok(())
     }
 }
 
 impl DocFolder for Cache {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
-        // If this is a private module, we don't want it in the search index.
-        let orig_privmod = match item.inner {
-            clean::ModuleItem(..) => {
-                let prev = self.privmod;
-                self.privmod = prev || (self.remove_priv && item.visibility != Some(hir::Public));
+        // If this is a stripped module,
+        // we don't want it or its children in the search index.
+        let orig_stripped_mod = match item.inner {
+            clean::StrippedItem(box clean::ModuleItem(..)) => {
+                let prev = self.stripped_mod;
+                self.stripped_mod = true;
                 prev
             }
-            _ => self.privmod,
+            _ => self.stripped_mod,
         };
 
         // Register any generics to their corresponding string. This is used
@@ -983,6 +987,7 @@ impl DocFolder for Cache {
         // Index this method for searching later on
         if let Some(ref s) = item.name {
             let (parent, is_method) = match item.inner {
+                clean::StrippedItem(..) => ((None, None), false),
                 clean::AssociatedConstItem(..) |
                 clean::TypedefItem(_, true) if self.parent_is_trait_impl => {
                     // skip associated items in trait impls
@@ -1021,13 +1026,9 @@ impl DocFolder for Cache {
                 }
                 _ => ((None, Some(&*self.stack)), false)
             };
-            let hidden_field = match item.inner {
-                clean::StructFieldItem(clean::HiddenStructField) => true,
-                _ => false
-            };
 
             match parent {
-                (parent, Some(path)) if is_method || (!self.privmod && !hidden_field) => {
+                (parent, Some(path)) if is_method || (!self.stripped_mod) => {
                     // Needed to determine `self` type.
                     let parent_basename = self.parent_stack.first().and_then(|parent| {
                         match self.paths.get(parent) {
@@ -1035,6 +1036,7 @@ impl DocFolder for Cache {
                             _ => None
                         }
                     });
+                    debug_assert!(!item.is_stripped());
 
                     // A crate has a module at its root, containing all items,
                     // which should not be indexed. The crate-item itself is
@@ -1051,7 +1053,7 @@ impl DocFolder for Cache {
                         });
                     }
                 }
-                (Some(parent), None) if is_method || (!self.privmod && !hidden_field)=> {
+                (Some(parent), None) if is_method || (!self.stripped_mod)=> {
                     if parent.is_local() {
                         // We have a parent, but we don't know where they're
                         // defined yet. Wait for later to index this item.
@@ -1075,7 +1077,7 @@ impl DocFolder for Cache {
             clean::StructItem(..) | clean::EnumItem(..) |
             clean::TypedefItem(..) | clean::TraitItem(..) |
             clean::FunctionItem(..) | clean::ModuleItem(..) |
-            clean::ForeignFunctionItem(..) if !self.privmod => {
+            clean::ForeignFunctionItem(..) if !self.stripped_mod => {
                 // Reexported items mean that the same id can show up twice
                 // in the rustdoc ast that we're looking at. We know,
                 // however, that a reexported item doesn't show up in the
@@ -1093,7 +1095,7 @@ impl DocFolder for Cache {
             }
             // link variants to their parent enum because pages aren't emitted
             // for each variant
-            clean::VariantItem(..) if !self.privmod => {
+            clean::VariantItem(..) if !self.stripped_mod => {
                 let mut stack = self.stack.clone();
                 stack.pop();
                 self.paths.insert(item.def_id, (stack, ItemType::Enum));
@@ -1176,7 +1178,7 @@ impl DocFolder for Cache {
 
         if pushed { self.stack.pop().unwrap(); }
         if parent_pushed { self.parent_stack.pop().unwrap(); }
-        self.privmod = orig_privmod;
+        self.stripped_mod = orig_stripped_mod;
         self.parent_is_trait_impl = orig_parent_is_trait_impl;
         return ret;
     }
@@ -1233,15 +1235,12 @@ impl Context {
 
         // render the crate documentation
         let mut work = vec!((self, item));
-        loop {
-            match work.pop() {
-                Some((mut cx, item)) => cx.item(item, |cx, item| {
-                    work.push((cx.clone(), item));
-                })?,
-                None => break,
-            }
-        }
 
+        while let Some((mut cx, item)) = work.pop() {
+            cx.item(item, |cx, item| {
+                work.push((cx.clone(), item))
+            })?
+        }
         Ok(())
     }
 
@@ -1272,10 +1271,10 @@ impl Context {
             let tyname = shortty(it).to_static_str();
             let desc = if it.is_crate() {
                 format!("API documentation for the Rust `{}` crate.",
-                        cx.layout.krate)
+                        cx.shared.layout.krate)
             } else {
                 format!("API documentation for the Rust `{}` {} in crate `{}`.",
-                        it.name.as_ref().unwrap(), tyname, cx.layout.krate)
+                        it.name.as_ref().unwrap(), tyname, cx.shared.layout.krate)
             };
             let keywords = make_item_keywords(it);
             let page = layout::Page {
@@ -1293,82 +1292,75 @@ impl Context {
             // write syscall all the time.
             let mut writer = BufWriter::new(w);
             if !cx.render_redirect_pages {
-                layout::render(&mut writer, &cx.layout, &page,
+                layout::render(&mut writer, &cx.shared.layout, &page,
                                &Sidebar{ cx: cx, item: it },
                                &Item{ cx: cx, item: it })?;
+
             } else {
                 let mut url = repeat("../").take(cx.current.len())
                                            .collect::<String>();
-                match cache().paths.get(&it.def_id) {
-                    Some(&(ref names, _)) => {
-                        for name in &names[..names.len() - 1] {
-                            url.push_str(name);
-                            url.push_str("/");
-                        }
-                        url.push_str(&item_path(it));
-                        layout::redirect(&mut writer, &url)?;
+                if let Some(&(ref names, _)) = cache().paths.get(&it.def_id) {
+                    for name in &names[..names.len() - 1] {
+                        url.push_str(name);
+                        url.push_str("/");
                     }
-                    None => {}
+                    url.push_str(&item_path(it));
+                    layout::redirect(&mut writer, &url)?;
                 }
             }
             writer.flush()
         }
 
-        // Private modules may survive the strip-private pass if they
-        // contain impls for public types. These modules can also
+        // Stripped modules survive the rustdoc passes (i.e. `strip-private`)
+        // if they contain impls for public types. These modules can also
         // contain items such as publicly reexported structures.
         //
         // External crates will provide links to these structures, so
-        // these modules are recursed into, but not rendered normally (a
-        // flag on the context).
+        // these modules are recursed into, but not rendered normally
+        // (a flag on the context).
         if !self.render_redirect_pages {
-            self.render_redirect_pages = self.ignore_private_item(&item);
+            self.render_redirect_pages = self.maybe_ignore_item(&item);
         }
 
-        match item.inner {
+        if item.is_mod() {
             // modules are special because they add a namespace. We also need to
             // recurse into the items of the module as well.
-            clean::ModuleItem(..) => {
-                let name = item.name.as_ref().unwrap().to_string();
-                let mut item = Some(item);
-                self.recurse(name, |this| {
-                    let item = item.take().unwrap();
-                    let joint_dst = this.dst.join("index.html");
-                    let dst = try_err!(File::create(&joint_dst), &joint_dst);
-                    try_err!(render(dst, this, &item, false), &joint_dst);
-
-                    let m = match item.inner {
-                        clean::ModuleItem(m) => m,
-                        _ => unreachable!()
-                    };
-
-                    // render sidebar-items.js used throughout this module
-                    {
-                        let items = this.build_sidebar_items(&m);
-                        let js_dst = this.dst.join("sidebar-items.js");
-                        let mut js_out = BufWriter::new(try_err!(File::create(&js_dst), &js_dst));
-                        try_err!(write!(&mut js_out, "initSidebarItems({});",
-                                    as_json(&items)), &js_dst);
-                    }
+            let name = item.name.as_ref().unwrap().to_string();
+            let mut item = Some(item);
+            self.recurse(name, |this| {
+                let item = item.take().unwrap();
+                let joint_dst = this.dst.join("index.html");
+                let dst = try_err!(File::create(&joint_dst), &joint_dst);
+                try_err!(render(dst, this, &item, false), &joint_dst);
 
-                    for item in m.items {
-                        f(this,item);
-                    }
-                    Ok(())
-                })
-            }
+                let m = match item.inner {
+                    clean::StrippedItem(box clean::ModuleItem(m)) |
+                    clean::ModuleItem(m) => m,
+                    _ => unreachable!()
+                };
 
-            // Things which don't have names (like impls) don't get special
-            // pages dedicated to them.
-            _ if item.name.is_some() => {
-                let joint_dst = self.dst.join(&item_path(&item));
+                // render sidebar-items.js used throughout this module
+                {
+                    let items = this.build_sidebar_items(&m);
+                    let js_dst = this.dst.join("sidebar-items.js");
+                    let mut js_out = BufWriter::new(try_err!(File::create(&js_dst), &js_dst));
+                    try_err!(write!(&mut js_out, "initSidebarItems({});",
+                                    as_json(&items)), &js_dst);
+                }
 
-                let dst = try_err!(File::create(&joint_dst), &joint_dst);
-                try_err!(render(dst, self, &item, true), &joint_dst);
+                for item in m.items {
+                    f(this,item);
+                }
                 Ok(())
-            }
+            })
+        } else if item.name.is_some() {
+            let joint_dst = self.dst.join(&item_path(&item));
 
-            _ => Ok(())
+            let dst = try_err!(File::create(&joint_dst), &joint_dst);
+            try_err!(render(dst, self, &item, true), &joint_dst);
+            Ok(())
+        } else {
+            Ok(())
         }
     }
 
@@ -1376,7 +1368,7 @@ impl Context {
         // BTreeMap instead of HashMap to get a sorted output
         let mut map = BTreeMap::new();
         for item in &m.items {
-            if self.ignore_private_item(item) { continue }
+            if self.maybe_ignore_item(item) { continue }
 
             let short = shortty(item).to_static_str();
             let myname = match item.name {
@@ -1394,27 +1386,18 @@ impl Context {
         return map;
     }
 
-    fn ignore_private_item(&self, it: &clean::Item) -> bool {
+    fn maybe_ignore_item(&self, it: &clean::Item) -> bool {
         match it.inner {
+            clean::StrippedItem(..) => true,
             clean::ModuleItem(ref m) => {
-                (m.items.is_empty() &&
-                 it.doc_value().is_none() &&
-                 it.visibility != Some(hir::Public)) ||
-                (self.passes.contains("strip-private") && it.visibility != Some(hir::Public))
-            }
-            clean::PrimitiveItem(..) => it.visibility != Some(hir::Public),
+                it.doc_value().is_none() && m.items.is_empty() && it.visibility != Some(hir::Public)
+            },
             _ => false,
         }
     }
 }
 
 impl<'a> Item<'a> {
-    fn ismodule(&self) -> bool {
-        match self.item.inner {
-            clean::ModuleItem(..) => true, _ => false
-        }
-    }
-
     /// Generate a url appropriate for an `href` attribute back to the source of
     /// this item.
     ///
@@ -1457,10 +1440,11 @@ impl<'a> Item<'a> {
         // know the span, so we plow forward and generate a proper url. The url
         // has anchors for the line numbers that we're linking to.
         } else if self.item.def_id.is_local() {
-            self.cx.local_sources.get(&PathBuf::from(&self.item.source.filename)).map(|path| {
+            let path = PathBuf::from(&self.item.source.filename);
+            self.cx.shared.local_sources.get(&path).map(|path| {
                 format!("{root}src/{krate}/{path}#{href}",
                         root = self.cx.root_path,
-                        krate = self.cx.layout.krate,
+                        krate = self.cx.shared.layout.krate,
                         path = path,
                         href = href)
             })
@@ -1495,6 +1479,7 @@ impl<'a> Item<'a> {
 
 impl<'a> fmt::Display for Item<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        debug_assert!(!self.item.is_stripped());
         // Write the breadcrumb trail header for the top
         write!(fmt, "\n<h1 class='fqn'><span class='in-band'>")?;
         match self.item.inner {
@@ -1516,7 +1501,7 @@ impl<'a> fmt::Display for Item<'a> {
         };
         if !is_primitive {
             let cur = &self.cx.current;
-            let amt = if self.ismodule() { cur.len() - 1 } else { cur.len() };
+            let amt = if self.item.is_mod() { cur.len() - 1 } else { cur.len() };
             for (i, component) in cur.iter().enumerate().take(amt) {
                 write!(fmt, "<a href='{}index.html'>{}</a>::<wbr>",
                        repeat("../").take(cur.len() - i - 1)
@@ -1542,7 +1527,7 @@ impl<'a> fmt::Display for Item<'a> {
         // [src] link in the downstream documentation will actually come back to
         // this page, and this link will be auto-clicked. The `id` attribute is
         // used to find the link to auto-click.
-        if self.cx.include_sources && !is_primitive {
+        if self.cx.shared.include_sources && !is_primitive {
             if let Some(l) = self.href() {
                 write!(fmt, "<a id='src-{}' class='srclink' \
                               href='{}' title='{}'>[src]</a>",
@@ -1575,15 +1560,12 @@ impl<'a> fmt::Display for Item<'a> {
 }
 
 fn item_path(item: &clean::Item) -> String {
-    match item.inner {
-        clean::ModuleItem(..) => {
-            format!("{}/index.html", item.name.as_ref().unwrap())
-        }
-        _ => {
-            format!("{}.{}.html",
-                    shortty(item).to_static_str(),
-                    *item.name.as_ref().unwrap())
-        }
+    if item.is_mod() {
+        format!("{}/index.html", item.name.as_ref().unwrap())
+    } else {
+        format!("{}.{}.html",
+                shortty(item).to_static_str(),
+                *item.name.as_ref().unwrap())
     }
 }
 
@@ -1626,7 +1608,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
     document(w, cx, item)?;
 
     let mut indices = (0..items.len()).filter(|i| {
-        !cx.ignore_private_item(&items[*i])
+        !cx.maybe_ignore_item(&items[*i])
     }).collect::<Vec<usize>>();
 
     // the order of item types in the listing
@@ -1670,6 +1652,9 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
     let mut curty = None;
     for &idx in &indices {
         let myitem = &items[idx];
+        if myitem.is_stripped() {
+            continue;
+        }
 
         let myty = Some(shortty(myitem));
         if curty == Some(ItemType::ExternCrate) && myty == Some(ItemType::Import) {
@@ -1774,7 +1759,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio
             format!("Deprecated{}{}", since, Markdown(&reason))
         } else if stab.level == stability::Unstable {
             let unstable_extra = if show_reason {
-                match (!stab.feature.is_empty(), &cx.issue_tracker_base_url, stab.issue) {
+                match (!stab.feature.is_empty(), &cx.shared.issue_tracker_base_url, stab.issue) {
                     (true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
                         format!(" (<code>{}</code> <a href=\"{}{}\">#{}</a>)",
                                 Escape(&stab.feature), tracker_url, issue_no, issue_no),
@@ -2146,6 +2131,7 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                where_clause = WhereClause(g))
     }
     match item.inner {
+        clean::StrippedItem(..) => Ok(()),
         clean::TyMethodItem(ref m) => {
             method(w, item, m.unsafety, hir::Constness::NotConst,
                    m.abi, &m.generics, &m.self_, &m.decl, link)
@@ -2182,8 +2168,7 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     document(w, cx, it)?;
     let mut fields = s.fields.iter().filter(|f| {
         match f.inner {
-            clean::StructFieldItem(clean::HiddenStructField) => false,
-            clean::StructFieldItem(clean::TypedStructField(..)) => true,
+            clean::StructFieldItem(..) => true,
             _ => false,
         }
     }).peekable();
@@ -2273,7 +2258,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
             if let clean::VariantItem( Variant { kind: StructVariant(ref s) } ) = variant.inner {
                 let fields = s.fields.iter().filter(|f| {
                     match f.inner {
-                        clean::StructFieldItem(clean::TypedStructField(..)) => true,
+                        clean::StructFieldItem(..) => true,
                         _ => false,
                     }
                 });
@@ -2332,24 +2317,17 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
     match ty {
         doctree::Plain => {
             write!(w, " {{\n{}", tab)?;
-            let mut fields_stripped = false;
             for field in fields {
-                match field.inner {
-                    clean::StructFieldItem(clean::HiddenStructField) => {
-                        fields_stripped = true;
-                    }
-                    clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
-                        write!(w, "    {}{}: {},\n{}",
-                               VisSpace(field.visibility),
-                               field.name.as_ref().unwrap(),
-                               *ty,
-                               tab)?;
-                    }
-                    _ => unreachable!(),
-                };
+                if let clean::StructFieldItem(ref ty) = field.inner {
+                    write!(w, "    {}{}: {},\n{}",
+                           VisSpace(field.visibility),
+                           field.name.as_ref().unwrap(),
+                           *ty,
+                           tab)?;
+                }
             }
 
-            if fields_stripped {
+            if it.has_stripped_fields().unwrap() {
                 write!(w, "    // some fields omitted\n{}", tab)?;
             }
             write!(w, "}}")?;
@@ -2361,10 +2339,10 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
                     write!(w, ", ")?;
                 }
                 match field.inner {
-                    clean::StructFieldItem(clean::HiddenStructField) => {
+                    clean::StrippedItem(box clean::StructFieldItem(..)) => {
                         write!(w, "_")?
                     }
-                    clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
+                    clean::StructFieldItem(ref ty) => {
                         write!(w, "{}{}", VisSpace(field.visibility), *ty)?
                     }
                     _ => unreachable!()
@@ -2540,6 +2518,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                 assoc_type(w, item, bounds, default.as_ref(), link)?;
                 write!(w, "</code></h4>\n")?;
             }
+            clean::StrippedItem(..) => return Ok(()),
             _ => panic!("can't make docs for trait item with name {:?}", item.name)
         }
 
@@ -2661,16 +2640,16 @@ impl<'a> fmt::Display for Source<'a> {
             write!(fmt, "<span id=\"{0}\">{0:1$}</span>\n", i, cols)?;
         }
         write!(fmt, "</pre>")?;
-        write!(fmt, "{}", highlight::highlight(s, None, None))?;
+        write!(fmt, "{}", highlight::render_with_highlighting(s, None, None))?;
         Ok(())
     }
 }
 
 fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
               t: &clean::Macro) -> fmt::Result {
-    w.write_str(&highlight::highlight(&t.source,
-                                      Some("macro"),
-                                      None))?;
+    w.write_str(&highlight::render_with_highlighting(&t.source,
+                                                     Some("macro"),
+                                                     None))?;
     render_stability_since_raw(w, it.stable_since(), None)?;
     document(w, cx, it)
 }
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index 88cb20991d6..f93ecb46228 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -21,6 +21,7 @@ use clean::Item;
 use plugins;
 use fold;
 use fold::DocFolder;
+use fold::FoldItem::Strip;
 
 /// Strip items marked `#[doc(hidden)]`
 pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
@@ -39,18 +40,12 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
 
                     // use a dedicated hidden item for given item type if any
                     match i.inner {
-                        clean::StructFieldItem(..) => {
-                            return Some(clean::Item {
-                                inner: clean::StructFieldItem(clean::HiddenStructField),
-                                ..i
-                            });
-                        }
-                        _ => {
-                            return None;
+                        clean::StructFieldItem(..) | clean::ModuleItem(..) => {
+                            return Strip(i).fold()
                         }
+                        _ => return None,
                     }
                 }
-
                 self.fold_item_recur(i)
             }
         }
@@ -125,12 +120,14 @@ struct Stripper<'a> {
 impl<'a> fold::DocFolder for Stripper<'a> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         match i.inner {
+            clean::StrippedItem(..) => return Some(i),
             // These items can all get re-exported
             clean::TypedefItem(..) | clean::StaticItem(..) |
             clean::StructItem(..) | clean::EnumItem(..) |
             clean::TraitItem(..) | clean::FunctionItem(..) |
             clean::VariantItem(..) | clean::MethodItem(..) |
-            clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => {
+            clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
+            clean::ConstantItem(..) => {
                 if i.def_id.is_local() {
                     if !self.access_levels.is_exported(i.def_id) {
                         return None;
@@ -138,23 +135,17 @@ impl<'a> fold::DocFolder for Stripper<'a> {
                 }
             }
 
-            clean::ConstantItem(..) => {
-                if i.def_id.is_local() && !self.access_levels.is_exported(i.def_id) {
-                    return None;
-                }
-            }
-
             clean::StructFieldItem(..) => {
                 if i.visibility != Some(hir::Public) {
-                    return Some(clean::Item {
-                        inner: clean::StructFieldItem(clean::HiddenStructField),
-                        ..i
-                    })
+                    return Strip(i).fold();
                 }
             }
 
-            // handled below
-            clean::ModuleItem(..) => {}
+            clean::ModuleItem(..) => {
+                if i.def_id.is_local() && i.visibility != Some(hir::Public) {
+                    return Strip(self.fold_item_recur(i).unwrap()).fold()
+                }
+            }
 
             // trait impls for private items should be stripped
             clean::ImplItem(clean::Impl{
@@ -165,7 +156,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
                 }
             }
             // handled in the `strip-priv-imports` pass
-            clean::ExternCrateItem(..) | clean::ImportItem(_) => {}
+            clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
 
             clean::DefaultImplItem(..) | clean::ImplItem(..) => {}
 
@@ -187,7 +178,6 @@ impl<'a> fold::DocFolder for Stripper<'a> {
 
             // implementations of traits are always public.
             clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
-
             // Struct variant fields have inherited visibility
             clean::VariantItem(clean::Variant {
                 kind: clean::StructVariant(..)
@@ -202,19 +192,17 @@ impl<'a> fold::DocFolder for Stripper<'a> {
             self.fold_item_recur(i)
         };
 
-        i.and_then(|i| {
-            match i.inner {
-                // emptied modules/impls have no need to exist
-                clean::ModuleItem(ref m)
-                    if m.items.is_empty() &&
-                       i.doc_value().is_none() => None,
-                clean::ImplItem(ref i) if i.items.is_empty() => None,
-                _ => {
-                    self.retained.insert(i.def_id);
-                    Some(i)
-                }
+        i.and_then(|i| { match i.inner {
+            // emptied modules/impls have no need to exist
+            clean::ModuleItem(ref m)
+                if m.items.is_empty() &&
+                   i.doc_value().is_none() => None,
+            clean::ImplItem(ref i) if i.items.is_empty() => None,
+            _ => {
+                self.retained.insert(i.def_id);
+                Some(i)
             }
-        })
+        }})
     }
 }
 
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 331e3431cee..5bd3b9c4f59 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -431,7 +431,7 @@ impl Collector {
                 // compiler failures are test failures
                 should_panic: testing::ShouldPanic::No,
             },
-            testfn: testing::DynTestFn(Box::new(move|| {
+            testfn: testing::DynTestFn(box move|| {
                 runtest(&test,
                         &cratename,
                         cfgs,
@@ -442,7 +442,7 @@ impl Collector {
                         as_test_harness,
                         compile_fail,
                         &opts);
-            }))
+            })
         });
     }
 
diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs
index 945eb6a42e5..8a50f07e6d8 100644
--- a/src/libstd/time/duration.rs
+++ b/src/libstd/time/duration.rs
@@ -52,6 +52,7 @@ impl Duration {
     /// If the nanoseconds is greater than 1 billion (the number of nanoseconds
     /// in a second), then it will carry over into the seconds provided.
     #[stable(feature = "duration", since = "1.3.0")]
+    #[inline]
     pub fn new(secs: u64, nanos: u32) -> Duration {
         let secs = secs + (nanos / NANOS_PER_SEC) as u64;
         let nanos = nanos % NANOS_PER_SEC;
@@ -60,12 +61,14 @@ impl Duration {
 
     /// Creates a new `Duration` from the specified number of seconds.
     #[stable(feature = "duration", since = "1.3.0")]
+    #[inline]
     pub fn from_secs(secs: u64) -> Duration {
         Duration { secs: secs, nanos: 0 }
     }
 
     /// Creates a new `Duration` from the specified number of milliseconds.
     #[stable(feature = "duration", since = "1.3.0")]
+    #[inline]
     pub fn from_millis(millis: u64) -> Duration {
         let secs = millis / MILLIS_PER_SEC;
         let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI;
@@ -77,6 +80,7 @@ impl Duration {
     /// The extra precision represented by this duration is ignored (e.g. extra
     /// nanoseconds are not represented in the returned value).
     #[stable(feature = "duration", since = "1.3.0")]
+    #[inline]
     pub fn as_secs(&self) -> u64 { self.secs }
 
     /// Returns the nanosecond precision represented by this duration.
@@ -85,6 +89,7 @@ impl Duration {
     /// represented by nanoseconds. The returned number always represents a
     /// fractional portion of a second (e.g. it is less than one billion).
     #[stable(feature = "duration", since = "1.3.0")]
+    #[inline]
     pub fn subsec_nanos(&self) -> u32 { self.nanos }
 }
 
diff --git a/src/libsyntax/errors/json.rs b/src/libsyntax/errors/json.rs
index 212a54447a8..f369582bc5c 100644
--- a/src/libsyntax/errors/json.rs
+++ b/src/libsyntax/errors/json.rs
@@ -20,7 +20,7 @@
 // FIXME spec the JSON output properly.
 
 
-use codemap::{Span, MultiSpan, CodeMap};
+use codemap::{self, Span, MultiSpan, CodeMap};
 use diagnostics::registry::Registry;
 use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion};
 use errors::emitter::Emitter;
@@ -197,8 +197,8 @@ impl DiagnosticSpan {
 
     fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
         match *rsp {
-            // FIXME(#30701) handle Suggestion properly
             RenderSpan::FullSpan(ref msp) |
+            // FIXME(#30701) handle Suggestion properly
             RenderSpan::Suggestion(CodeSuggestion { ref msp, .. }) => {
                 DiagnosticSpan::from_multispan(msp, je)
             }
@@ -207,13 +207,13 @@ impl DiagnosticSpan {
                     let end = je.cm.lookup_char_pos(span.hi);
                     DiagnosticSpan {
                         file_name: end.file.name.clone(),
-                        byte_start: span.lo.0,
+                        byte_start: span.hi.0,
                         byte_end: span.hi.0,
-                        line_start: 0,
+                        line_start: end.line,
                         line_end: end.line,
-                        column_start: 0,
+                        column_start: end.col.0 + 1,
                         column_end: end.col.0 + 1,
-                        text: DiagnosticSpanLine::from_span(span, je),
+                        text: DiagnosticSpanLine::from_span_end(span, je),
                     }
                 }).collect()
             }
@@ -237,25 +237,70 @@ impl DiagnosticSpan {
     }
 }
 
-impl DiagnosticSpanLine {
-    fn from_span(span: &Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
-        let lines = match je.cm.span_to_lines(*span) {
+macro_rules! get_lines_for_span {
+    ($span: ident, $je: ident) => {
+        match $je.cm.span_to_lines(*$span) {
             Ok(lines) => lines,
             Err(_) => {
                 debug!("unprintable span");
                 return Vec::new();
             }
-        };
+        }
+    }
+}
+
+impl DiagnosticSpanLine {
+    fn line_from_filemap(fm: &codemap::FileMap,
+                         index: usize,
+                         h_start: usize,
+                         h_end: usize)
+                         -> DiagnosticSpanLine {
+        DiagnosticSpanLine {
+            text: fm.get_line(index).unwrap().to_owned(),
+            highlight_start: h_start,
+            highlight_end: h_end,
+        }
+    }
+
+    /// Create a list of DiagnosticSpanLines from span - each line with any part
+    /// of `span` gets a DiagnosticSpanLine, with the highlight indicating the
+    /// `span` within the line.
+    fn from_span(span: &Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
+        let lines = get_lines_for_span!(span, je);
 
         let mut result = Vec::new();
         let fm = &*lines.file;
 
         for line in &lines.lines {
-            result.push(DiagnosticSpanLine {
-                text: fm.get_line(line.line_index).unwrap().to_owned(),
-                highlight_start: line.start_col.0 + 1,
-                highlight_end: line.end_col.0 + 1,
-            });
+            result.push(DiagnosticSpanLine::line_from_filemap(fm,
+                                                              line.line_index,
+                                                              line.start_col.0 + 1,
+                                                              line.end_col.0 + 1));
+        }
+
+        result
+    }
+
+    /// Create a list of DiagnosticSpanLines from span - the result covers all
+    /// of `span`, but the highlight is zero-length and at the end of `span`.
+    fn from_span_end(span: &Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
+        let lines = get_lines_for_span!(span, je);
+
+        let mut result = Vec::new();
+        let fm = &*lines.file;
+
+        for (i, line) in lines.lines.iter().enumerate() {
+            // Invariant - CodeMap::span_to_lines will not return extra context
+            // lines - the last line returned is the last line of `span`.
+            let highlight = if i == lines.lines.len() - 1 {
+                (line.end_col.0 + 1, line.end_col.0 + 1)
+            } else {
+                (0, 0)
+            };
+            result.push(DiagnosticSpanLine::line_from_filemap(fm,
+                                                              line.line_index,
+                                                              highlight.0,
+                                                              highlight.1));
         }
 
         result
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 9027a5b1074..75916b87c12 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -6124,7 +6124,7 @@ impl<'a> Parser<'a> {
 
         // Allow a leading :: because the paths are absolute either way.
         // This occurs with "use $crate::..." in macros.
-        self.eat(&token::ModSep);
+        let is_global = self.eat(&token::ModSep);
 
         if self.check(&token::OpenDelim(token::Brace)) {
             // use {foo,bar}
@@ -6135,7 +6135,7 @@ impl<'a> Parser<'a> {
                 |p| p.parse_path_list_item())?;
             let path = ast::Path {
                 span: mk_sp(lo, self.span.hi),
-                global: false,
+                global: is_global,
                 segments: Vec::new()
             };
             return Ok(P(spanned(lo, self.span.hi, ViewPathList(path, idents))));
@@ -6164,7 +6164,7 @@ impl<'a> Parser<'a> {
                     )?;
                     let path = ast::Path {
                         span: mk_sp(lo, self.span.hi),
-                        global: false,
+                        global: is_global,
                         segments: path.into_iter().map(|identifier| {
                             ast::PathSegment {
                                 identifier: identifier,
@@ -6180,7 +6180,7 @@ impl<'a> Parser<'a> {
                     self.bump();
                     let path = ast::Path {
                         span: mk_sp(lo, self.span.hi),
-                        global: false,
+                        global: is_global,
                         segments: path.into_iter().map(|identifier| {
                             ast::PathSegment {
                                 identifier: identifier,
@@ -6203,7 +6203,7 @@ impl<'a> Parser<'a> {
         let mut rename_to = path[path.len() - 1];
         let path = ast::Path {
             span: mk_sp(lo, self.last_span.hi),
-            global: false,
+            global: is_global,
             segments: path.into_iter().map(|identifier| {
                 ast::PathSegment {
                     identifier: identifier,
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index a02a10aa003..16417ac0044 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -514,7 +514,7 @@ macro_rules! declare_special_idents_and_keywords {(
 // If the special idents get renumbered, remember to modify these two as appropriate
 pub const SELF_KEYWORD_NAME: ast::Name = ast::Name(SELF_KEYWORD_NAME_NUM);
 const STATIC_KEYWORD_NAME: ast::Name = ast::Name(STATIC_KEYWORD_NAME_NUM);
-const SUPER_KEYWORD_NAME: ast::Name = ast::Name(SUPER_KEYWORD_NAME_NUM);
+pub const SUPER_KEYWORD_NAME: ast::Name = ast::Name(SUPER_KEYWORD_NAME_NUM);
 const SELF_TYPE_KEYWORD_NAME: ast::Name = ast::Name(SELF_TYPE_KEYWORD_NAME_NUM);
 
 pub const SELF_KEYWORD_NAME_NUM: u32 = 1;
diff --git a/src/snapshots.txt b/src/snapshots.txt
index d1a2ab464cb..61dfd4f8f86 100644
--- a/src/snapshots.txt
+++ b/src/snapshots.txt
@@ -9,6 +9,7 @@ S 2016-03-18 235d774
   freebsd-x86_64 390b9a9f60f3d0d6a52c04d939a0355f572d03b3
 
 S 2016-02-17 4d3eebf
+  dragonfly-x86_64 765bb5820ad406e966ec0ac51c8070b656459b02
   linux-i386 5f194aa7628c0703f0fd48adc4ec7f3cc64b98c7
   linux-x86_64 d29b7607d13d64078b6324aec82926fb493f59ba
   macos-i386 4c8e42dd649e247f3576bf9dfa273327b4907f9c
@@ -16,6 +17,7 @@ S 2016-02-17 4d3eebf
   winnt-i386 0c336d794a65f8e285c121866c7d59aa2dd0d1e1
   winnt-x86_64 27e75b1bf99770b3564bcebd7f3230be01135a92
   openbsd-x86_64 ac957c6b84de2bd67f01df085d9ea515f96e22f3
+  freebsd-i386 4e2af0b34eb335e173aebff543be693724a956c2
   freebsd-x86_64 f38991fbb81c1cd8d0bbda396f98f13a55b42804
 
 S 2015-12-18 3391630
diff --git a/src/test/auxiliary/reexp_stripped.rs b/src/test/auxiliary/reexp_stripped.rs
new file mode 100644
index 00000000000..2b061e3997d
--- /dev/null
+++ b/src/test/auxiliary/reexp_stripped.rs
@@ -0,0 +1,21 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use private::Quz;
+pub use hidden::Bar;
+
+mod private {
+    pub struct Quz;
+}
+
+#[doc(hidden)]
+pub mod hidden {
+    pub struct Bar;
+}
diff --git a/src/test/compile-fail/consider-removing-last-semi.rs b/src/test/compile-fail/consider-removing-last-semi.rs
new file mode 100644
index 00000000000..02148a138c9
--- /dev/null
+++ b/src/test/compile-fail/consider-removing-last-semi.rs
@@ -0,0 +1,23 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn f() -> String {  //~ ERROR E0269
+                    //~^ HELP detailed explanation
+    0u8;
+    "bla".to_string();  //~ HELP consider removing this semicolon
+}
+
+fn g() -> String {  //~ ERROR E0269
+                    //~^ HELP detailed explanation
+    "this won't work".to_string();
+    "removeme".to_string(); //~ HELP consider removing this semicolon
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-32128.rs b/src/test/compile-fail/issue-32128.rs
new file mode 100644
index 00000000000..fe7e66a2116
--- /dev/null
+++ b/src/test/compile-fail/issue-32128.rs
@@ -0,0 +1,25 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Example {
+    example: Box<Fn(i32) -> i32>
+}
+
+fn main() {
+    let demo = Example {
+        example: Box::new(|x| {
+            x + 1
+        })
+    };
+
+    demo.example(1);    //~ ERROR no method named `example`
+                        //~^ NOTE use `(demo.example)(...)`
+    // (demo.example)(1);
+}
diff --git a/src/test/compile-fail/use-super-global-path.rs b/src/test/compile-fail/use-super-global-path.rs
new file mode 100644
index 00000000000..d721d428f29
--- /dev/null
+++ b/src/test/compile-fail/use-super-global-path.rs
@@ -0,0 +1,22 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_attrs)]
+
+mod foo {
+    pub fn g() {
+        use ::super::main; //~ WARN expected identifier, found keyword `super`
+        //~^ WARN this was previously accepted by the compiler but is being phased out
+        main();
+    }
+}
+
+#[rustc_error]
+fn main() { foo::g(); } //~ ERROR compilation successful
diff --git a/src/test/rustdoc/redirect.rs b/src/test/rustdoc/redirect.rs
new file mode 100644
index 00000000000..98e66e8c024
--- /dev/null
+++ b/src/test/rustdoc/redirect.rs
@@ -0,0 +1,48 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:reexp_stripped.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate reexp_stripped;
+
+pub trait Foo {}
+
+// @has redirect/index.html
+// @has - '//code' 'pub use reexp_stripped::Bar'
+// @has - '//code/a' 'Bar'
+// @has reexp_stripped/hidden/struct.Bar.html
+// @has - '//p/a' '../../reexp_stripped/struct.Bar.html'
+// @has 'reexp_stripped/struct.Bar.html'
+#[doc(no_inline)]
+pub use reexp_stripped::Bar;
+impl Foo for Bar {}
+
+// @has redirect/index.html
+// @has - '//code' 'pub use reexp_stripped::Quz'
+// @has - '//code/a' 'Quz'
+// @has reexp_stripped/private/struct.Quz.html
+// @has - '//p/a' '../../reexp_stripped/struct.Quz.html'
+// @has 'reexp_stripped/struct.Quz.html'
+#[doc(no_inline)]
+pub use reexp_stripped::Quz;
+impl Foo for Quz {}
+
+mod private_no_inline {
+    pub struct Qux;
+    impl ::Foo for Qux {}
+}
+
+// @has redirect/index.html
+// @has - '//code' 'pub use private_no_inline::Qux'
+// @!has - '//code/a' 'Qux'
+#[doc(no_inline)]
+pub use private_no_inline::Qux;
diff --git a/src/test/rustdoc/structfields.rs b/src/test/rustdoc/structfields.rs
new file mode 100644
index 00000000000..c4327f70728
--- /dev/null
+++ b/src/test/rustdoc/structfields.rs
@@ -0,0 +1,44 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// @has structfields/struct.Foo.html
+pub struct Foo {
+    // @has - //pre "pub a: ()"
+    pub a: (),
+    // @has - //pre "// some fields omitted"
+    // @!has - //pre "b: ()"
+    b: (),
+    // @!has - //pre "c: usize"
+    #[doc(hidden)]
+    c: usize,
+    // @has - //pre "pub d: usize"
+    pub d: usize,
+}
+
+// @has structfields/struct.Bar.html
+pub struct Bar {
+    // @has - //pre "pub a: ()"
+    pub a: (),
+    // @!has - //pre "// some fields omitted"
+}
+
+// @has structfields/enum.Qux.html
+pub enum Qux {
+    Quz {
+        // @has - //pre "a: ()"
+        a: (),
+        // @!has - //pre "b: ()"
+        #[doc(hidden)]
+        b: (),
+        // @has - //pre "c: usize"
+        c: usize,
+        // @has - //pre "// some fields omitted"
+    },
+}